11 KiB
11 KiB
Baron SSO i18n(국제화) 처리 정책
1. 개요 (Overview)
본 문서는 Baron SSO 시스템(Backend, UserFront, AdminFront, DevFront)의 다국어 지원을 위한 표준 정책을 정의합니다. 모든 UI 텍스트와 서버 메시지는 하드코딩을 지양하고, 약속된 코드값(Key)을 기반으로 렌더링해야 합니다.
2. 기본 원칙 (Core Principles)
- Backend는 Key만 전달한다: API 응답에는 사용자에게 보여질 텍스트(메시지)를 포함하지 않는다. 대신 기계가 해석 가능한
code를 반환한다. - Frontend가 렌더링 주체다: 모든 번역 데이터(Dictionary)는 프론트엔드 애플리케이션이 보유하며, 백엔드로부터 받은
code나 UI의 키값을 매핑하여 적절한 언어로 표시한다. - URL 기반 로케일 격리: 언어 설정은 URL 경로(
/{locale}/...)에 명시적으로 드러나야 한다. - 포맷 및 관리:
- 모든 리소스는 TOML 포맷을 사용한다. (주석 가능, 가독성 우수)
- **
template.toml**을 기준(Master)으로 삼아, 각 언어 파일(ko.toml,en.toml)이 키를 빠짐없이 구현했는지 관리한다.
3. 키(Key) 명명 규칙 (Naming Convention)
메시지 키는 계층 구조를 가지며 snake_case와 dot(.) 표기법을 혼용하여 체계적으로 관리합니다.
TOML에서는 [Section]을 사용하여 계층을 표현합니다.
3.1 카테고리 (Category)
가장 상위 레벨에서 메시지의 성격을 정의합니다.
| Prefix (Section) | 설명 | 예시 |
|---|---|---|
[ui] |
버튼, 레이블, 메뉴 등 짧은 단어 | ui.btn.save, ui.nav.dashboard |
[msg] |
문장형 알림, 설명 텍스트, 다이얼로그 내용 | msg.info.saved_success |
[err] |
백엔드 에러 코드 또는 프론트 유효성 검사 에러 | err.auth.user_not_found |
[domain] |
비즈니스 도메인 용어 (명사 위주) | domain.user.role |
[unit] |
시간, 화폐, 데이터 단위 | unit.time.sec |
3.2 TOML 예시 (template.toml)
# UI Elements
[ui]
[ui.btn]
save = ""
cancel = ""
[ui.label]
password = ""
# Messages
[msg]
[msg.info]
saved_success = ""
# Errors (Backend Codes)
[err]
[err.auth]
user_not_found = ""
4. 로케일 및 라우팅 정책 (Locale & Routing)
4.1 지원 언어 및 Fallback
- 기본 언어(Default):
en(영어) - 지원 언어:
ko(한국어),en(영어) - 매핑 로직:
- 브라우저 설정이
ko,ko-KR인 경우 → 한국어 (ko) 노출 - 그 외 모든 언어(
ja,zh,en-US등) → 영어 (en) 노출
- 브라우저 설정이
4.2 URL 구조
모든 페이지는 URL의 첫 번째 경로(Path Segment)로 언어를 구분합니다.
https://sso.baron.io/ko/login(한국어)https://sso.baron.io/en/dashboard(영어)
4.3 라우팅 및 리다이렉트 동작
- Root 접속 시 (
/):- 사용자의 브라우저
navigator.language를 감지합니다. ko계열이면/ko/dashboard로 리다이렉트합니다.- 그 외에는
/en/dashboard로 리다이렉트합니다. - 단, 이전에 언어를 선택한 쿠키나 로컬스토리지 값이 있다면 그 값을 우선합니다.
- 로컬스토리지 키는 **
locale**을 사용합니다.
- 사용자의 브라우저
- 언어 변경 시:
- 모든 화면에는 **언어 선택기(Language Selector)**가 노출되어야 합니다.
- 변경 시 해당 언어의 URL로 이동(
window.location변경 혹은 Router Push)하며, 선택된 언어를 로컬스토리지에 저장합니다.
5. 아키텍처 및 데이터 흐름
5.1 백엔드 (Go Fiber)
백엔드는 번역을 수행하지 않습니다. 오직 상황에 맞는 Error Code만 반환합니다.
응답 예시 (401 Unauthorized):
{
"error": "Invalid password",
"code": "auth.invalid_credentials", // TOML의 [err.auth] invalid_credentials 와 매핑
"details": null
}
5.2 프론트엔드 (React / Flutter)
5.2.1 리소스 공유 및 변환
- TOML은 개발 및 관리 편의를 위한 포맷입니다.
- Build Time 또는 Runtime에 TOML 파일을 로드하여 사용합니다.
- React (Vite):
vite-plugin-toml등을 사용하거나, 빌드 스크립트로 JSON 변환 후i18next에 주입. - Flutter:
toml패키지를 사용하여 로드하거나, 전처리 스크립트로 ARB/JSON 변환 후easy_localization사용.
- React (Vite):
5.2.2 관리 프로세스 (Template & CI)
template.toml: 개발자가 새로운 번역 키를 추가할 때 반드시 이 파일에 먼저 정의해야 합니다.ko.toml,en.toml: 템플릿의 키를 바탕으로 실제 번역 값을 채워 넣습니다.- UserFront 런타임 리소스 동기화:
- UserFront는 런타임에
userfront/assets/translations/*.toml을 직접 읽습니다. - 따라서
locales/ko.toml,locales/en.toml,locales/template.toml을 수정한 뒤에는 반드시 아래 동기화 스크립트를 실행해야 합니다. - 실행 명령:
./scripts/sync_userfront_locales.sh - 이 단계가 누락되면 루트 SoT와 UserFront 실제 표시 문구가 어긋날 수 있습니다.
- UserFront는 런타임에
- React 공통 locale 레이어:
- React 계열 프런트(
adminfront,devfront,orgfront)는common/locales/*.toml을 공통 문구 레이어로 사용합니다. - 공통 key는
ui.common.*,msg.common.*범위에만 둡니다. - 각 앱의
src/locales/*.toml은 앱 전용 문구를 유지하고, 로딩 시common locale -> app locale override순서로 merge 합니다.
- React 계열 프런트(
- CI 검증 (Verification):
- Level 1: 리소스 동기화 검사 (
templatevslang)locales/*.toml과common/locales/*.toml각각에 대해template.toml에 있는 모든 키가ko.toml,en.toml에 존재하는지 재귀적으로 검사합니다.- 누락 시 빌드 실패.
- Level 2: 코드 사용성 검사 (
codevstemplate)- 전체 프론트엔드 소스코드(
src/**/*.{ts,tsx},lib/**/*.dart)를 스캔하여 번역 함수(t('key'),'key'.tr())에 사용된 키를 추출합니다. - Missing Key: 코드에는 있는데 해당 레이어의
template.toml에 없는 키를 검출하여 경고 또는 에러를 발생시킵니다. - Unused Key: 각
template.toml에는 있는데 코드 어디에서도 쓰이지 않는 키를 리포트하여 정리할 수 있게 합니다.
- 전체 프론트엔드 소스코드(
- Level 1: 리소스 동기화 검사 (
5.2.3 React (Admin/Dev) 구현 가이드
- 패키지 설치:
npm install i18next react-i18next i18next-browser-languagedetector npm install -D vite-plugin-toml - Vite 설정 (
vite.config.ts):import { defineConfig } from 'vite'; import { plugin as toml } from 'vite-plugin-toml'; export default defineConfig({ plugins: [toml], // .toml 파일을 모듈로 import 가능하게 함 }); - i18n 초기화 (
src/i18n.ts):import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; // TOML 파일 직접 import (JSON 객체로 변환됨) import ko from './locales/ko.toml'; import en from './locales/en.toml'; i18n .use(LanguageDetector) .use(initReactI18next) .init({ resources: { ko: { translation: ko }, en: { translation: en }, }, fallbackLng: 'en', interpolation: { escapeValue: false, }, }); export default i18n;
5.2.4 Flutter (User) 구현 가이드
Flutter는 런타임에 TOML을 파싱하기 위해 toml 패키지와 easy_localization의 커스텀 로더를 사용합니다.
5.2.5 UserFront 에러 표시 정책 (Production)
UserFront(/error)는 프로덕션에서 다음 규칙으로 에러를 표시합니다.
- Internal whitelist 코드
msg.userfront.error.whitelist.{code}메시지를 노출합니다.
- ORY bypass 코드
msg.userfront.error.ory.{code}메시지를 노출합니다.
- 그 외 코드
unknown_error로 처리하고 일반 안내 문구(msg.userfront.error.detail_contact)를 노출합니다.
코드 집합은 userfront/lib/core/constants/error_whitelist.dart를 단일 기준으로 유지합니다.
- 패키지 추가 (
pubspec.yaml):dependencies: easy_localization: ^3.0.0 toml: ^0.14.0 flutter: assets: - assets/translations/ - Custom AssetLoader 구현 (
lib/core/i18n/toml_asset_loader.dart):import 'dart:ui'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/services.dart'; import 'package:toml/toml.dart'; class TomlAssetLoader extends AssetLoader { const TomlAssetLoader(); @override Future<Map<String, dynamic>> load(String path, Locale locale) async { final assetPath = '$path/${locale.languageCode}.toml'; try { // 1. Asset 파일 읽기 final String content = await rootBundle.loadString(assetPath); // 2. TOML 파싱 final TomlDocument document = TomlDocument.parse(content); // 3. Map으로 변환하여 반환 return document.toMap(); } catch (e) { // 로깅 또는 빈 맵 반환 print('Error loading TOML asset: $assetPath, error: $e'); return {}; } } } - 초기화 (
main.dart):void main() async { WidgetsFlutterBinding.ensureInitialized(); await EasyLocalization.ensureInitialized(); runApp( EasyLocalization( supportedLocales: const [Locale('en'), Locale('ko')], path: 'assets/translations', fallbackLocale: const Locale('en'), assetLoader: const TomlAssetLoader(), // 커스텀 로더 적용 child: const MyApp(), ), ); }
6. 작업 체크리스트
- 공통:
locales/template.toml정의 및 초기 키셋 구성. - CI:
template.tomlvs*.toml키 동기화 검증 스크립트 작성 (scripts/verify-i18n.jsorpy). - Admin/DevFront: Vite TOML 플러그인 설정 및
react-i18next연동. - UserFront: TOML -> JSON 변환 스크립트 추가 및
easy_localization연동.
6.1 UserFront 번역 수정 체크포인트
UserFront 번역을 수정할 때는 아래 순서를 기본 절차로 사용합니다.
locales/*.toml수정./scripts/sync_userfront_locales.sh실행- UserFront 회귀 테스트 실행
- 예:
cd userfront && flutter test test/english_locale_placeholder_test.dart
- 예:
- 전체 키 정합성 점검
- 예:
node tools/i18n-scanner/index.js
- 예: