From 96a294551260fde264ecfcfd5b172bd6e79cb06f Mon Sep 17 00:00:00 2001 From: Yamen Ahmad Date: Mon, 20 Apr 2026 17:19:49 +0400 Subject: [PATCH] fix(i18n): default startup language to English First-visit users now always land on the English UI regardless of navigator.language. Arabic remains one click away via the toggle, and the user's explicit pick is persisted to localStorage (encoach-lang) and honoured on every subsequent load. - src/i18n/index.ts: set lng: "en", drop navigator/htmlTag from the detector order so an Arabic-locale browser no longer silently boots the UI in Arabic before the user has chosen. - src/lib/api-client.ts: mirror the same policy for the Accept-Language header sent to the backend, so AI-generated content stays English on first visit instead of echoing the browser locale. Made-with: Cursor --- src/i18n/index.ts | 25 +++++++++++++++++++------ src/lib/api-client.ts | 8 +++++--- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/i18n/index.ts b/src/i18n/index.ts index 7a74a00..43745b1 100644 --- a/src/i18n/index.ts +++ b/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/src/lib/api-client.ts b/src/lib/api-client.ts index bdce30b..e0f9783 100644 --- a/src/lib/api-client.ts +++ b/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"; }