Renderingen-US

Reader locales

Reader locale is a property of the compiler, not a translation of this site. The six /{locale}/ trees are translated prose mirrors of the English documentation; a reader locale changes the code surface — the keywords, type names, and diagnostic text the compiler reads and writes. This page is the hub of that feature; the pages below carry the reference data.

PageWhat it holds
Keyword referenceevery canonical key across all eight packs
Locale examplesone program shown in all eight surfaces
Diagnostics by localeone compiler failure printed in each language
English · Latin · العربية · हिन्दी · ไทย · Tiếng Việt · 简体中文 · 繁體中文per-locale keyword tables, native name, and script notes

The reference tables are generated from the eight reader packs themselves, so they cannot drift from the compiler by hand.

Reader locale#

Reader locale is Faber's system for rendering source code, compiler diagnostics, and language keywords in the reader's human language — without forking the semantics. A Thai programmer can read and write Faber source with Thai keywords, receive compiler errors in Thai, and collaborate through the same HIR as a Latin or Chinese user. The mechanism that localises code from Latin to Thai is the same mechanism that emits code to Rust: HIR → surface — neither is privileged.

Problem#

Large language models have localised the conversation around programming — a Thai computer scientist can ask an LLM for help in Thai — but not the durable artifact. The generated code, APIs, compiler errors, and documentation remain English-shaped. English proficiency becomes a gate to computer science, not merely to conversation.

Reader locale is the design response: the language a human uses to understand Faber — source, diagnostics, and optionally stdlib spellings — without English as a prerequisite. It is not application internationalisation (complete string-matrix coverage). It is reader dialect support: opt-in, partial packs over a semantic core that does not fork.

Product thesis: English should not be the required review language for software intent. LLMs have localised the conversation around programming; reader locale localises the durable artifact.

How it works#

A reader-locale pack maps Faber keywords, primitive type spellings, and diagnostic templates into a target language. Packs are TOML files with three tables:

  • [keywords] — maps keyword names to their localised spellings
  • [types] — maps primitive type names to localised spellings
  • [diagnostics.*] — maps diagnostic codes to localised message templates
  • [llm] — system prompt snippets and exemplars for LLM code generation

The compiler validates packs against a generated Latin scaffold — every keyword and type must have a defined spelling or explicitly inherit from Latin. Missing rows produce visible fallback rather than silent gaps.

Select a locale at the command line or in faber.toml:

faber check --locale th-TH program.fab
# faber.toml
[locale]
locale = "zh-Hans"

The legacy [reader] table name and --reader-locale flag are still accepted as aliases during the rename sweep; [locale] / --locale are canonical. The message language for diagnostics is independent of the code locale and is selected with --diagnostic-locale <locale>.

What localises and what does not#

LayerIn the HIR?Behaviour
Keywords, types, paired phrasesYesLossless across all renderings
Glyphs ← → ∴ ≡ ∪ ⇥Yes (invariant)Identical in every rendering
Type-first structureYesIdentical in every rendering
Numerals—ASCII only in all locales
CommentsNoOut of compiler scope; LLM-mediated, opt-in
Identifier namesNoPreserved byte-for-byte
Stdlib spellingsNoPer-locale overlay

The critical architectural guarantee: any locale surface can become any other, including Latin, at any time. A localised Faber file is never a trap because it is never the only form the code can take. faber format --locale la reproduces the former --canonical re-emit surface.

Shipped packs#

Eight packs ship with Radix today:

CodeLanguageScriptStatus
laLatina (Latin)LatinCanonical
enEnglishLatinBase surface
th-THไทยThaiReference proof
zh-Hans简体中文Simplified ChineseCoverage proof
zh-Hant繁體中文Traditional ChineseCoverage proof
arالعربيةArabicCoverage proof
hiहिन्दीDevanagariCoverage proof
viTiếng ViệtVietnamese (Latin)Coverage proof

en is the English reader surface — English keywords map to themselves, like la maps Latin to itself — and was renamed from the old llm pack in the 2026-08 locale rename. The reference locales below remain the collective architectural stress set; en and la do not stress the substrate because they are the base surfaces:

LocaleAccessArchitectural stress
th-THHighSpaceless script — the tokeniser stress test
zh-Hans / zh-HantVery highPaired keywords; sibling pack inheritance; NFKC width collapse
arHighRight-to-left; bidi isolation in diagnostics
hiVery highMatra/virama clusters; Indic numerals
viHighHeavy diacritics on Latin script; NFKC edge cases

The reference set is chosen for architectural coverage, not population. Population alone would prove nothing the substrate did not already handle.

Localised source examples#

Each of the six non-canonical locales has a complete Faber package under examples/reader-locale/ with localised source, diagnostic test cases, and a faber.toml manifest. The same program rendered in the two base surfaces — English (this page's reader locale) and canonical Latin — then the six packaged locale surfaces below:

English en — base surface

fn salve(string name) → string {
    const string msg ← "Salve, §!"(name)
    return msg
}

main {
    const string m ← salve("munde")
    print m
}

The surface an English reader writes: fn, const, string, return, main, print — the spellings every page on this site teaches.

Latin la — canonical

functio salve(textus nomen) → textus {
    fixum textus msg ← "Salve, §!"(nomen)
    redde msg
}

incipit {
    fixum textus m ← salve("munde")
    nota m
}

The canonical rendering. faber format --locale la reproduces the former --canonical re-emit surface. Latin keywords map to themselves; type names are the canonical spellings.

ไทย th-TH — reference proof

ฟังก์ชัน salve(ข้อความ name) → ข้อความ {
    ค่าคงที่ ข้อความ msg ← "Salve, §!"(name)
    คืนค่า msg
}

เริ่มต้น {
    ค่าคงที่ ข้อความ m ← salve("มุนเด")
    แจ้ง m
}

The access-wedge proof. Thai is a spaceless script — no inter-word boundaries — making it the tokeniser stress test and the original architectural driver for the reader-locale system. Every token boundary must be resolved by the lexer through keyword matching alone.

简体中文 zh-Hans

函数 问候(文本 名字) → 文本 {
    常量 文本 问候语 ← "你好,§!"(名字)
    返回 问候语
}

入口 {
    常量 文本 消息 ← 问候("世界")
    显示 消息
}

Paired keywords (如果/否则 for if/secus) requiring pack keyword groups; full/half-width punctuation; NFKC width collapse at lex entry. The hardest LLM emission case due to CJK tokeniser boundaries. A sibling pack for Traditional Chinese (zh-Hant) inherits and overrides zh-Hans roots.

العربية ar

دالة salve(نص name) → نص {
    ثابت نص msg ← "مرحبا، §!"(name)
    أعد msg
}

بداية {
    ثابت نص m ← salve("عالم")
    اعرض m
}

Right-to-left script embedded inside a logical-order LTR code block. Keywords are wrapped in <bdi> (bidirectional isolation) in the compiler's HTML diagnostic output to prevent RFO (right-follows-left) distortion. The raw source uses Arabic script in logical order; the display layer handles bidi presentation.

हिन्दी hi

फलन salve(पाठ name) → पाठ {
    स्थिर पाठ msg ← "Salve, §!"(name)
    लौटा msg
}

आरंभ {
    स्थिर पाठ m ← salve("जगत")
    दिखा m
}

Devanagari script with matra/virama consonant clusters. Proves the path for the wider Indic family — Bengali, Tamil, Telugu inherit the same shaping infrastructure — though pack authoring for each remains separate work. Indic numeral glyphs (०-९) are not accepted in numeric literals; ASCII digits are preserved across all locales.

Tiếng Việt vi

hàm chào(vănbản tên) → vănbản {
    hằng vănbản lời_chào ← "Xin chào, §!"(tên)
    trả lời_chào
}

bắtđầu {
    hằng vănbản thông_điệp ← chào("thế giới")
    in thông_điệp
}

The control case: Latin-script but not English. Heavy diacritic load (ế, ệ, ả) stresses NFKC edge cases in the lexer. Prevents an architecture that works on exotic scripts but is unproven on Latin-with-diacritics. Identifiers use Vietnamese words (chào, tên, lời_chào, thông_điệp), preserved byte-for-byte by the compiler.

The glyphs (← → ∴ ≡ ∪ ⇥), structural positions, and identifier names are identical across all six renderings above. Only the keywords and type names change. The HIR is exactly the same program — the compiler treats all six as equivalent. Rendering Faber to Thai is the same compiler operation as rendering it to Rust: HIR → surface, with neither privileged.

Localised diagnostics#

Diagnostics are structured facts before prose. Each diagnostic carries a stable code (LEX###, LOCALE###, PARSE###, SEM###, WARN###) and named arguments; the pack owns the rendered template text. This means the diagnostic renderer can emit messages in any locale without changing the diagnostic infrastructure.

The reader-locale example packages include diagnostic test cases — type mismatches, undefined variables, non-ASCII numbers — proving the full pipeline is locale-aware:

  • examples/reader-locale/vi/src/type-mismatch.fab
  • examples/reader-locale/vi/src/undefined-variable.fab
  • examples/reader-locale/vi/src/non-ascii-number.fab
  • examples/reader-locale/vi/src/keyword-suggestion.fab
  • examples/reader-locale/vi/src/keyword-edit-distance.fab

Bidi isolation is built in: Arabic keywords inside logical-order LTR code blocks are wrapped in <bdi> elements in HTML output, preventing the RFO (right-follows-left) distortion that would otherwise make RTL runs unreadable.

Status#

LayerStatus
Pack schema, aliases, inheritance, validation, diagnostics, LLM artifactsShipped
Pack-aware lexing, type resolution, manifest/CLI selection, visible fallbackShipped
Pack-owned diagnostic rendering, faber explain, bidi-isolated displayShipped
Canonical Faber formattingShipped
Localised Faber re-emission (format --locale <locale>)Shipped
Stdlib gloss overlays, measured LLM emission fidelity, complete locale coverageDeferred
Multilingual documentation generationProposed

The substrate prerequisite — NFKC normalisation at lex entry — has landed. Keyword tables, diagnostic named-args, the renderer, and pack delivery are shipped. The north-star layers (localised re-emission, stdlib glosses, LLM emission benchmarks, generated multilingual docs) remain explicitly partial or deferred.

References#

  1. radix/docs/design/reader-locale.md — full design document (69 KB)
  2. examples/reader-locale/ — 6 locale packages with localised source
  3. locale/*/pack.toml — 8 installed pack definitions
  4. radix/crates/radix/src/locale.rs — runtime implementation
  5. radix/docs/design/faber-canonical-surface.md — canonical mode and faber format
  6. radix/docs/factory/lex-nfkc-normalization/ — NFKC prerequisite delivery

Reader-locale packages#

Each non-Latin reader locale has a complete Faber package under examples/reader-locale/ with localised source, diagnostic test cases, and a faber.toml manifest.

Available packages#

LocalePathSource example
th-THexamples/reader-locale/th-TH/ฟังก์ชัน salve(ข้อความ name) → ข้อความ
zh-Hansexamples/reader-locale/zh-Hans/函数 问候(文本 名字) → 文本
zh-Hantexamples/reader-locale/zh-Hant/函式 問候(文字 名字) → 文字
arexamples/reader-locale/ar/دالة تحية(نص اسم) → نص
hiexamples/reader-locale/hi/फलन नमस्कार(पाठ नाम) → पाठ
viexamples/reader-locale/vi/hàm chào(vănbản tên) → vănbản

Diagnostic test cases#

Each package includes test cases proving the full compiler pipeline is locale-aware:

  • type-mismatch.fab — localised type error diagnostics
  • undefined-variable.fab — localised name resolution errors
  • non-ascii-number.fab — NFKC handling
  • keyword-suggestion.fab — localised "did you mean?" hints