기본사용법

VanillaFront 튜토리얼 — 7. 다국어

VanillaFront 2026. 9. 11. 09:29

https://vanillafront.com 참조

VanillaFront 튜토리얼 — 7. 다국어

라벨과 메시지를 프로젝트 언어별로 표시하는 다국어 처리. VanillaFront는 크게 두 개의 도구를 제공합니다.

  • Va.Lang — 사전 기반 번역
  • Va.Locale — 현재 UI 언어 설정 (ko/en/es)

작지만 명확한 시스템입니다. 이번 편에서 흐름을 정리합니다.


개념 정리

두 개념이 짝을 이룹니다.

도구역할

Va.Locale 지금 UI가 어떤 언어인지 관리
Va.Lang 그 언어에 맞는 텍스트를 사전에서 꺼냄
  • 언어 설정: Va.Locale.setLanguage('en')
  • 사전 세팅: Va.Lang.setData({...})
  • 번역 조회: Va.Lang.get('번호')  no (영어 모드일 때)

여기에 편의 별칭 두 개가 더 있습니다.

  • Va.$('번호')  Va.Lang.get('번호')의 축약
  • Va.$$('번호', '0001') — 파라미터 치환까지 포함한 형태

1) 언어 설정 — Va.Locale

프로젝트 시작 시 언어를 정합니다. 보통 config.js에 두고 앱 초기화 때 반영합니다.

config.js

const config = {
    labelPosition: 'top',
    labelSeperator: false,
    language: 'ko'          // ← 시작 언어
};
export default config;

앱 초기화

class App extends Va.View {
    init() {
        Va.Config.setData(config);
        Va.Locale.setLanguage(config.language);   // 명시적 설정 권장
    }
    config() {
        return {
            tagName: 'article',
            tags: [
                { tagName: 'dateField', label: 'Calendar' }
            ]
        };
    }
}

지원 언어

프레임워크가 기본 제공하는 시스템 언어팩:

코드언어

ko 한국어 (기본)
en 영어
es 스페인어

lib/lang/va_ko.js, va_en.js, va_es.js에 정의되어 있으며 필요 시 추가 언어팩을 만들 수 있습니다.

언어 전환

onChangeLanguage(lang) {
    Va.Locale.setLanguage(lang);
    // 이후 렌더링되는 화면은 새 언어로 표시
    // 이미 렌더된 라벨을 갈아치우려면 화면 다시 그리기 (뷰 재생성)
}

⚠️ 주의: 이미 그려진 라벨의 텍스트는 자동으로 안 바뀝니다. 언어 전환 후엔 뷰를 다시 렌더링해야 반영됩니다. 실무에서는 언어 전환 시 페이지 리로드가 가장 간단합니다.


2) 사전 관리 — Va.Lang

프로젝트 고유의 업무 용어를 사전으로 관리합니다.

사전 세팅

init() {
    const data = {
        '번호':   { ko: '번호',   en: 'No.',       es: 'No.' },
        '고객명': { ko: '고객명', en: 'Customer',  es: 'Cliente' },
        '나이':   { ko: '나이',   en: 'Age',       es: 'Edad' }
    };
    Va.Lang.setData(data);
}

포인트:

  • 한글 키 그대로 사용 가능  { '번호': {...} }
  • 각 키 값은 언어별 객체 { ko, en, es, ... }
  • Va.Locale이 지정한 언어의 값이 자동으로 선택됨

단순 문자열도 허용

값이 문자열이면 언어 구분 없이 그 문자열이 반환됩니다.

{
    '앱이름': 'VanillaFront',                    // 언어 상관없이 'VanillaFront'
    '고객명': { ko: '고객명', en: 'Customer' }    // 언어별
}

조회

Va.Lang.get('번호');   // 'ko'면 '번호', 'en'면 'No.'
Va.$('번호');          // 위와 동일 (축약)

주의: 사전에 없는 키를 넘기면 키 문자열 그대로 반환됩니다. 즉 Va.$('알수없는키') → '알수없는키' — 화면이 깨지진 않지만 번역 누락을 눈치채기 어렵습니다.

뷰에서 사용

config() {
    return {
        tagName: 'article',
        tags: [
            { tagName: 'inputField', label: Va.Lang.get('번호') },
            { tagName: 'inputField', label: Va.Lang.get('고객명') }
        ]
    };
}

