/* * i18n 초기화 — react-i18next + expo-localization. * · 지원 언어: ko(기본/폴백)·en·zh·ja * · 최초 렌더 전 동기 초기화(initImmediate:false) — expo-localization getLocales()는 동기. * · 사용자가 고른 언어는 AsyncStorage 키 `kintex_lang`에 지속. 없으면 디바이스 로케일 감지. * 보안: 번역 리소스에 시크릿/자격증명 없음. 외부 네트워크 로드 없음(리소스 번들 내장). */ import AsyncStorage from '@react-native-async-storage/async-storage'; import { getLocales } from 'expo-localization'; import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import { en } from './locales/en'; import { ja } from './locales/ja'; import { ko } from './locales/ko'; import { zh } from './locales/zh'; import { DEFAULT_LANG, SUPPORTED_LANGS, type Lang } from './types'; export const LANG_STORAGE_KEY = 'kintex_lang'; export const resources = { ko: { translation: ko }, en: { translation: en }, zh: { translation: zh }, ja: { translation: ja }, } as const; /** 지원 언어로 정규화(미지원 → 기본). 'zh-Hans' 등 지역 태그는 앞 2자로 축약. */ export function normalizeLang(code: string | null | undefined): Lang { if (!code) return DEFAULT_LANG; const base = code.toLowerCase().split(/[-_]/)[0]; return (SUPPORTED_LANGS as readonly string[]).includes(base) ? (base as Lang) : DEFAULT_LANG; } /** 디바이스 로케일(동기) → 지원 언어. */ function detectDeviceLang(): Lang { try { const locales = getLocales(); return normalizeLang(locales?.[0]?.languageCode ?? locales?.[0]?.languageTag); } catch { return DEFAULT_LANG; } } // ── 동기 초기화(디바이스 로케일 기준). 저장된 사용자 선택은 부팅 직후 loadStoredLanguage로 반영. ── if (!i18n.isInitialized) { i18n.use(initReactI18next).init({ resources, lng: detectDeviceLang(), fallbackLng: DEFAULT_LANG, supportedLngs: SUPPORTED_LANGS as unknown as string[], defaultNS: 'translation', interpolation: { escapeValue: false }, returnNull: false, initImmediate: false, // 최초 렌더에서 t()가 즉시 동작하도록 동기 초기화 }); } /** 저장된 사용자 선택 언어를 로드해 적용(부팅 시 1회). 없으면 디바이스 언어 유지. */ export async function loadStoredLanguage(): Promise { try { const saved = await AsyncStorage.getItem(LANG_STORAGE_KEY); if (saved) { const lang = normalizeLang(saved); if (i18n.language !== lang) await i18n.changeLanguage(lang); return lang; } } catch { /* graceful — 디바이스 언어 유지 */ } return normalizeLang(i18n.language); } /** 언어 변경 + 지속. 셀렉터 UI에서 호출. */ export async function setAppLanguage(lang: Lang): Promise { await i18n.changeLanguage(lang); try { await AsyncStorage.setItem(LANG_STORAGE_KEY, lang); } catch { /* graceful — 메모리 상 언어는 이미 반영됨 */ } } export default i18n;