intlify / vue-i18n

Vue I18n for Vue 3

Home Page:https://vue-i18n.intlify.dev/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Pluralized message interpolation with numeric values

adrianrudnik opened this issue · comments

Clear and concise description of the problem

I'm currently unable to come up with a simple solution to:

{ "en": { "message": { "hits": "No hits | One hit | {count} hits" } } }
{{ t('hits', { count: n(hit) }) }}

Example: https://stackblitz.com/edit/vitejs-vite-quzfyg?file=src%2FApp.vue

I did:

  • Looked through the docs for interpolation, no example found, no modifier available.
  • Looked throught he docs for number formatting, not example or mention found.
  • Looked through the custom message format, which touches the topic, but would still fail from my understanding.
  • Looked again at pluralization, but from my understanding $tc is not available in composition and was merged with t, which does not do the same, no mention in the changelog through, only that it was available in v8?

Suggested solution

Not sure how to approach it.

I thought about just writing a custom modifier, but that would require me to either have n() or the current locale available in the createI18n({ ..., modifiers: {]) block, so also not doable, as this is prior setup of the module.

Maybe have a built in modifier? Maybe n() returns a proxy that t() could react on, to see if it needs to run a modifier itself?

Alternative

No response

Additional context

No response

Validations

After some more work on different parts, the current workaround I'm using is the very verbose i18n-t translation component to inject the "manual" formatting there. As for the given example, here is how the workaround would look like

  <ul>
    <i18n-t
      keypath="hits"
      tag="li"
      :plural="hit"
      v-for="hit of hits"
      :key="hit"
    >
      <template v-slot:count>{{ n(hit) }}</template>
    </i18n-t>
  </ul>

Not sure if this is the "wanted" way to wrap n() into this, but it works for now. Not sure if this can be closed, should be documented, or might be easier to implement with a modifier or some other solution.

During the migration from v8 to v9, I encountered an issue where pluralization doesn't work correctly if the localized string contains the 'count' or 'n' interpolation keys.

From what I've found, this problem stems from the getPluralIndex method of the @intlify/core-base module. It ignores a passed pluralization form parameter if the option.named.count or option.named.n contains a numeric value:

function getPluralIndex(options) {
// prettier-ignore
const index = isNumber(options.pluralIndex)
    ? options.pluralIndex
    : -1;
// prettier-ignore
return options.named && (isNumber(options.named.count) || isNumber(options.named.n))
    ? isNumber(options.named.count)
        ? options.named.count
        : isNumber(options.named.n)
            ? options.named.n
            : index
    : index;
}

@adrianrudnik You can use the following approach instead of i18n-t component:

https://stackblitz.com/edit/vitejs-vite-uqwnwb?file=src%2FApp.vue,src%2Flocales%2Fen.json

@kazupon, You can use the link above to reproduce the problem I described. I'm not sure if this is a bug. After all, we can simply not use the 'count' and 'n' keys, but this behavior seems very unusual and strange. Also, I could not find any documentation regarding this.