From 528100dcf70b084bccba8dab329efbee16fabba7 Mon Sep 17 00:00:00 2001 From: Benziza <74437449+Benziza@users.noreply.github.com> Date: Wed, 9 Sep 2026 05:33:40 +0000 Subject: [PATCH] feat(i18n): add Arabic localization and basic RTL support (#14130) Co-authored-by: Hengfei Yang --- scripts/translations/README.md | 11 +- scripts/translations/translator.py | 6 +- web/src/App.vue | 21 +- web/src/components/CodeQueryEditor.vue | 2 +- web/src/components/Header.spec.ts | 22 + web/src/components/Header.vue | 4 +- web/src/layouts/MainLayout.spec.ts | 3 +- web/src/layouts/MainLayout.vue | 4 + web/src/lib/core/Icon/OIcon.spec.ts | 10 + web/src/lib/core/Icon/OIcon.vue | 33 + web/src/lib/core/Navbar/ONavGroup.spec.ts | 45 + web/src/lib/core/Navbar/ONavGroup.vue | 7 +- web/src/lib/forms/Switch/OSwitch.spec.ts | 24 + web/src/lib/forms/Switch/OSwitch.vue | 14 +- web/src/locales/alertLibraryParity.spec.ts | 1 + .../locales/anomalySensitivityParity.spec.ts | 8 +- web/src/locales/index.spec.ts | 29 +- web/src/locales/index.ts | 13 +- web/src/locales/languages/ar-SA.json | 17153 ++++++++++++++++ web/src/locales/localeMessages.spec.ts | 2 +- web/src/locales/numberFormat.ts | 1 + web/src/main.ts | 8 +- web/src/styles/rtl.css | 26 + 23 files changed, 17412 insertions(+), 35 deletions(-) create mode 100644 web/src/locales/languages/ar-SA.json create mode 100644 web/src/styles/rtl.css diff --git a/scripts/translations/README.md b/scripts/translations/README.md index 7061ea4961..de4f1451c6 100644 --- a/scripts/translations/README.md +++ b/scripts/translations/README.md @@ -53,6 +53,7 @@ no API calls, needs no API key, and installs nothing, so it costs a few seconds. The list lives in `LANGUAGE_NAMES` in `translator.py` — that dict is the single source of truth for both the locale codes and the language names used in the prompt. +- 🇸🇦 Arabic (ar-SA) - 🇹🇷 Turkish (tr-TR) - 🇨🇳 Simplified Chinese (zh-CN) - 🇹🇼 Traditional Chinese (zh-TW) @@ -68,9 +69,6 @@ source of truth for both the locale codes and the language names used in the pro - 🇵🇱 Polish (pl-PL) - 🇻🇳 Vietnamese (vi-VN) -RTL languages (Arabic, Persian) are deliberately excluded until the web app has -`dir="rtl"` support — see the note in `translator.py`. - ## How It Works 1. **Source File**: All translations originate from `web/src/locales/languages/en-US.json` @@ -339,6 +337,7 @@ scripts/translations/ web/src/locales/languages/ ├── en-US.json # Source file (English) +├── ar-SA.json # Arabic translations ├── tr-TR.json # Turkish translations ├── zh-CN.json # Chinese translations ├── fr-FR.json # French translations @@ -424,7 +423,7 @@ lose it, nothing breaks; the run simply re-bills those strings. ### Two PRs Conflict in the Generated Locale Files **Symptom:** two open PRs both changed `en-US.json`; the second to merge has conflicts -in the 14 locale files and in `.translation_state.json`. +in the 15 locale files and in `.translation_state.json`. This is inherent to generating in each PR rather than in one serialised bot PR. Both branches rewrote the same generated files. Generating at merge time rather than on @@ -536,7 +535,7 @@ check that PR: 4. **Click "Merge when ready".** Now the workflow: - Triggers, because `en-US.json` differs from the base branch - - Translates only the **new or modified** keys to all 14 languages + - Translates only the **new or modified** keys to all 15 languages - Pushes `fr-FR.json`, `es-ES.json`, etc. plus `.translation_state.json` onto your branch - That one push re-runs your PR's checks; then it queues and merges @@ -586,7 +585,7 @@ source of truth that keeps subsequent runs incremental. ## Cost Considerations Translation is billed per token by DeepSeek. The whole `en-US.json` is ~10,700 -strings; a full 14-language rebuild is a one-time cost, and day-to-day runs only +strings; a full 15-language rebuild is a one-time cost, and day-to-day runs only translate the handful of new/changed keys in a given PR. ### Cost Optimization: diff --git a/scripts/translations/translator.py b/scripts/translations/translator.py index 62b69bc8fc..f4cb2fb121 100644 --- a/scripts/translations/translator.py +++ b/scripts/translations/translator.py @@ -56,6 +56,7 @@ SOURCE_LOCALE = "en-US" # Human-readable target names used in the translation prompt, keyed by the target # locale's filename stem (BCP-47 style, matching web/src/locales/languages/*.json). LANGUAGE_NAMES = { + "ar-SA": "Arabic", "tr-TR": "Turkish", "zh-CN": "Simplified Chinese", "fr-FR": "French", @@ -70,11 +71,6 @@ LANGUAGE_NAMES = { "ru-RU": "Russian", "pl-PL": "Polish", "vi-VN": "Vietnamese", - # NOTE: RTL languages (ar Arabic, fa Persian) are intentionally NOT listed - # yet — the web app has no dir="rtl" support, and the locale registry's - # strict on-disk/localeFileMap sync would force them to be user-selectable - # (and auto-served to ar/fa browsers) the moment their files are generated. - # Add them here together with RTL layout support and their web wiring. } # The term table injected into every prompt. Strings reach the model as isolated diff --git a/web/src/App.vue b/web/src/App.vue index 28355dbf3d..fafd6d971b 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -15,10 +15,12 @@ along with this program. If not, see . -->