| name | arib-docs-language |
| argument-hint | <component> --locale <code> |
| description | Docs | Universal language/i18n compliance - RTL, LTR, CJK, Indic, fonts, formatting, accessibility |
/arib-docs-language Command
Purpose
Verify language, localization, and script-direction compliance for any target locale or writing system.
Trigger
User types /arib-docs-language [component] [--locale <code>]
Examples:
/arib-docs-language header --locale ar-SA
/arib-docs-language user-profile --locale zh-CN
/arib-docs-language checkout --locale ja
/arib-docs-language all --locale he
/arib-docs-language dashboard --locale hi
/arib-docs-language all ← audits all locales configured in the project
Instructions
Step 1: Activate LANGUAGE SPECIALIST Agent Mode
Enter universal language verification mode by reading .claude/agents/language.md.
Determine the target script direction from the locale:
ar, he, fa, ur → RTL
zh, ja, ko → CJK
hi, bn, ta, te → Indic
en, fr, de, es, pt, tr, ru → LTR
- Mixed content → Bidirectional
Step 2: Scan for Hardcoded Strings
Search the target component for hardcoded user-facing text:
grep -rn ">[^<{]*[a-zA-Z\u0600-\u06FF\u4E00-\u9FFF\u3040-\u309F][^<{]*<" \
--include="*.js" --include="*.tsx" --include="*.ts" --include="*.vue" \
--include="*.jsx" --include="*.svelte" [component-path]
For each match found:
- Flag the hardcoded string
- Check if it should be an i18n key instead
- Verify the string exists in the target locale's translation file
- Document location and replacement needed
Expected: All user-facing text should use i18n keys like t('key.name') or equivalent.
Step 3: Check Content Direction Implementation
Verify proper direction markup for the target locale:
For RTL locales (ar, he, fa, ur):
- Root/body has
dir="rtl" when locale is active
- Dynamically set based on language selection
- Check:
<html dir={isRTL ? 'rtl' : 'ltr'}>
For CJK locales (zh, ja, ko):
- Verify
lang attribute is set correctly
- Check for
writing-mode support if vertical text is needed
- Verify CJK line-break rules (
word-break: keep-all for Korean, etc.)
For Bidi content:
- Check
<bdi> / unicode-bidi usage for mixed-direction text
- Verify user-generated content is isolated with
dir="auto"
Step 4: Check CSS Logical Properties
Verify CSS uses logical properties for bidirectional support:
Correct (logical properties):
margin-inline-start instead of margin-left
margin-inline-end instead of margin-right
padding-inline-start instead of padding-left
text-align: start instead of text-align: left
inset-inline-start instead of left
border-inline-start instead of border-left
Scan for problematic patterns:
grep -rn "margin-left\|margin-right\|padding-left\|padding-right\|text-align:\s*left\|text-align:\s*right" \
--include="*.css" --include="*.scss" --include="*.module.css" [component-path]
Document each instance that should use logical properties.
Step 5: Check Font & Typography
Verify font support for the target locale:
| Script Group | Required Check |
|---|
| Arabic | Arabic font family, correct shaping, tashkeel rendering |
| CJK | CJK font loaded, correct weight, character coverage |
| Indic | Devanagari/Bengali/Tamil font, complex ligatures |
| Cyrillic | Extended Cyrillic coverage for all target languages |
| Latin Ext. | Accented characters, special glyphs (ñ, ß, ø, etc.) |
Check:
- Font family specified in CSS for the locale
- Fallback fonts in correct priority order
@font-face declarations load properly
- No font-weight issues with the target script
Step 6: Check Number, Date, Currency Formatting
Verify locale-aware formatting using Intl APIs:
| Format | What to Check |
|---|
| Numbers | Correct digit system (Eastern Arabic ٠١٢, Devanagari ०१२) |
| Decimals | Correct separator (comma vs. period vs. momayyez) |
| Dates | Correct format (DD/MM, MM/DD, YYYY年MM月DD日) |
| Calendar | Correct calendar system (Gregorian, Hijri, Buddhist, etc.) |
| Currency | Correct symbol, placement, and formatting |
| Time | 12-hour vs. 24-hour based on locale convention |
| Timezone | Correct default timezone for the target market |
Expected: All formatting should use Intl.NumberFormat, Intl.DateTimeFormat, Intl.DisplayNames - never hardcoded logic.
Step 7: Check Input & Text Processing
Verify the component handles multilingual input correctly:
- IME Support: Input method editors work for CJK, Indic scripts
- Text selection: Multi-byte characters select correctly
- Text truncation: Respects grapheme clusters, not byte length
- Search/filter: Unicode-aware comparison and sorting
- Form validation: Regex patterns allow target script characters
- Placeholder text: Translated and direction-correct
- Max-length: Counts graphemes, not bytes or code units
Step 8: Check UI Layout & Mirroring
For RTL locales, verify:
- Icons with directional meaning are mirrored (arrows, back/forward)
- Icons with universal meaning are NOT mirrored (clock, search, checkmark)
- Scrollbars, sliders, progress bars reverse direction
- Tables and data grids read correctly in target direction
- Breadcrumbs, navigation flow match reading direction
- No absolute positioning that breaks in mirrored layout
For CJK locales, verify:
- Text doesn't overflow fixed-width containers (CJK chars are wider)
- Line height accommodates taller characters
- Ruby text (furigana) renders correctly for Japanese
Step 9: Check Accessibility
Verify locale-aware accessibility:
lang attribute set on elements with different-language content
- Screen reader announces text in correct language
- Keyboard navigation follows locale's reading direction
- Focus order matches visual layout for the locale
- ARIA labels are translated
Step 10: Generate Compliance Report
COMPLIANT
✅ LANGUAGE AUDIT - COMPLIANT
Component: [component-name]
Target Locale: [locale-code] ([script-direction])
Audit Date: [date]
Findings:
- Hardcoded strings: PASS (all use i18n keys)
- Content direction: PASS (dir attribute correct)
- CSS logical properties: PASS (no physical properties)
- Font & typography: PASS (target script supported)
- Number/Date/Currency: PASS (Intl APIs used)
- Input & text processing: PASS (Unicode-aware)
- UI layout & mirroring: PASS (direction-correct)
- Accessibility: PASS (lang + ARIA correct)
Status: Ready for [locale-name] market
NON-COMPLIANT
❌ LANGUAGE AUDIT - NON-COMPLIANT
Component: [component-name]
Target Locale: [locale-code] ([script-direction])
Audit Date: [date]
Issues Found:
1. [CRITICAL] Hardcoded Strings:
- File: [path], Line [n]: "[text]"
- Action: Move to i18n translation file under key [suggested-key]
2. [HIGH] Direction Support:
- Missing dir="rtl" on [element]
- Action: Add dynamic dir attribute based on locale
3. [MEDIUM] CSS Physical Properties:
- File: [path]: margin-left used instead of margin-inline-start
- Action: Replace with CSS logical property
4. [MEDIUM] Font Loading:
- Missing [script] font configuration
- Action: Add font-face declaration with fallback stack
5. [LOW] Accessibility:
- Missing lang="[code]" on [element]
- Action: Add lang attribute for embedded content
Priority Actions:
1. [Most critical fix]
2. [Next fix]
3. [Next fix]
Re-run audit after fixes: /arib-docs-language [component] --locale [code]
Supported Locales (Non-Exhaustive)
| Code | Language | Script | Direction |
|---|
| ar-SA | Arabic (Saudi) | Arabic | RTL |
| ar-EG | Arabic (Egypt) | Arabic | RTL |
| he | Hebrew | Hebrew | RTL |
| fa | Persian | Arabic | RTL |
| ur | Urdu | Arabic | RTL |
| zh-CN | Chinese (Simp) | Han | LTR |
| zh-TW | Chinese (Trad) | Han | LTR |
| ja | Japanese | Han+Kana | LTR/TTB |
| ko | Korean | Hangul | LTR |
| hi | Hindi | Devanagari | LTR |
| bn | Bengali | Bengali | LTR |
| ta | Tamil | Tamil | LTR |
| th | Thai | Thai | LTR |
| ru | Russian | Cyrillic | LTR |
| en | English | Latin | LTR |
| fr | French | Latin | LTR |
| de | German | Latin | LTR |
| es | Spanish | Latin | LTR |
| pt-BR | Portuguese | Latin | LTR |
| tr | Turkish | Latin | LTR |
RTL vs LTR Comprehensive Checklist
HTML/DOM Level
| Element | RTL Check | LTR Check |
|---|
<html> | dir="rtl" set | dir="ltr" or omitted |
<body> | Inherits from html or explicit | Inherits from html or omitted |
| Language attribute | lang="ar" or lang="ar-SA" | lang="en" or lang="en-US" |
| Input/form elements | dir="auto" for user input | dir="ltr" or omit |
| Embedded content | Nested lang attribute if different | lang attribute if needed |
CSS Logical Properties Reference
Replace physical properties with logical equivalents for bidirectional support:
Margins:
margin-left: 1rem;
margin-right: 1rem;
margin-inline-start: 1rem;
margin-inline-end: 1rem;
Padding:
padding-left: 20px;
padding-right: 20px;
padding-inline-start: 20px;
padding-inline-end: 20px;
Text Alignment:
text-align: left;
text-align: right;
text-align: start;
text-align: end;
Borders:
border-left: 2px solid red;
border-right: 2px solid blue;
border-inline-start: 2px solid red;
border-inline-end: 2px solid blue;
Positioning:
left: 10px;
right: 10px;
inset-inline-start: 10px;
inset-inline-end: 10px;
Width/Height on blocks:
left: 0;
top: 0;
inset: 0;
inset-inline-start: 0;
inset-block-start: 0;
i18n Key Naming Conventions
Standard hierarchy for translation keys:
feature.section.action.description
Examples:
├─ navigation
│ ├─ menu.home
│ ├─ menu.about
│ ├─ menu.contact
│ └─ breadcrumb.separator
├─ user
│ ├─ profile.title
│ ├─ profile.email.label
│ ├─ profile.email.error.required
│ └─ profile.save.button
├─ forms
│ ├─ login.title
│ ├─ login.email.label
│ ├─ login.email.error.invalid
│ ├─ login.password.label
│ ├─ login.password.error.weak
│ └─ login.submit.button
└─ errors
├─ http.404.title
├─ http.404.message
├─ http.500.title
└─ http.500.message
Avoid:
- Generic keys:
label.1, text.2, msg (unscalable)
- Concatenated keys:
title_subtitle_desc (hard to translate)
- Feature duplication:
user_profile_title and admin_profile_title (use context instead)
Do use:
- Contextual nesting:
pages.settings.profile.title
- Semantic naming:
validation.email.invalid
- Feature-scoped keys:
checkout.payment.method.label
Number/Date/Currency Formatting by Locale Examples
Number Formatting
JavaScript using Intl.NumberFormat:
const num = 1234567.89;
new Intl.NumberFormat('en-US').format(num);
new Intl.NumberFormat('de-DE').format(num);
new Intl.NumberFormat('ar-SA').format(num);
new Intl.NumberFormat('en-IN').format(num);
Python:
import babel.numbers
locale.format_number(1234567.89, locale='en_US')
locale.format_number(1234567.89, locale='de_DE')
locale.format_number(1234567.89, locale='ar_SA')
Date Formatting
JavaScript:
const date = new Date('2026-04-19');
new Intl.DateTimeFormat('en-US').format(date);
new Intl.DateTimeFormat('de-DE').format(date);
new Intl.DateTimeFormat('ar-SA').format(date);
new Intl.DateTimeFormat('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric'
}).format(date);
new Intl.DateTimeFormat('ja-JP').format(date);
new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: true
}).format(date);
new Intl.DateTimeFormat('de-DE', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
hour12: false
}).format(date);
Currency Formatting
JavaScript:
const amount = 1234.56;
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(amount);
new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR'
}).format(amount);
new Intl.NumberFormat('en-GB', {
style: 'currency',
currency: 'GBP'
}).format(amount);
new Intl.NumberFormat('ar-SA', {
style: 'currency',
currency: 'SAR'
}).format(amount);
new Intl.NumberFormat('en-IN', {
style: 'currency',
currency: 'INR'
}).format(amount);
new Intl.NumberFormat('ja-JP', {
style: 'currency',
currency: 'JPY'
}).format(amount);
new Intl.NumberFormat('zh-CN', {
style: 'currency',
currency: 'CNY'
}).format(amount);
Bidirectional Text Handling Patterns
Unicode Bidirectional Algorithm (UBA) Support
Problem: Mixed LTR and RTL text can display incorrectly without proper markup.
Example:
User input: "Hello مرحبا World" (English + Arabic + English)
Without markup: Hello مرحبا World (may display incorrectly)
With markup: Hello <bdi>مرحبا</bdi> World (correct)
Solutions:
<bdi> tag (Bidirectional Isolation):
<p>Posted by <bdi>Ahmed_2026</bdi> on <time>2026-04-19</time></p>
unicode-bidi CSS:
.user-input {
unicode-bidi: isolate;
direction: auto;
}
- HTML5
dir="auto":
<input type="text" dir="auto" placeholder="Enter name">
<p dir="auto">Start typing in any direction...</p>
- Strong directional characters for resetting:
<p>Email: user@example.com‬ <span lang="ar">البريد الإلكتروني</span></p>
Font Stack Recommendations by Script
Arabic Script (Arabic, Urdu, Persian, Farsi)
body {
font-family:
-apple-system, BlinkMacSystemFont,
"Segoe UI",
"Traditional Arabic",
"Simplified Arabic",
"Droid Arabic Naskh",
"GE Dinar One",
"Arial",
sans-serif;
font-size: 16px;
}
h1, h2, h3 {
font-family: "GE Dinar Two", "Arial", sans-serif;
font-weight: 600;
}
.arabic-text {
font-feature-settings: "liga" 1, "dlig" 1;
letter-spacing: 0.5px;
}
Chinese (Simplified & Traditional)
.zh-CN {
font-family:
-apple-system, BlinkMacSystemFont,
"Microsoft YaHei",
"WenQuanYi Micro Hei",
"PingFang SC",
"Hiragino Sans GB",
"STHeiti",
"sans-serif";
line-height: 1.6;
}
.zh-TW {
font-family:
-apple-system, BlinkMacSystemFont,
"Microsoft JhengHei",
"WenQuanYi Micro Hei",
"PingFang TC",
"Hiragino Sans",
"STHeiti",
"sans-serif";
word-break: keep-all;
}
Japanese (CJK + Kana)
body {
font-family:
-apple-system, BlinkMacSystemFont,
"Segoe UI",
"Noto Sans JP",
"Hiragino Kaku Gothic Pro",
"Yu Gothic",
"MS PGothic",
"sans-serif";
line-height: 1.7;
}
ruby {
ruby-position: over;
font-size: 0.5em;
}
rt {
font-size: inherit;
font-family: "Hiragino Kaku Gothic Pro", sans-serif;
}
.japanese-text {
word-break: break-word;
line-break: strict;
}
Korean (Hangul)
body {
font-family:
-apple-system, BlinkMacSystemFont,
"Segoe UI",
"Noto Sans CJK KR",
"Apple SD Gothic Neo",
"Noto Sans Korean",
"Malgun Gothic",
"sans-serif";
word-break: keep-all;
line-height: 1.6;
}
Indic Scripts (Devanagari, Bengali, Tamil, Telugu)
.devanagari {
font-family:
"Noto Sans Devanagari",
"ITrans",
"Arial Unicode MS",
sans-serif;
font-size: 18px;
line-height: 1.8;
letter-spacing: 0.3px;
}
.bengali {
font-family:
"Noto Sans Bengali",
"Arial Unicode MS",
sans-serif;
font-size: 17px;
line-height: 1.8;
}
.tamil {
font-family:
"Noto Sans Tamil",
"Arial Unicode MS",
sans-serif;
font-size: 18px;
line-height: 1.8;
}
Cyrillic (Russian, Ukrainian, Serbian)
body {
font-family:
-apple-system, BlinkMacSystemFont,
"Segoe UI",
"Noto Sans",
"Roboto",
"Arial",
sans-serif;
font-size: 16px;
}
@font-face {
font-family: "Roboto";
src: url("/fonts/roboto-cyrillic-ext.woff2") format("woff2");
unicode-range: U+0400-04FF, U+0500-052F;
}
Emoji & Symbol Support
body {
font-family:
"System UI",
"Segoe UI",
"Helvetica",
sans-serif,
"Apple Color Emoji",
"Segoe UI Emoji",
"Noto Color Emoji";
}
Common i18n Mistakes
| Mistake | Example | Fix |
|---|
| Hardcoded dates | "April 19, 2026" in code | Use Intl.DateTimeFormat with locale |
| Hardcoded numbers | "1,234.56" | Use Intl.NumberFormat |
| String concatenation | "Total: " + amount (fails in RTL) | Use message format: t('price.total', { amount }) |
| No dir attribute | Assume LTR layout | Always set dir="ltr" or dir="rtl" |
| Physical CSS | margin-left: 10px | Use margin-inline-start |
| Left/right icons | Arrow always points left | Mirror for RTL, use symbolic icons instead |
| No font stack | Only specify Latin font | Provide fallback chain for target scripts |
| Ignore line height | Default 1.2 for CJK | Increase to 1.6-1.8 for complex scripts |
| No IME support | Assume QWERTY input | Test with CJK input method editors |
| Email in URL param | ?email=user@example.com | RTL can break parameter parsing |
Related Skills
/arib-docs-api - Document API endpoints with locale support
/arib-docs-generate - Generate i18n-compliant documentation
/arib-io - Process i18n audit requests
Notes
- This audit ensures users of ANY locale have a proper experience
- CSS logical properties are essential for bidirectional support
- All user-visible text must be i18n compliant
- Font loading is critical for proper character display across scripts
- Regional standards (calendars, number systems, currencies) matter for UX
- Run this audit before any release targeting a new market
- For multi-locale projects, run once per locale:
/arib-docs-language all --locale ar-SA then /arib-docs-language all --locale zh-CN
- Test with actual users from target locales when possible
- Use professional translation services, not machine translation, for user-facing text
- Budget extra time for RTL projects - layout changes are complex
- Consider hiring a native speaker for QA if entering new market