Skip to content

feat(i18n): add Persian (fa) locale with RTL — desktop + dashboard - #86335

Open
blackorange-mega wants to merge 4 commits into
NousResearch:mainfrom
blackorange-mega:feat/i18n-persian-desktop-dashboard
Open

feat(i18n): add Persian (fa) locale with RTL — desktop + dashboard#86335
blackorange-mega wants to merge 4 commits into
NousResearch:mainfrom
blackorange-mega:feat/i18n-persian-desktop-dashboard

Conversation

@blackorange-mega

@blackorange-mega blackorange-mega commented Aug 14, 2026

Copy link
Copy Markdown

What does this PR do?

Adds Persian (Farsi, fa) as a selectable UI language in both graphical front-ends — the Electron desktop app and the web dashboard — including right-to-left layout.

Persian was missing from both GUI catalogs: apps/desktop/src/i18n/ shipped en, zh, zh-hant, ja, ar, and web/src/i18n/ shipped 17 locales with no fa.

Why this approach. It mirrors #70870 (feat(i18n): Arabic (ar) locale with RTL support), which is the existing precedent for adding one language across the GUI surfaces. As #76854 notes, the RTL infrastructure already exists, so this is a translation change rather than an architectural one — fa joins the RTL_LOCALES sets and inherits the plumbing Arabic already uses.

The issue asks only for the desktop app. The dashboard is included because it is the other GUI, has the same gap, and follows the same three-line registration — leaving it out would ship a half-Persian product for the same review cost.

Scope — and what this deliberately leaves alone

This PR touches only the two GUI catalogs. It does not add locales/fa.yaml and does not register fa in agent/i18n.py.

That CLI/gateway half is already covered by the open, approved #53398, and CONTRIBUTING.md asks contributors to improve an existing PR rather than open a competing one. The two are complementary and can land in either order — the desktop and dashboard catalogs are independent TypeScript modules with their own Locale union, so nothing here depends on the Python side.

Related Issue

Fixes #76854

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)

Changes Made

Desktop (apps/desktop/src/i18n/)

  • fa.tsnew. Persian catalog built with defineLocale(), so English keys added later fall back cleanly instead of breaking the build
  • types.tsfa added to the Locale union
  • catalog.ts — registered in TRANSLATIONS
  • languages.ts — picker entry (endonym فارسی, englishName: 'Persian' for search) plus aliases fa-IR, fa-AF, persian, farsi, فارسی
  • context.tsxfa added to RTL_LOCALES
  • context.test.tsx, languages.test.ts — new coverage

Dashboard (web/src/i18n/)

  • fa.tsnew. Persian catalog built with defineLocale()
  • types.tsfa added to the Locale union
  • context.tsxTRANSLATIONS, LOCALE_META (endonym فارسی), RTL_LOCALES

RTL

No new CSS. Both providers already set document.documentElement.dir from RTL_LOCALES, and the dashboard's html[dir="rtl"] rule in index.css is language-agnostic, so Tailwind's logical utilities (ms-/me-, ps-/pe-) flip for Persian exactly as they do for Arabic.

Chat-message bidi is unaffected — that resolves per-message from content via dir="auto" (#44596), independently of UI language.

Translation notes

  • {placeholder} tokens and arrow-function signatures are preserved verbatim; the dashboard catalog was checked against en.ts for placeholder parity.
  • Identifiers stay untranslated: brand and provider names, env-var keys, file paths, cron expressions, and protocol terms (MCP, OAuth, PKCE, YAML, SSH).
  • Latin digits throughout, matching ar.ts and the Latin numerals produced by runtime interpolation — mixing Eastern Arabic-Indic digits into interpolated strings would render inconsistently.
  • ZWNJ (U+200C) is applied where Persian orthography requires it (می‌شود, به‌روزرسانی).
  • Dari (fa-AF) aliases to this catalog rather than falling back to English. Dari and Iranian Persian differ in vocabulary and register but share an orthography and are mutually intelligible in writing, so a shared catalog serves Afghan users far better than English. If Dari-specific strings are wanted later, prs can be split out without disturbing this locale.

How to Test

  1. npm install --workspace apps/desktop && npm --workspace apps/desktop run dev
  2. Open Settings → Language and pick فارسی. The UI switches to Persian and the whole window mirrors to RTL — sidebar, chevrons, and padding flip. Switch back to English and it returns to LTR.
  3. Same in the dashboard (npm install --workspace web && npm --workspace web run dev) via the language switcher.
  4. Config round-trip: the choice persists as display.language: fa in ~/.hermes/config.yaml. Setting fa-IR, farsi, or فارسی there also resolves to Persian.
  5. Automated: npm --workspace apps/desktop exec vitest run src/i18n and npm --workspace web exec vitest run.

Tests added

  • context.test.tsx — Persian sets dir="rtl" / lang="fa" and reverts to LTR on switch back, matching the existing Arabic case
  • languages.test.tsfa, FA-IR, fa_af, Farsi, and فارسی all normalize to fa; fa-IR is a supported config value but not a Locale id

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs to make sure this isn't a duplicate — see the scope note above re: feat: Add Persian (fa) localization #53398 (CLI/gateway fa, intentionally not duplicated here). No open PR adds fa to either GUI catalog.
  • My PR contains only changes related to this feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass — N/A, no Python touched. This is a TypeScript-only change; the equivalent JS suites were run instead (below).
  • I've added tests for my changes
  • I've tested on my platform: Windows 11

Documentation & Housekeeping

  • I've updated relevant documentation — N/A (locale files are self-describing; no user-facing docs enumerate GUI locales)
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A (no new keys; display.language already exists and simply accepts one more value)
  • I've updated CONTRIBUTING.md or AGENTS.md — N/A (no architecture or workflow change)
  • I've considered cross-platform impact — the change is pure locale data plus a dir attribute; no platform-specific paths or APIs
  • I've updated tool descriptions/schemas — N/A (tool behavior unchanged; only display titles under assistant.tool.titles are translated)

Verification

  • tsc --noEmit — clean, desktop and web
  • vitest run src/i18n (desktop) — 29/29 pass
  • vitest run (web) — 218/218 pass
  • eslint — 0 errors on every touched path
  • prettier --check apps/desktop/src/i18n/ — clean. The web/ tree is not Prettier-governed under the root config (web/src/i18n/en.ts and ar.ts do not satisfy it either), so web/src/i18n/fa.ts follows the double-quote, semicolon style of its siblings instead.

One note in the interest of full disclosure: the full desktop suite has pre-existing flaky failures on main in messaging/index, gateway-settings, and skills/index (DOM queries matching multiple elements). Measured on this machine, main alone fails 47 tests across 12 files; with this branch applied it is 42 across 11. This change neither causes nor fixes them — it only touches src/i18n/.

Summary by CodeRabbit

  • New Features

    • Added Persian (فارسی) as a supported language across desktop and web.
    • Added Persian translations for navigation, settings, sessions, workflows, and other core areas.
    • Added support for Persian locale aliases and language-name detection.
    • Persian automatically uses a right-to-left layout.
  • Bug Fixes

    • Ensured language and text direction reset correctly when switching away from Persian.
    • Improved Persian pluralized labels and count formatting.

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/i18n Localization, locales, translations comp/dashboard Web dashboard / control panel UI (dashboard/, landing) comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have type/feature New feature or request