Skip to content

feat(i18n): add RTL text direction and typography support for Persian and Arabic#4075

Open
MRGhust wants to merge 2 commits into
openfrontio:mainfrom
MRGhust:rtl-support-open-frante
Open

feat(i18n): add RTL text direction and typography support for Persian and Arabic#4075
MRGhust wants to merge 2 commits into
openfrontio:mainfrom
MRGhust:rtl-support-open-frante

Conversation

@MRGhust
Copy link
Copy Markdown
Contributor

@MRGhust MRGhust commented May 30, 2026

Description:

This Pull Request introduces non-destructive, class-based Right-to-Left (RTL) text flow and premium typography support for Persian (fa), Arabic (ar), and Hebrew (he) language elements.

Instead of full-document mirroring (which would break or mirror the global WebGL game coordinate layouts, main top bars, sidebars, and in-game controls), this solution targets only readable text containers (paragraphs, tables, lists, headers, and prose elements) and sets their text flow and alignment under a dynamic .rtl-text CSS class.

Key Improvements:

  • Class-based RTL activation: Adds/removes .rtl-text and standard lang attributes dynamically inside LangSelector.ts based on language selection.
  • Premium Native Typography: Applies a professional, beautiful native sans-serif font stack under .rtl-text inside styles.css for clean Arabic/Persian/Hebrew glyph rendering.
  • Non-destructive logical padding overrides: Intercepts physical .pl-4 and .pl-5 styles in RTL mode and remaps them to right paddings to align bullet points and table cells perfectly on the right.
  • Bidi safety: Enforces standard LTR flow for code/keybind monospace labels (e.g. Esc, Ctrl, Shift) to prevent symbol inversion.

All 1,300+ automated unit tests passed successfully, and ESLint / Prettier formatting checks passed with zero warnings.


  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • I have added relevant tests to the test directory
  • I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced

Discord Username: NOBODYiran

Screenshot 2026-05-30 110319

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 30, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b018cba8-b7c1-4632-8961-84641ee8a53c

📥 Commits

Reviewing files that changed from the base of the PR and between 24bef58 and a703996.

📒 Files selected for processing (1)
  • src/client/styles.css
💤 Files with no reviewable changes (1)
  • src/client/styles.css

Walkthrough

This PR centralizes RTL language codes, applies or removes an rtl-text class and sets document.documentElement.lang during initial language selection and on language changes, and adds CSS rules under html.rtl-text to flip direction, alignment, and padding while keeping inline code LTR.

Changes

RTL Language Support

Layer / File(s) Summary
RTL language detection and initial setup
src/client/LangSelector.ts
Adds a RTL_LANGUAGES set and, during initial language setup, checks the selected language, toggles rtl-text on document.documentElement, and sets the document lang attribute.
RTL updates on language change
src/client/LangSelector.ts
changeLanguage now repeats RTL detection and toggles the rtl-text class and lang attribute so the document reflects the new language direction.
RTL-specific styling
src/client/styles.css
Adds html.rtl-text rules to set direction: rtl/text-align: right for typography, swap list and .pl-4/.pl-5 padding to the right, and force .font-mono, kbd, and code to render LTR.`

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

Words turn to the right and find their place,
Script and spacing swap a gentle pace,
Persian, Arabic, Hebrew sing,
The page aligns for every string,
A small change brings a wider view.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main change: adding RTL text direction and typography support for Persian and Arabic languages.
Description check ✅ Passed The description is directly related to the changeset, providing detailed context about the RTL implementation approach, key improvements, and testing completion.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/client/LangSelector.ts (1)

214-220: ⚡ Quick win

Extract the RTL logic to avoid duplication.

The same RTL detection and class/attribute update logic appears in both initializeLanguage (lines 103-109) and changeLanguage (lines 214-220). Extract this into a helper method to keep the code DRY.

♻️ Suggested refactor

Add a private helper method:

+  private applyRtlSettings(lang: string): void {
+    const isRtl = RTL_LANGUAGES.has(lang);
+    if (isRtl) {
+      document.documentElement.classList.add("rtl-text");
+    } else {
+      document.documentElement.classList.remove("rtl-text");
+    }
+    document.documentElement.setAttribute("lang", lang);
+  }

Then use it in both places:

   this.defaultTranslations = defaultTranslations;
   this.translations = translations;
   this.currentLang = userLang;

-  const isRtl = RTL_LANGUAGES.has(userLang);
-  if (isRtl) {
-    document.documentElement.classList.add("rtl-text");
-  } else {
-    document.documentElement.classList.remove("rtl-text");
-  }
-  document.documentElement.setAttribute("lang", userLang);
+  this.applyRtlSettings(userLang);

   await this.loadLanguageList();
   localStorage.setItem("lang", lang);
   this.translations = await this.loadLanguage(lang);
   this.currentLang = lang;

-  const isRtl = RTL_LANGUAGES.has(lang);
-  if (isRtl) {
-    document.documentElement.classList.add("rtl-text");
-  } else {
-    document.documentElement.classList.remove("rtl-text");
-  }
-  document.documentElement.setAttribute("lang", lang);
+  this.applyRtlSettings(lang);

   this.applyTranslation();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/LangSelector.ts` around lines 214 - 220, Extract the duplicated
