diff --git a/js/components/src/i18n/i18n-loader.native.ts b/js/components/src/i18n/i18n-loader.native.ts new file mode 100644 index 00000000..754435a0 --- /dev/null +++ b/js/components/src/i18n/i18n-loader.native.ts @@ -0,0 +1,56 @@ +// Native translation loader - imports translations directly for bundling +// Metro will use this file for React Native builds + +// Import all translations directly so they're bundled into the app +import enUSCommon from "../../public/locales/en-US/common.json"; +import enUSSettings from "../../public/locales/en-US/settings.json"; +import esESCommon from "../../public/locales/es-ES/common.json"; +import esESSettings from "../../public/locales/es-ES/settings.json"; +import frFRCommon from "../../public/locales/fr-FR/common.json"; +import frFRSettings from "../../public/locales/fr-FR/settings.json"; +import ptBRCommon from "../../public/locales/pt-BR/common.json"; +import ptBRSettings from "../../public/locales/pt-BR/settings.json"; +import zhHantCommon from "../../public/locales/zh-Hant/common.json"; +import zhHantSettings from "../../public/locales/zh-Hant/settings.json"; + +const translationMap: Record = { + "en-US/common": enUSCommon, + "en-US/settings": enUSSettings, + "pt-BR/common": ptBRCommon, + "pt-BR/settings": ptBRSettings, + "es-ES/common": esESCommon, + "es-ES/settings": esESSettings, + "zh-Hant/common": zhHantCommon, + "zh-Hant/settings": zhHantSettings, + "fr-FR/common": frFRCommon, + "fr-FR/settings": frFRSettings, +}; + +export async function loadTranslationData( + locale: string, + namespace: string, +): Promise { + // Map base language codes to full locales + const fullLocale = locale.includes("-") + ? locale + : { + en: "en-US", + pt: "pt-BR", + es: "es-ES", + zh: "zh-Hant", + fr: "fr-FR", + }[locale] || locale; + + const localeNamespaceKey = `${fullLocale}/${namespace}`; + const translations = translationMap[localeNamespaceKey]; + + if (!translations) { + throw new Error(`No translation mapping for ${localeNamespaceKey}`); + } + + if (!translations || Object.keys(translations).length === 0) { + throw new Error("No translations found"); + } + + return translations; +} diff --git a/js/components/src/i18n/i18n-loader.ts b/js/components/src/i18n/i18n-loader.ts new file mode 100644 index 00000000..ad324c77 --- /dev/null +++ b/js/components/src/i18n/i18n-loader.ts @@ -0,0 +1,19 @@ +// Web translation loader - loads translations via fetch for code splitting +// Metro will use this file for web builds + +export async function loadTranslationData( + locale: string, + namespace: string, +): Promise { + const response = await fetch(`/locales/${locale}/${namespace}.json`); + if (!response.ok) { + throw new Error(`HTTP ${response.status}`); + } + const translations = await response.json(); + + if (!translations || Object.keys(translations).length === 0) { + throw new Error("No translations found"); + } + + return translations; +} diff --git a/js/components/src/i18n/i18next-config.ts b/js/components/src/i18n/i18next-config.ts index 67f82821..98840e14 100644 --- a/js/components/src/i18n/i18next-config.ts +++ b/js/components/src/i18n/i18next-config.ts @@ -145,68 +145,17 @@ export const I18NEXT_CONFIG = { debug: process.env.NODE_ENV === "development", }; -// Translation loading function that loads compiled JSON files per namespace +// Import platform-specific translation loader +// Metro will use i18n-loader.native.ts for React Native, i18n-loader.ts for web +import { loadTranslationData as platformLoadTranslationData } from "./i18n-loader"; + +// Translation loading function with error handling async function loadTranslationData( locale: string, namespace: string, ): Promise { try { - let translations: any = {}; - - try { - // For web environments, load from public directory - if (typeof window !== "undefined") { - const response = await fetch(`/locales/${locale}/${namespace}.json`); - if (!response.ok) { - throw new Error(`HTTP ${response.status}`); - } - translations = await response.json(); - } else { - // For React Native, use static requires for bundler compatibility - // Map base language codes to full locales - const fullLocale = locale.includes("-") - ? locale - : { - en: "en-US", - pt: "pt-BR", - es: "es-ES", - zh: "zh-Hant", - fr: "fr-FR", - }[locale] || locale; - - // Static requires for React Native bundler - const localeNamespaceKey = `${fullLocale}/${namespace}`; - const translationMap: Record = { - "en-US/common": require("../../public/locales/en-US/common.json"), - "pt-BR/common": require("../../public/locales/pt-BR/common.json"), - "es-ES/common": require("../../public/locales/es-ES/common.json"), - "zh-Hant/common": require("../../public/locales/zh-Hant/common.json"), - "fr-FR/common": require("../../public/locales/fr-FR/common.json"), - "en-US/settings": require("../../public/locales/en-US/settings.json"), - "pt-BR/settings": require("../../public/locales/pt-BR/settings.json"), - "es-ES/settings": require("../../public/locales/es-ES/settings.json"), - "zh-Hant/settings": require("../../public/locales/zh-Hant/settings.json"), - "fr-FR/settings": require("../../public/locales/fr-FR/settings.json"), - }; - - translations = translationMap[localeNamespaceKey]; - - if (!translations) { - throw new Error( - `No static translation mapping for ${localeNamespaceKey}`, - ); - } - } - } catch (loadError: any) { - throw new Error( - `Failed to load ${namespace} translations for ${locale}: ${loadError.message}`, - ); - } - - if (!translations || Object.keys(translations).length === 0) { - throw new Error("No translations found in file"); - } - + const translations = await platformLoadTranslationData(locale, namespace); return translations; } catch (error: any) { console.error(