1
0
forked from baron/baron-sso
Files
baron-sso/docs/i18n.md

9.5 KiB

Baron SSO i18n(국제화) 처리 정책

1. 개요 (Overview)

본 문서는 Baron SSO 시스템(Backend, UserFront, AdminFront, DevFront)의 다국어 지원을 위한 표준 정책을 정의합니다. 모든 UI 텍스트와 서버 메시지는 하드코딩을 지양하고, 약속된 코드값(Key)을 기반으로 렌더링해야 합니다.


2. 기본 원칙 (Core Principles)

  1. Backend는 Key만 전달한다: API 응답에는 사용자에게 보여질 텍스트(메시지)를 포함하지 않는다. 대신 기계가 해석 가능한 code를 반환한다.
  2. Frontend가 렌더링 주체다: 모든 번역 데이터(Dictionary)는 프론트엔드 애플리케이션이 보유하며, 백엔드로부터 받은 code나 UI의 키값을 매핑하여 적절한 언어로 표시한다.
  3. URL 기반 로케일 격리: 언어 설정은 URL 경로(/{locale}/...)에 명시적으로 드러나야 한다.
  4. 포맷 및 관리:
    • 모든 리소스는 TOML 포맷을 사용한다. (주석 가능, 가독성 우수)
    • **template.toml**을 기준(Master)으로 삼아, 각 언어 파일(ko.toml, en.toml)이 키를 빠짐없이 구현했는지 관리한다.

3. 키(Key) 명명 규칙 (Naming Convention)

메시지 키는 계층 구조를 가지며 snake_casedot(.) 표기법을 혼용하여 체계적으로 관리합니다. 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 라우팅 및 리다이렉트 동작

  1. Root 접속 시 (/):
    • 사용자의 브라우저 navigator.language를 감지합니다.
    • ko 계열이면 /ko/dashboard로 리다이렉트합니다.
    • 그 외에는 /en/dashboard로 리다이렉트합니다.
    • 단, 이전에 언어를 선택한 쿠키나 로컬스토리지 값이 있다면 그 값을 우선합니다.
    • 로컬스토리지 키는 **locale**을 사용합니다.
  2. 언어 변경 시:
    • 모든 화면에는 **언어 선택기(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 사용.

5.2.2 관리 프로세스 (Template & CI)

  1. template.toml: 개발자가 새로운 번역 키를 추가할 때 반드시 이 파일에 먼저 정의해야 합니다.
  2. ko.toml, en.toml: 템플릿의 키를 바탕으로 실제 번역 값을 채워 넣습니다.
  3. CI 검증 (Verification):
    • Level 1: 리소스 동기화 검사 (template vs lang)
      • template.toml에 있는 모든 키가 ko.toml, en.toml에 존재하는지 재귀적으로 검사합니다.
      • 누락 시 빌드 실패.
    • Level 2: 코드 사용성 검사 (code vs template)
      • 전체 프론트엔드 소스코드(src/**/*.{ts,tsx}, lib/**/*.dart)를 스캔하여 번역 함수(t('key'), 'key'.tr())에 사용된 키를 추출합니다.
      • Missing Key: 코드에는 있는데 template.toml에 없는 키를 검출하여 경고 또는 에러를 발생시킵니다.
      • Unused Key: template.toml에는 있는데 코드 어디에서도 쓰이지 않는 키를 리포트하여 정리할 수 있게 합니다.

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)는 프로덕션에서 다음 규칙으로 에러를 표시합니다.

  1. Internal whitelist 코드
    • msg.userfront.error.whitelist.{code} 메시지를 노출합니다.
  2. ORY bypass 코드
    • msg.userfront.error.ory.{code} 메시지를 노출합니다.
  3. 그 외 코드
    • 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. 작업 체크리스트

  1. 공통: locales/template.toml 정의 및 초기 키셋 구성.
  2. CI: template.toml vs *.toml 키 동기화 검증 스크립트 작성 (scripts/verify-i18n.js or py).
  3. Admin/DevFront: Vite TOML 플러그인 설정 및 react-i18next 연동.
  4. UserFront: TOML -> JSON 변환 스크립트 추가 및 easy_localization 연동.