Skip to main content

add-rbnf

Use when adding or expanding RBNF (Rule Based Number Format) rules for a CLDR language, so numbers can be spelled out as words (e.g. 42 -> "forty-two").

Source facts

Repository
unicode-org/cldr
Last source activity
July 15, 2026 at 20:02
Detected SKILL.md language
English
Stars
1,150
Forks
443

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
add-rbnf
description
Use when adding or expanding RBNF (Rule Based Number Format) rules for a CLDR language, so numbers can be spelled out as words (e.g. 42 -> "forty-two").
# Add RBNF Rules You are adding or expanding Rule Based Number Format (RBNF) rules for a language in the CLDR repository. RBNF rules turn the binary form of a number into words (e.g. 42 → "forty-two"). The user will specify a BCP 47 language tag (e.g. `sw`, `de_CH`, `sr_Latn`) — either in their request or, if not given, ask which language to work on. ## Prerequisites This skill assumes a usable CLDR build environment: Maven, Java JDK, and a built `tools/cldr-code/target/cldr-code.jar` (the Phase 3 validation steps run this jar and `mvn test`). If the jar hasn't been built yet, run `mvn -B package -DskipTests --file tools/pom.xml -pl cldr-code` (or an equivalent build) before starting Phase 3. ## Phase 1 — Language Analysis 1. Parse the language code from the user's request. If none was provided, ask the user which language to work on. 2. Check if `common/rbnf/<lang>.xml` already exists. - If it exists, read it. You are **expanding** existing rules — do not modify working rulesets, only add missing ones. - If it does not exist, you are creating rules for a **new language**. 3. Identify the language's grammatical properties relevant to number formatting using your linguistic knowledge: - Grammatical genders (e.g. masculine, feminine, neuter) — do numbers inflect for gender? - Grammatical cases (e.g. nominative, genitive, dative, accusative) — do numbers inflect for case? - Number word irregularities (e.g. French 70 = soixante-dix, German compound ordering with units before tens) - Plural categories that affect large number words (million, billion, etc.) - The word used for the decimal separator (e.g. "point", "Komma", "virgule") - Whether the language has ordinal concepts that need custom digit-ordinal rules beyond what `root.xml` provides 4. Find the most structurally similar existing RBNF language file to use as a template: - Romance languages → `fr.xml`, `es.xml`, `it.xml` - Slavic languages → `ru.xml`, `sr.xml`, `uk.xml` - Germanic languages → `de.xml`, `nl.xml` - Other families → find the closest match among existing files in `common/rbnf/` - Read the chosen template file to understand the structural pattern. 5. Present your findings to the user: - Which grammatical properties are relevant - Which template language you'll use - Which rulesets you plan to create (list them) - Ask the user to confirm or correct your analysis before proceeding. **Do not proceed to Phase 2 until the user confirms.** ## Phase 2 — Incremental Rule Authoring Build rulesets incrementally in complexity order. After writing each ruleset (or small group of closely related rulesets), run the full validation loop in Phase 3 before adding more. ### Ruleset build order 1. `%spellout-numbering` — basic counting form (typically delegates to a base cardinal ruleset). 2. `%spellout-numbering-year` — year formatting. 3. `%spellout-cardinal-*` — cardinal forms: - Start with the base cardinal (often `%spellout-cardinal-masculine` or `%spellout-cardinal` depending on whether the language has grammatical gender for numbers). - Then add gender variants (feminine, neuter) that delegate to the base for most numbers but differ at key points (typically "1" and sometimes "2"). - Then add case variants (genitive, dative, accusative, etc.) if the language inflects numbers for case. 4. `%spellout-ordinal-*` — ordinal forms, same progression (base, then gender/case variants). 5. `%digits-ordinal-*` — digit-based ordinals (e.g. "1st", "2e") in an `OrdinalRules` grouping — only if the language needs custom rules beyond `root.xml`. 6. Private helper rulesets (`%%` prefix) as needed — add these alongside the public rulesets that use them. ### Rule authoring standards Every public ruleset (`%` prefix) must include these special rules: - `-x:` — negative number handling (e.g. `minus >>` or `moins >>`) - `x.x:` — fractional number handling with the language-appropriate decimal word (e.g. `<< point >>` or `<< Komma >>`) - `Inf:` — infinity handling (e.g. `infinity` or `infini`) — only include if the language has a word for infinity; check the template language for guidance Termination rules: - Cardinal/numbering rulesets: `1000000000000000000: =#,##0=;` - Ordinal spell-out rulesets: `1000000000000000000: =#,##0=.;` (or equivalent digit fallback like `=%%digits-ordinal=`) For large number words (million, billion, trillion, quadrillion), use the plural syntax when the language has plural forms: ``` 1000000: << $(cardinal,one{million}other{millions})$[ >>]; ``` When a rule needs different text for standalone (zero remainder) vs. compound (non-zero remainder), use the bracket-pipe syntax `[ >>|text]` instead of splitting into two rules. The text before `|` is used when the remainder is non-zero; the text after `|` is used when it is zero: ``` // English ordinal: "two hundredth" (standalone) vs "two hundred first" (compound) // <%spellout-numbering< formats the quotient through the cardinal ruleset 100: <%spellout-numbering< hundred[ >>|th]; // Telugu ordinal: "వెయ్యవ" (standalone 1000th) vs "వెయ్యి మొదటి" (1001st) // Common prefix "వెయ్య" gets "ి >>" when compound or "వ" when standalone 1000: వెయ్య[ి >>|వ]; ``` This eliminates the need for separate standalone/combining rule pairs (e.g. `1000: వెయ్యవ;` / `1001: వెయ్యి >>;`). Naming conventions: - Public rulesets: `%spellout-cardinal-<gender>[-<case>]` (e.g. `%spellout-cardinal-masculine-genitive`) - Private helpers: `%%` prefix (e.g. `%%et-un`, `%%spellout-leading`) - Ordinal rulesets: `%spellout-ordinal-<gender>[-<case>]` - Digit ordinals: `%digits-ordinal-<gender>` (in `OrdinalRules` grouping) ### XML file format For a **new language**, create `common/rbnf/<lang>.xml` with this structure: ```xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE ldml SYSTEM "../../common/dtd/ldml.dtd"> <!-- Copyright © <this year>-<this year> Unicode, Inc. CLDR data files are interpreted according to the LDML specification (http://unicode.org/reports/tr35/) For terms of use, see http://www.unicode.org/copyright.html --> <ldml> <identity> <version number="$Revision$"/> <language type="<lang>"/> </identity> <rbnf> <rulesetGrouping type="SpelloutRules"> <rbnfRules><![CDATA[ ... rules go here ... ]]></rbnfRules> </rulesetGrouping> </rbnf> </ldml> ``` For locale variants (e.g. `de_CH`, `fr_BE`), add `<territory>` or `<script>` elements in the identity block as appropriate. Add an `OrdinalRules` grouping only when the language needs custom digit-ordinal rules beyond `root.xml`: ```xml <rulesetGrouping type="OrdinalRules"> <rbnfRules><![CDATA[ ... digit ordinal rules ... ]]></rbnfRules> </rulesetGrouping> ``` For an **existing language**, read the existing `common/rbnf/<lang>.xml` file and add new rulesets inside the existing `<rbnfRules>` CDATA section without modifying rulesets that already work. ## Phase 3 — Validation Run this validation loop after each ruleset (or small group of related rulesets) is added or modified. Track how many times you have attempted validation for the current ruleset — if you exceed 5 attempts, stop and ask the user for guidance. ### Validation steps 1. **Delete the existing .ssv file** (so the generator will create a fresh one): ```bash rm -f common/testData/rbnf/<lang>.ssv ``` 2. **Generate test data** from the current rules: ```bash java -DCLDR_DIR=$(pwd) -Xmx6g -jar tools/cldr-code/target/cldr-code.jar generate-rbnf-ssv ``` 3. **Run the RBNF tests**: ```bash mvn -DHAS_CLDR_ARCHIVE=false -Dtest="TestRBNF" --file tools/pom.xml -pl cldr-code test ``` 4. **Read the generated .ssv file** and review it for linguistic correctness: - Read `common/testData/rbnf/<lang>.ssv` - Spot-check these key numbers: 0, 1, 2, 3, 10, 11, 12, 13, 20, 21, 100, 101, 1000, 1000000 - Verify gender agreement for "1" across all gendered rulesets - Verify correct plural forms for large number words - Check ordinals for 1-10 (often irregular) - Verify the decimal separator word matches the language convention - Verify the negative number prefix matches the language convention 5. **If any issues are found** (test failures OR linguistic errors): - Fix the rules in the XML file - Go back to step 1 and repeat 6. **If everything passes**, proceed to the next ruleset in the Phase 2 build order, or to Phase 4 if all rulesets are complete. ### Error diagnosis | Symptom | Likely cause | Fix | |---|---|---| | `Failed to create RuleBasedNumberFormat` | Malformed RBNF syntax (missing semicolons, bad references) | Read the error message carefully, fix the XML rule syntax | | Test format mismatch (`expected "X" but got "Y"`) | Rules produce wrong output | Compare expected vs actual, fix the rule that handles that number | | Test parse failure (`parse failed for "X"`) | Ambiguous rules — multiple rules could match the same text | Adjust rules to remove ambiguity, ensure number words are unique | | Linguistic error in .ssv review | Wrong number words, wrong gender, wrong plural | Fix the specific rule, often just the word text for a specific number | ## Phase 4 — Final Review Once all rulesets have been written and individually validated: 1. **Run the full validation loop one final time** (Phase 3 steps 1-4) to ensure everything still works together. 2. **Read the complete .ssv file** and review all number words across all rulesets. Pay special attention to consistency between related rulesets (e.g. cardinal masculine vs. cardinal feminine should only differ where gender matters). 3. **Present a summary to the user** of what was created or modified: - List all rulesets added or changed - Note any known limitations or areas where the user should double-check - Show a few example outputs (e.g. how 1, 21, 100, and 1000000 render in each ruleset) 4. **Apply code formatting** if any Java files were touched: ```bash mvn --file=tools/pom.xml spotless:apply ``` 5. The user can then commit the changes. The commit message should follow the format: `CLDR-NNNN Brief description of change` (the user will provide the JIRA ticket number).
View on GitHub