intlify / vue-i18n

Vue I18n for Vue 3
https://vue-i18n.intlify.dev/
MIT License
2.21k stars 337 forks source link

Add Pluralization rules based on Intl.PluralRules #2020

Open ssendev opened 1 week ago

ssendev commented 1 week ago

Clear and concise description of the problem

The default pluralization rules are pretty simple and Intl.PluralRules has 97% browsersupport so it would be nice to have an implementation based on it with fallback to the current simple one. Which maybe needs revising since it can currently return a number greater than choicesLength - 1 that then crashes vue

Suggested solution

Here is an implementation that works with the current api but the implementation could be cleaner without the Proxy

const pluralOrder: Intl.LDMLPluralRule[] = [
  'zero',
  'one',
  'two',
  'few',
  'many',
  'other',
]

function pluralSort(a: Intl.LDMLPluralRule, b: Intl.LDMLPluralRule) {
  return pluralOrder.indexOf(a) - pluralOrder.indexOf(b)
}

const pluralRules = new Proxy(
  {} as {
    [lang: string]:
      | ((choice: number, choicesLength: number) => number)
      | undefined
  },
  {
    get: (target, prop: string) => {
      if (prop in target) return target[prop]

      try {
        const rules = new Intl.PluralRules(prop)
        const categories = rules
          .resolvedOptions()
          .pluralCategories.sort(pluralSort)

        return (target[prop] = (choice: number, choicesLength: number) => {
          const rule = rules.select(choice)
          const n = categories.indexOf(rule)

          return Math.min(n, choicesLength - 1)
        })
      } catch (e) {
        target[prop] = undefined
      }
    },
  },
)

Alternative

If shipping it by default is considered too large it could live in an extra import so that it's easy to use

import pluralRules from '@intlify/plural'

The implementation could also be cleaner if instead of an object pluralRules could be a function that receives the locale maybe it would be a factory so that it only gets called once per locale

Additional context

No response

Validations