import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import commonEn from './languages/en/common.json'; import commonId from './languages/id/common.json'; import validationEn from './languages/en/validation.json'; import validationId from './languages/id/validation.json'; const DEFAULT_LANGUAGE = 'en'; const SUPPORTED_LANGUAGES = ['en', 'id'] as const; export type SupportedLanguage = (typeof SUPPORTED_LANGUAGES)[number]; export const resources = { en: { common: commonEn.common, validation: validationEn.validation }, id: { common: commonId.common, validation: validationId.validation }, } as const; export interface I18nStorageAdapter { getLanguage(): Promise; setLanguage(lng: string): Promise; } export interface I18nConfig { storageAdapter?: I18nStorageAdapter; } // Store the adapter module-wide so manager.ts can access it export let globalStorageAdapter: I18nStorageAdapter | undefined; /** * Bootstraps the central i18n engine. * * It accepts an optional storage adapter to read the initial language. */ export async function setupI18n(config: I18nConfig = {}, defaultLanguage?: string): Promise { globalStorageAdapter = config.storageAdapter; let initialLng = defaultLanguage ? defaultLanguage : DEFAULT_LANGUAGE; try { if (globalStorageAdapter) { const storedLng = await globalStorageAdapter.getLanguage(); if (storedLng && SUPPORTED_LANGUAGES.includes(storedLng as SupportedLanguage)) { initialLng = storedLng; } } } catch (err) { console.warn('[i18n] Failed to read locale from storage', err); } await i18n.use(initReactI18next).init({ resources, lng: initialLng, fallbackLng: DEFAULT_LANGUAGE, defaultNS: 'common', interpolation: { escapeValue: false, // React already escapes values }, }); // Apply initial language to the DOM for SEO/Accessibility if (typeof document !== 'undefined') { document.documentElement.lang = i18n.language; } // Ensure DOM updates whenever the language changes later i18n.on('languageChanged', (lng) => { if (typeof document !== 'undefined') { document.documentElement.lang = lng; } }); }