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:
| language | categories |
|---|---|
| English, Swedish, German, Danish, Norwegian, Finnish, Dutch | one, other |
| French, Spanish, Italian, Portuguese | one, many, other (many: a whole million and up) |
| Polish | one, few, many, other |
| Arabic | zero, one, two, few, many, other |
| Japanese, Chinese, Korean | other |
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#
- A language's words — locales/<language>.osy — the file the forms are written in
- Which words are translated — the compiler finds every text a reader sees — what makes a hole a count