mirror of
https://github.com/TautvydasDerzinskas/Thingport.git
synced 2026-10-21 14:12:25 -05:00
fix(i18n): count plural forms only large round numbers use
This commit is contained in:
1 parent
96300510b4
commit
993c75c828
3 files changed
+25
-7
No files matched your search
@@ -1,6 +1,7 @@
|
||||
// Lists each locale's keys missing from, or no longer in, en.json: `npm run i18n:check [code]`.
|
||||
// A plural key (key_one, key_other, ...) needs every form the locale uses for whole-number counts.
|
||||
import { readdirSync, readFileSync } from "node:fs";
|
||||
import { pluralForms } from "./plural-forms.mjs";
|
||||
|
||||
const dir = new URL("../src/i18n/locales/", import.meta.url);
|
||||
const PLURAL = /_(zero|one|two|few|many|other)$/;
|
||||
@@ -13,12 +14,6 @@ function keys(node, prefix = "") {
|
||||
|
||||
const read = (code) => keys(JSON.parse(readFileSync(new URL(`${code}.json`, dir), "utf8")));
|
||||
|
||||
// Fractional-only forms (Lithuanian `many`) are left out: counts here are whole numbers.
|
||||
function pluralForms(code) {
|
||||
const rules = new Intl.PluralRules(code);
|
||||
return new Set(Array.from({ length: 1000 }, (_, n) => rules.select(n)));
|
||||
}
|
||||
|
||||
const plurals = new Set();
|
||||
const plain = [];
|
||||
for (const key of read("en")) {
|
||||
@@ -40,7 +35,7 @@ if (only && codes.length === 0) {
|
||||
for (const code of codes) {
|
||||
const forms = [...pluralForms(code)];
|
||||
const en = new Set([...plain, ...[...plurals].flatMap((base) => forms.map((form) => `${base}_${form}`))]);
|
||||
// Extra plural forms a translator added (such as `_many`) aren't stale, just unused for whole numbers.
|
||||
// Extra plural forms a translator added (Lithuanian `_many`) aren't stale, just unused by this locale's whole numbers.
|
||||
const locale = new Set(read(code).filter((key) => en.has(key) || !plurals.has(key.replace(PLURAL, ""))));
|
||||
const missing = [...en].filter((key) => !locale.has(key));
|
||||
const stale = [...locale].filter((key) => !en.has(key));
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// The plural forms a locale uses for whole-number counts: 0-999 plus powers of ten, so forms only large
|
||||
// round numbers take (French and Spanish `many` for 1,000,000) count too. Fractional-only forms (Lithuanian
|
||||
// `many`) are left out.
|
||||
const SAMPLES = [...Array.from({ length: 1000 }, (_, n) => n), ...Array.from({ length: 10 }, (_, k) => 10 ** (k + 3))];
|
||||
|
||||
export function pluralForms(code) {
|
||||
const rules = new Intl.PluralRules(code);
|
||||
return new Set(SAMPLES.map((n) => rules.select(n)));
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { pluralForms } from "./plural-forms.mjs";
|
||||
|
||||
describe("pluralForms", () => {
|
||||
it("includes forms only large round counts use", () => {
|
||||
expect([...pluralForms("fr")].toSorted()).toEqual(["many", "one", "other"]);
|
||||
expect([...pluralForms("es")].toSorted()).toEqual(["many", "one", "other"]);
|
||||
});
|
||||
|
||||
it("leaves out fractional-only forms", () => {
|
||||
expect([...pluralForms("lt")].toSorted()).toEqual(["few", "one", "other"]);
|
||||
expect([...pluralForms("en")].toSorted()).toEqual(["one", "other"]);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user