Skip to content

feat(ar-SA): rewrite the counted-noun engine and add a case option - #449

Merged
forzagreen merged 2 commits into
mainfrom
feat/ar-grammar
Sep 11, 2026
Merged

forzagreen merged 2 commits into
mainfrom
feat/ar-grammar

Conversation

@forzagreen

@forzagreen forzagreen commented Sep 11, 2026

Copy link
Copy Markdown
Owner

Summary

Rewrites the Arabic converter around the classical rules of the counted noun (العدد والمعدود) so one engine renders bare cardinals, scale words and currency units. Adds case and hundredSpelling options to every Arabic form, and fills in the remaining Arab-world currencies.

Also carries the fix(deps-dev) commit from #450 so the audit check passes here; it will drop out on rebase once #450 merges.

Grammar fixes (all were producing malformed Arabic)

Input Before After
toCurrency(100) مائة ريالاً مئة ريال
toCurrency(1000) ألف ريالاً ألف ريال
toCurrency(2000) ألفان ريالاً ألفا ريال
toCurrency(11000) أحد عشر ألف ريالاً أحد عشر ألف ريال
toCurrency(101) مائة وواحد ريالاً مئة ريال وريال واحد
toCurrency(0) صفر ريالاً صفر ريال
toCurrency(0.08) ثمان هللات ثماني هللات
toCardinal(200000) مئتان ألف مئتا ألف
toCardinal(101000) مائة وألف ألف مئة ألف وألف
toCardinal(105000) مائة وخمسة ألف مئة وخمسة آلاف
toCardinal(121000) مائة وواحد وعشرون ألف مئة وواحد وعشرون ألفاً
toCardinal(3000, feminine) ثلاث آلاف ثلاثة آلاف
toCardinal(21, feminine) واحدة وعشرون إحدى وعشرون
toOrdinal(11) الأحد عشر الحادي عشر
toOrdinal(21) الواحد وعشرون الحادي والعشرون
toOrdinal(101) المائة وواحد الحادي بعد المئة

The rules now encoded, each in one place:

  • 1 and 2 follow the noun ("ريال واحد", "ريالان"); 3–10 take the opposite gender and a genitive plural; 11–99 take a singular accusative تمييز.
  • 100, 1000 and every larger scale word head a genitive singular (إضافة). A dual head drops its ن ("مئتا ألف", "ألفا ريال"), and a تمييز scale word sheds its tanwīn when it heads the currency ("أحد عشر ألف ريال").
  • A compound ending in 1 or 2 repeats the noun, as in "ألف ليلة وليلة".
  • Ordinals past 99 use the classical بعد construction that numbers the nights of ألف ليلة وليلة: "الحادي والعشرون بعد المئة", "الحادي بعد الألفين".

New options (cardinal, ordinal and currency)

  • case: nominative (مرفوع, default) | accusative (منصوب) | genitive (مجرور). The oblique cases put ـين on duals and tens ("اثنين وعشرين", "ألفين", "ريالين", "الحادي والعشرين"), which is what an amount needs after مبلغ or a preposition. Accusative and genitive coincide in unvocalised text except for the defective feminine 8 (ثمانيَ vs ثمانٍ).
  • hundredSpelling: 'مئة' (default, the academies' standard) | 'مائة' (the traditional orthography, still printed on banknotes). 200–900 follow it: مئتان / مائتان, ثلاثمئة / ثلاثمائة.

Currency matrix

toCurrency now reads majorGender from the matrix instead of assuming masculine, and the matrix gains AED, DZD, EGP, LBP, QAR, SDG, SYP and YER. The Lebanese and Syrian ليرة is the first feminine major unit, which exercises every agreement rule from the other side ("ثلاث ليرات", "إحدى عشرة ليرة", "ألف ليرة وليرة واحدة").

Test plan

  • npm test (845 tests) and npm run lint pass
  • Fixtures rewritten with ~350 cases covering every rule above, both genders, all three cases, both spellings, and each new currency
  • LANGUAGES.md regenerated; CLI picks up --case and --hundred-spelling automatically
  • Range, options, bare-tag and currency-vocab contract gates pass unchanged

🤖 Generated with Claude Code

forzagreen and others added 2 commits September 11, 2026 11:23
Rebuild the Arabic converter around the classical rules of العدد والمعدود,
one engine for bare cardinals, scale words and currency units:

- 100/1000/million head a genitive singular: "مائة ريال", "ألف ريال",
  never "مائة ريالاً"; a dual head drops its ن: "مئتا ألف", "ألفا ريال"
- 11-99 keep the tamyīz tanwīn only when nothing follows: "أحد عشر ألفاً"
  but "أحد عشر ألف ريال"
- a trailing 1 or 2 repeats the noun: "مائة ريال وريال واحد",
  "مائة ألف وألفان" — previously "مائة وألف ألف" and "مائة واثنان ألف"
- scale words are masculine nouns, so 3000 is "ثلاثة آلاف" whatever the
  gender option; feminine 8 is "ثماني" as a construct head and "إحدى"
  stands in compounds ("إحدى وعشرون")
- ordinals get their dedicated forms: "الحادي عشر", "الحادي والعشرون",
  and "الحادي بعد المائة" past 99 instead of a bare "ال" on the cardinal
- new `case` option (nominative | accusative | genitive) on every form:
  "اثنين وعشرين", "ألفين", "ريالين", "الحادي والعشرين"
- currency reads majorGender from the matrix, and the matrix gains the
  rest of the Arab-world set: AED, DZD, EGP, LBP, QAR, SDG, SYP, YER

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
مئة is the spelling the Arabic language academies standardise on; the
traditional مائة (still printed on banknotes) stays available through
`hundredSpelling: 'مائة'`, which 200–900 follow (مائتان, ثلاثمائة). The
case option's description now names each case in Arabic (مرفوع, منصوب,
مجرور) next to the Latin term.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@forzagreen
forzagreen merged commit b0107e9 into main Sep 11, 2026
6 checks passed
@forzagreen
forzagreen deleted the feat/ar-grammar branch September 11, 2026 09:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant