diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts index 7a74a00b..43745b1f 100644 --- a/frontend/src/i18n/index.ts +++ b/frontend/src/i18n/index.ts @@ -5,10 +5,16 @@ * they go through type-checking and tree-shaking, and so non-translators * can't ship a broken JSON file that blocks the build. * - * Language detection order: - * 1. localStorage key ``encoach-lang`` (explicit user pick) - * 2. ``navigator.language`` - * 3. fallback ``en`` + * Language selection order (product decision: English is the default UI + * language at startup; Arabic is opt-in via the language toggle): + * 1. localStorage key ``encoach-lang`` (explicit user pick, persisted) + * 2. ``en`` — fallback used on first visit, regardless of browser locale + * + * We intentionally do **not** read ``navigator.language`` anymore: an + * Arabic-locale browser should still land on the English UI the first time + * a user visits, because the QA team and the product manager both sign off + * against the English baseline. Users that actively want Arabic flip the + * toggle once and the preference is remembered from then on. * * RTL handling: whenever the active language switches to one of RTL_LANGS, * we flip ``document.documentElement.dir`` so Tailwind's RTL utilities + @@ -31,6 +37,8 @@ export const SUPPORTED_LANGS = [ export type SupportedLang = (typeof SUPPORTED_LANGS)[number]["code"]; +export const DEFAULT_LANG: SupportedLang = "en"; + i18n .use(LanguageDetector) .use(initReactI18next) @@ -39,11 +47,16 @@ i18n en: { translation: en }, ar: { translation: ar }, }, - fallbackLng: "en", + // Explicit default — english is the baseline UI language at startup. + lng: DEFAULT_LANG, + fallbackLng: DEFAULT_LANG, supportedLngs: SUPPORTED_LANGS.map((l) => l.code), interpolation: { escapeValue: false }, detection: { - order: ["localStorage", "navigator", "htmlTag"], + // Only honour the user's saved pick. Navigator/htmlTag detection was + // removed so Arabic-locale browsers don't silently boot the UI in + // Arabic before the user has chosen. + order: ["localStorage"], caches: ["localStorage"], lookupLocalStorage: "encoach-lang", }, diff --git a/frontend/src/lib/api-client.ts b/frontend/src/lib/api-client.ts index bdce30b0..e0f97839 100644 --- a/frontend/src/lib/api-client.ts +++ b/frontend/src/lib/api-client.ts @@ -131,15 +131,17 @@ function refreshOnce(): Promise { } function getCurrentLanguage(): string { + // Mirrors the i18n bootstrap in src/i18n/index.ts: the user's explicit + // pick wins; everything else falls back to English. We intentionally do + // not consult navigator.language here so AI-generated content stays in + // English on first visit (matching the UI default) until the user flips + // the language toggle. try { const stored = localStorage.getItem("encoach-lang"); if (stored) return stored; } catch { // localStorage unavailable (SSR, sandboxing, etc.) } - if (typeof navigator !== "undefined" && navigator.language) { - return navigator.language.split("-")[0]; - } return "en"; }