RTL handling in initializeLanguage and changeLanguage into a private helper
(e.g., applyRtlForLang or updateRtlForLang) that takes the lang string, sets
document.documentElement.lang attribute, checks RTL_LANGUAGES.has(lang) and
adds/removes the "rtl-text" class accordingly; then replace the
RTL/class/attribute lines in initializeLanguage and changeLanguage with calls to
that helper to keep logic DRY and centralized.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/styles.css`:
- Around line 42-48: Remove the invalid element selector "html.rtl-text
font-mono" from the selector list—keep the class-based selector ".font-mono" and
the other valid selectors ("html.rtl-text .font-mono", "html.rtl-text kbd",
"html.rtl-text code") so the rule applies correctly; update the selector list in
the block that currently starts with "html.rtl-text font-mono" to exclude the
erroneous element selector.

---

Nitpick comments:
In `@src/client/LangSelector.ts`:
- Around line 214-220: Extract the duplicated RTL handling in initializeLanguage
and changeLanguage into a private helper (e.g., applyRtlForLang or
updateRtlForLang) that takes the lang string, sets document.documentElement.lang
attribute, checks RTL_LANGUAGES.has(lang) and adds/removes the "rtl-text" class
accordingly; then replace the RTL/class/attribute lines in initializeLanguage
and changeLanguage with calls to that helper to keep logic DRY and centralized.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 606ed08f-1976-4a4b-9c58-b615e4eed567

📥 Commits

Reviewing files that changed from the base of the PR and between f366f76 and 24bef58.

📒 Files selected for processing (2)
  • src/client/LangSelector.ts
  • src/client/styles.css

Comment thread src/client/styles.css Outdated
@github-project-automation github-project-automation Bot moved this from Triage to Development in OpenFront Release Management May 30, 2026
@MRGhust MRGhust changed the title feat(i18n): add non-destructive RTL text direction and typography sup… feat(i18n): add RTL text direction and typography support for Persian and Arabic May 30, 2026
@MRGhust MRGhust marked this pull request as draft May 30, 2026 07:49
@MRGhust MRGhust marked this pull request as ready for review May 30, 2026 07:52
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a703996410

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/client/styles.css
Comment on lines +42 to +46
html.rtl-text .font-mono,
html.rtl-text kbd,
html.rtl-text code {
direction: ltr;
display: inline-block;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid overriding flex layouts for monospace controls

When Persian, Arabic, or Hebrew is selected, this selector applies display: inline-block to every .font-mono element, not just inline key labels/code. Several existing controls combine .font-mono with layout utilities such as flex (for example the keybind button in src/client/components/baseComponents/setting/SettingKeybind.ts), so this higher-specificity rule overrides their flex display and removes the centering/alignment behavior in RTL mode. Limit the display override to actual inline kbd/code elements or preserve the existing display for .font-mono containers.

Useful? React with 👍 / 👎.

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

Labels

None yet

Projects

Status: Development

Development

Successfully merging this pull request may close these issues.

1 participant