Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 26 additions & 28 deletions config/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,26 @@ export const countryLocaleVariants: Record<string, (LocaleObjectData & { country
],*/
}

function createPluralRule(locale: string, mapping: Record<string, number>) {
return (choice: number, choicesLength: number) => {
const name = new Intl.PluralRules(locale).select(choice)
const plural = mapping[name] || 0

// In case translation doesn't have all plural forms, use the last available form
if (plural > choicesLength - 1) {
if (import.meta.dev) {
// oxlint-disable-next-line no-console -- warn logging
console.warn(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add // oxlint-disable-next-line no-console -- warn logging

`Plural form index ${plural} for choice ${choice} exceeds available forms ${choicesLength} for locale ${locale}.`,
)
}
return choicesLength - 1
}

return plural
}
}

const locales: (LocaleObjectData | (Omit<LocaleObjectData, 'code'> & { code: string }))[] = [
{
code: 'en',
Expand All @@ -89,10 +109,7 @@ const locales: (LocaleObjectData | (Omit<LocaleObjectData, 'code'> & { code: str
file: 'ar.json',
name: 'العربية',
dir: 'rtl',
pluralRule: (choice: number) => {
const name = new Intl.PluralRules('ar-EG').select(choice)
return { zero: 0, one: 1, two: 2, few: 3, many: 4, other: 5 }[name]
},
pluralRule: createPluralRule('ar-EG', { zero: 0, one: 1, two: 2, few: 3, many: 4, other: 5 }),
},
{
code: 'az-AZ',
Expand Down Expand Up @@ -148,10 +165,7 @@ const locales: (LocaleObjectData | (Omit<LocaleObjectData, 'code'> & { code: str
code: 'hu-HU',
file: 'hu-HU.json',
name: 'Magyar',
pluralRule: (choice: number) => {
const name = new Intl.PluralRules('hu-HU').select(choice)
return { zero: 0, one: 0, two: 1, few: 1, many: 1, other: 1 }[name]
},
pluralRule: createPluralRule('hu-HU', { zero: 0, one: 0, two: 1, few: 1, many: 1, other: 1 }),
},
{
code: 'zh-CN',
Expand Down Expand Up @@ -197,21 +211,13 @@ const locales: (LocaleObjectData | (Omit<LocaleObjectData, 'code'> & { code: str
code: 'ru-RU',
file: 'ru-RU.json',
name: 'Русский',
pluralRule: (choice: number) => {
const name = new Intl.PluralRules('ru-RU').select(choice)
return { zero: 2, one: 0, two: 1, few: 1, many: 2, other: 3 }[name]
},
pluralRule: createPluralRule('ru-RU', { zero: 2, one: 0, two: 1, few: 1, many: 2, other: 3 }),
},
{
code: 'uk-UA',
file: 'uk-UA.json',
name: 'Українська',
pluralRule: (choice: number) => {
if (choice === 0) return 0

const name = new Intl.PluralRules('uk-UA').select(choice)
return { zero: 0, one: 1, two: 0, few: 2, many: 3, other: 4 }[name]
},
pluralRule: createPluralRule('uk-UA', { zero: 0, one: 1, two: 0, few: 2, many: 3, other: 4 }),
},
/*{
code: 'ru-RU',
Expand All @@ -226,10 +232,7 @@ const locales: (LocaleObjectData | (Omit<LocaleObjectData, 'code'> & { code: str
code: 'cs-CZ',
file: 'cs-CZ.json',
name: 'Čeština',
pluralRule: (choice: number) => {
const name = new Intl.PluralRules('cs-CZ').select(choice)
return { zero: 2, one: 0, two: 1, few: 1, many: 2, other: 2 }[name]
},
pluralRule: createPluralRule('cs-CZ', { zero: 2, one: 0, two: 1, few: 1, many: 2, other: 2 }),
} /*
{
code: 'pl-PL',
Expand Down Expand Up @@ -287,12 +290,7 @@ const locales: (LocaleObjectData | (Omit<LocaleObjectData, 'code'> & { code: str
code: 'pl-PL',
file: 'pl-PL.json',
name: 'Polski',
pluralRule: (choice: number) => {
if (choice === 0) return 0

const name = new Intl.PluralRules('pl-PL').select(choice)
return { zero: 0, one: 1, two: 0, few: 2, many: 3, other: 4 }[name]
},
pluralRule: createPluralRule('pl-PL', { zero: 0, one: 1, two: 0, few: 2, many: 3, other: 4 }),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd /dev/shm/repo && find . -name "i18n.ts" -o -name "config" -type d | head -20

Repository: npmx-dev/npmx.dev

Length of output: 124


🏁 Script executed:

cd /dev/shm/repo && fd -t f "i18n" | head -20

Repository: npmx-dev/npmx.dev

Length of output: 124


🏁 Script executed:

cd /dev/shm/repo && cat -n config/i18n.ts | head -30

Repository: npmx-dev/npmx.dev

Length of output: 124


🏁 Script executed:

git ls-files | head -30

Repository: npmx-dev/npmx.dev

Length of output: 667


🏁 Script executed:

fd -t f "i18n.ts"

Repository: npmx-dev/npmx.dev

Length of output: 75


🏁 Script executed:

cat -n config/i18n.ts | sed -n '230,310p'

Repository: npmx-dev/npmx.dev

Length of output: 2197


🏁 Script executed:

cat -n config/i18n.ts | sed -n '1,100p'

Repository: npmx-dev/npmx.dev

Length of output: 4818


🏁 Script executed:

grep -n "createPluralRule" config/i18n.ts | head -20

Repository: npmx-dev/npmx.dev

Length of output: 758


🏁 Script executed:

node -e "console.log(new Intl.PluralRules('pl-PL').select(0))"

Repository: npmx-dev/npmx.dev

Length of output: 65


🏁 Script executed:

node -e "
const rule = new Intl.PluralRules('pl-PL');
console.log('choice 0:', rule.select(0));
console.log('choice 1:', rule.select(1));
console.log('choice 5:', rule.select(5));
console.log('choice 22:', rule.select(22));
"

Repository: npmx-dev/npmx.dev

Length of output: 119


Restore explicit zero handling for Polish locale or update plural form mapping.

The new implementation using createPluralRule introduces a behavioural regression. Intl.PluralRules('pl-PL').select(0) returns "many" (not "zero"), which maps to form index 3, whereas the previous implementation explicitly returned form index 0 for choice === 0. This changes how "0 items" is displayed in Polish.

Additionally, the zero: 0 key in the mapping is unreachable dead code—Intl.PluralRules('pl-PL') never returns a "zero" category for the Polish locale.

Either restore the explicit zero handling (as in the commented-out lines 241–247) within createPluralRule, or confirm this is intentional and update the mapping accordingly.

},
{
code: 'pt-BR',
Expand Down
Loading