Osy#betaRun it on Osyrin: osyrin.com

Reference / I18n

A count's plural forms — one text per CLDR category

text "{n} items" => { one: "{n} vara", other: "{n} varor" };

A message with a whole-number hole (`$"{n} items"`) may take one text per plural category of its language — CLDR's `zero`, `one`, `two`, `few`, `many`, `other` — and the number chooses. The compile requires every category the language has and no other; a translation that does not change with the count may stay one text. A form that stands for exactly one number may say it in words ("منتج واحد") and leave the count out.

stable3 examples compiled by CIi18npluraltranslation

Summary#

The first whole-number hole of a message is its count. Its translation is either one text (the same for every count) or an object with one text per category the language has:

languagecategories
English, Swedish, German, Danish, Norwegian, Finnish, Dutchone, other
French, Spanish, Italian, Portugueseone, many, other (many: a whole million and up)
Polishone, few, many, other
Arabiczero, one, two, few, many, other
Japanese, Chinese, Koreanother

Signature#

text "{count} items in your bag" => { one: "{count} vara i din kasse", other: "{count} varor i din kasse" };

Description#

The rules are CLDR's, for whole numbers, and the same table runs in the browser and on the server. Polish, for example: 1 is one; 2–4, 22–24, 32–34 … are few; 0, 5–21, 25–31 … are many. Every form must still use exactly the source's placeholders — with one exception.

A form for exactly one number may say it in words. Arabic does not write "1 منتج" or "2 منتج": it says "منتج واحد" (one product) and "منتجان" (two products, the dual), and the number is in the word. So a form whose category covers exactly one count — Arabic zero (0), one (1) and two (2), English or Swedish one (1), Polish one (1) — may leave the count out. Every other placeholder is still required, and so is the count in every other form: Arabic few is 3–10, 103–110 …, and French one is both 0 and 1, so a form like that without the count would read the same for different numbers. The refusal names the forms that may drop it.

English source text often cannot say 1 item and 2 items with one sentence; add an en locale file to give the source language its own forms — it is a translation like any other.

A number written against a mark or a letter is a label, not a count. $"Merged into #{number}." names ticket 1042, and $"Escalated to L{level}." names a level: neither is "how many", so neither chooses a plural form, and its translation is ONE text. A count stands on its own — {n} items, ({n}) — and a count later in the same message still chooses: in $"#{number} has {count} replies" it is count.

Examples#

[Route("/")]
[AllowAnonymous]
component Basket() {
  int count = 1;
  render { Text($"{count} bottles chilled"); }
}

translations sv {
  text "{count} bottles chilled" => { one: "{count} flaska kyld", other: "{count} flaskor kylda" };
}
[Route("/")]
[AllowAnonymous]
component Basket() {
  int count = 2;
  render { Text($"{count} bottles chilled"); }
}

translations ar {
  text "{count} bottles chilled" => { zero: "لا زجاجات مبرّدة", one: "زجاجة واحدة مبرّدة", two: "زجاجتان مبرّدتان",
    few: "{count} زجاجات مبرّدة", many: "{count} زجاجة مبرّدة", other: "{count} زجاجة مبرّدة" };
}
[Route("/")]
[AllowAnonymous]
component Ticket() {
  int number = 1042;
  int count = 3;
  render {
    Stack {
      Text($"Merged into #{number}.");
      Text($"#{number} has {count} replies");
    }
  }
}

translations sv {
  text "Merged into #{number}." => "Sammanslaget med #{number}.";
  text "#{number} has {count} replies" => { one: "#{number} har ett svar", other: "#{number} har {count} svar" };
}

See also#

Related

A language's words — locales/<language>.osy

A project's translations are checked-in source: one `locales/<language>.osy` per language, a `translations sv { }`…

Which words are translated — the compiler finds every text a reader sees

You write your app's words where they belong, in ordinary strings. The compiler finds every one a reader can see — by…