한글 키를 그대로 라벨로 두는 프로젝트라면 사전 없이도 그대로 동작합니다 (조회 실패 시 키 자체가 반환되므로). 나중에 영어·스페인어를 지원할 때 사전만 채우면 됩니다.


3) 파라미터 치환 — Va.$$ / Va.Lang.get

번역 문장 안에 값을 삽입할 때 씁니다. {0}, {1}, {2} 자리표시자를 파라미터로 채웁니다.

사전 정의

{
    '고객명번호': {
        ko: '고객 {0} (번호: {1})',
        en: 'Customer {0} (No.: {1})'
    }
}

사용

Va.Lang.get('고객명번호', '홍길동', '0001');
// ko → '고객 홍길동 (번호: 0001)'
// en → 'Customer 홍길동 (No.: 0001)'

Va.$$('고객명번호', '홍길동', '0001');   // 위와 동일 (축약)

최대 5개 파라미터 지원 (p0 ~ p4).

실전 예

{
    tagName: 'inputField',
    label: Va.$$('번호', '0001'),   // '번호 (0001)' 같은 라벨
    ref: 'input1'
}

4) 편의 별칭 정리

표기뜻

Va.Lang.get(key, ...) 원본 API
Va.$(key) 단순 조회 축약
Va.$$(key, ...args) 파라미터 치환 축약

프로젝트 코드에서는 대개 Va.$ / Va.$$로 짧게 씁니다.


5) 시스템 언어팩 — Va.SysLang

프레임워크 컴포넌트가 자체적으로 쓰는 텍스트(달력 요일·월, "확인", "오류", "총 데이터 수" 등)는 별도의 시스템 언어팩으로 관리됩니다.

예 — 한국어 lib/lang/va_ko.js

Va.SysLang = class extends Va {
    static calendarYear = '년';
    static calendarMonth = '월';
    static monthTitle = ['1월', '2월', '3월', ..., '12월'];
    static weekTitle = ['일', '월', '화', '수', '목', '금', '토'];

    static textConfirm() { return '확인'; }
    static textError()   { return '오류'; }
    static textAll()     { return '전체'; }
    static textBlankData() { return '데이터가 존재하지 않습니다.'; }
    // ... 등등
};

동작

  • Va.Locale.setLanguage('en') 하면 va_en.js의 Va.SysLang이 활성화됨
  • DatePicker의 요일·월 이름, 그리드의 "데이터가 존재하지 않습니다" 같은 프레임워크 자동 텍스트가 알아서 언어에 맞게 표시됨
  • 개발자가 신경 쓸 필요 없음

6) 실전 예제 — 언어 전환

전체 흐름을 한 파일로 정리해 봅시다.

import Va from '../../lib/va.js';

class App extends Va.View {
    init() {
        // 사전 세팅
        Va.Lang.setData({
            '번호':   { ko: '번호',   en: 'No.',       es: 'No.' },
            '고객명': { ko: '고객명', en: 'Customer',  es: 'Cliente' },
            '나이':   { ko: '나이',   en: 'Age',       es: 'Edad' },
            '조회':   { ko: '조회',   en: 'Search',    es: 'Buscar' },
            '고객명번호': {
                ko: '고객 {0} (번호: {1})',
                en: 'Customer {0} (No.: {1})',
                es: 'Cliente {0} (No.: {1})'
            }
        });

        // 초기 언어
        Va.Locale.setLanguage('ko');
    }

    onChangeLang(btn, el, evt) {
        Va.Locale.setLanguage(btn.option.lang);
        // 반영 위해 리로드 (가장 간단한 방법)
        window.location.reload();
    }

    config() {
        return {
            tagName: 'article',
            style: 'max-width:600px',
            tags: [
                {
                    tagName: 'div',
                    tags: [
                        { tagName: 'button', text: '한국어', lang: 'ko', onClick: 'onChangeLang' },
                        { tagName: 'button', text: 'English', lang: 'en', onClick: 'onChangeLang' },
                        { tagName: 'button', text: 'Español', lang: 'es', onClick: 'onChangeLang' }
                    ]
                },
                {
                    tagName: 'inputField',
                    label: Va.$('번호'),
                    value: '0001'
                },
                {
                    tagName: 'inputField',
                    label: Va.$('고객명'),
                    value: '홍길동'
                },
                {
                    tagName: 'inputField',
                    label: Va.$('나이')
                },
                {
                    tagName: 'div',
                    innerHTML: Va.$$('고객명번호', '홍길동', '0001')
                },
                {
                    tagName: 'button',
                    text: Va.$('조회'),
                    appearance: 'primary'
                },
                {
                    tagName: 'dateField',
                    label: 'Calendar'
                }
            ]
        };
    }
}

동작:

  1. 초기 로드 시 한국어로 표시
  2. "English" 버튼 클릭 → Va.Locale.setLanguage('en') → 페이지 리로드
  3. 리로드 후 모든 라벨과 DatePicker 달력이 영어로 표시

7) 사전 관리 팁

1) 사전을 별도 파일로 뺄 것

앱이 커지면 사전을 뷰 안에 두지 말고 별도 파일로:

assets/
└── lang/
    ├── dict.js         (또는 dict.json)
    └── dict.en.js      (언어별로 분리해도 됨)
// assets/lang/dict.js
export default {
    '번호':   { ko: '번호',   en: 'No.' },
    '고객명': { ko: '고객명', en: 'Customer' }
    // ...
};
// index.js
import dict from './assets/lang/dict.js';
Va.Lang.setData(dict);

2) 서버에서 사전 내려받기

DB로 관리하는 프로젝트라면:

init() {
    LangService.list(this, {}, (view, ok, res) => {
        if (ok) Va.Lang.setData(res.data.dict);
    });
}

번역이 자주 바뀌는 프로젝트에서 개발자 배포 없이 사전을 갱신할 수 있습니다.

3) 키 명명 규칙 통일

세 가지 스타일 중 하나로 통일:

스타일예시특징

한글 그대로 '고객명' 사전 없어도 화면이 자연스러움 (한국어 기본 프로젝트)
영어 스네이크 'cust_name' 다국어 우선 프로젝트에 무난
도트 계층 'cust.list.title' 대규모 프로젝트, 네임스페이스 관리

한글 키는 사전 없이도 한국어 화면이 되는 편리함이 있지만, 오탈자 감지가 어렵고 리팩토링이 힘듭니다. 프로젝트 규모에 맞게 선택하세요.

4) 번역 누락 감지

Va.$('없는키') → '없는키' 그대로 반환되어 화면에는 뜨지만 번역이 안 됩니다. QA에서 놓치기 쉬우니:

  • 개발 중 콘솔 warning을 추가하는 커스텀 래퍼
  • 사전 커버리지 체크 스크립트 (모든 Va.$('...') 호출을 grep해서 사전과 대조)

이런 도구를 팀 안에 마련해 두면 안전합니다.

5) 언어 전환은 리로드가 안전

이미 그려진 라벨 텍스트는 자동으로 안 바뀝니다. 뷰 재렌더링을 정확히 관리하려면 복잡하니, 언어 전환 시 페이지 리로드가 가장 안전한 UX입니다.

onChangeLang(btn) {
    Va.Locale.setLanguage(btn.option.lang);
    window.location.reload();
}

라우터를 쓰는 SPA라면 hash를 보존하며 리로드:

window.location = window.location.pathname + '?lang=' + lang + window.location.hash;

8) 자주 하는 실수

  1. Va.Lang.setData 없이 Va.$ 호출 — 조용히 키 그대로 반환. 번역이 안 되는 이유를 몰라 헤맴.
  2. Va.Locale.setLanguage 없이 사전만 세팅 — 어느 언어가 선택될지 몰라 예상과 다르게 표시.
  3. 한 화면 안에서 언어 전환 후 텍스트 안 바뀜 — 이미 렌더된 요소는 갱신 안 됨. 리로드 필요.
  4. DatePicker 요일이 영어인데 라벨은 한국어  Va.SysLang은 va_ko.js 등을 import해야 활성화. 언어팩 import 확인.
  5. 사전 값에 <script> 삽입 위험 — 사전이 서버에서 오는 경우 XSS 조심. 라벨은 대체로 안전하지만 innerHTML 자리에 넣을 때 sanitize 확인.

요약 — 다국어 5대 규칙

  1. Va.Locale.setLanguage로 현재 언어 지정  ko/en/es 지원, 커스텀 추가 가능
  2. Va.Lang.setData로 사전 세팅  { 키: { ko, en, es } } 형태
  3. Va.$(key) / Va.$$(key, ...args) 로 조회 — 파라미터 치환은 {0}~{4}
  4. 프레임워크 텍스트는 Va.SysLang이 자동 담당 — 달력 요일·월, "확인" 등
  5. 언어 전환은 페이지 리로드가 가장 안전 — 이미 그려진 라벨은 자동 갱신 안 됨