Updated PLANS.md, AGENTS.md, and arabic-localization.md to reflect the “foundations now, full translations later” approach and marked progress accordingly.

Implemented localization foundations across backend and frontend (locale settings/middleware, preferred language, i18n wiring, RTL support, minimal Arabic UI strings, Accept-Language).
Added targeted backend and frontend tests plus a risks note for pending full translation coverage.
This commit is contained in:
2026-02-28 11:48:58 +03:00
parent fd90af33b3
commit d40bb10876
27 changed files with 407 additions and 68 deletions
+91
View File
@@ -0,0 +1,91 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import en from "./en.json";
import arSa from "./ar-sa.json";
const STORAGE_KEY = "locale";
const DEFAULT_LOCALE = "ar-sa";
const SUPPORTED_LOCALES = ["ar-sa", "en"];
function normalizeLocale(value) {
if (!value) {
return DEFAULT_LOCALE;
}
const lowered = value.toLowerCase();
if (lowered.startsWith("ar")) {
return "ar-sa";
}
return "en";
}
function readStoredLocale() {
if (typeof window === "undefined") {
return null;
}
try {
return window.localStorage.getItem(STORAGE_KEY);
} catch (error) {
return null;
}
}
function writeStoredLocale(locale) {
if (typeof window === "undefined") {
return;
}
try {
window.localStorage.setItem(STORAGE_KEY, locale);
} catch (error) {
// Ignore storage errors (private mode, blocked storage, etc.).
}
}
function getInitialLocale() {
const stored = readStoredLocale();
if (stored) {
return normalizeLocale(stored);
}
if (typeof navigator !== "undefined") {
return normalizeLocale(navigator.language);
}
return DEFAULT_LOCALE;
}
function isRtl(locale) {
return normalizeLocale(locale) === "ar-sa";
}
function applyDocumentLocale(locale) {
if (typeof document === "undefined") {
return;
}
const normalized = normalizeLocale(locale);
document.documentElement.lang = normalized;
document.documentElement.dir = isRtl(normalized) ? "rtl" : "ltr";
}
i18n.use(initReactI18next).init({
resources: {
en: { translation: en },
"ar-sa": { translation: arSa },
},
lng: getInitialLocale(),
fallbackLng: "en",
interpolation: { escapeValue: false },
});
applyDocumentLocale(i18n.language);
i18n.on("languageChanged", applyDocumentLocale);
export function setLocale(locale) {
const normalized = normalizeLocale(locale);
writeStoredLocale(normalized);
return i18n.changeLanguage(normalized);
}
export function getActiveLocale() {
return i18n.language || DEFAULT_LOCALE;
}
export { DEFAULT_LOCALE, SUPPORTED_LOCALES, STORAGE_KEY };
export default i18n;