Vue-i18n: [Feature request] - Override of the getChoiceIndex function should be available via options object on initialization

Created on 15 Nov 2018  路  13Comments  路  Source: kazupon/vue-i18n

I use vue-i18n via another lib nuxt-i18n so I doesn't have direct access to the library to override getChoiceIndex method in a clean way as it described in the documentation and my personal opinion is that it looks dirty to to this at all. Instead, what I like is to be able to do override this method via default vue-i18n config object. The syntax is pretty simple:

new VueI18n({
  locale: 'pl', // set locale
  getChoiceIndex(choice, choicesLength) {
     // Custom pluralization code goes here
  }
})

so when using nuxt-i18n module I can simply do:

modules: [ ['nuxt-i18n', {
locales: [...], 
vueI18n: {
   getChoiceIndex(choice, choicesLength) {
     // Custom pluralization code goes here
  }
}
}]]

I think such approach is much more cleaner to use!

good first issue

Most helpful comment

Ok so upon some further digging, the problem is not in vue-i18n but rather in nuxt-i18n. As you can see here, nuxt-i18n takes the vueI18n options and stringifies them using JSON.stringify. That causes the functions to be removed and just returns an object pluralizationRules: {}.

So here's a nice workaround. Instead of adding pluralizationRules within vueI18n options, you can add a plugin:

export default ({ app }) => {
  app.i18n.pluralizationRules = {
    sl: slovenePluralization
  };
}

function slovenePluralization(number, choicesLength) {
  let option = null;

  if (number === 0) {
    option = 3;
  }

  if (number % 100 === 1) {
    option = 0;
  }

  if (number % 100 === 2) {
    option = 1;
  }

  if (number % 100 === 3 || number % 100 === 4) {
    option = 2;
  }

  if (option === null) {
    option = 3;
  }

  return option > choicesLength ? choicesLength : option;
}

and then you just have to register the plugin with ssr: true:

// nuxt.config.js

module.exports = {
  ...
  plugins: [
    { src: '~plugins/pluralization.js', ssr: true }
    ],
  ...
};

That way it works for SSR as well :)

Hope that helps. cc @fibigerg @AndrewBogdanovTSS

All 13 comments

@AndrewBogdanovTSS, sorry it took so long... but there it is! 馃槃

For now you can install it with

npm install --save raiondesu/vue-i18n#master

@Raiondesu is there any ETA on when this will be released in a stable version?

@AndrewBogdanovTSS, see changelog and v8.7.0

@Raiondesu I still see this page showcases outdated documentation. I believe it should show an example of using pluralizationRules option, right?

@Raiondesu I tried to pass pluralizationRules option like so:

pluralizationRules: {
      pl: n => n < 2 ? n : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 2 : 3
    }

but looks like this function is not being called at all 馃

Hmm... 馃

I tried out the latest build - pluralization seems to work fine for me... What a mystery.

Still, you are perfectly right documentation-wise. @kazupon, how do we update the docs on on the website?

Hi, not working for me either with nuxt, vue-i18n on v8.8.2. Am I missing somehting? Thanks @Raiondesu

[
  'nuxt-i18n',
  {
    locales: [{ code: 'en', iso: 'en-US', file: 'en.js' }, { code: 'cs', iso: 'cs-CZ', file: 'cs.js' }],
    strategy: 'prefix_except_default',
    defaultLocale: 'cs',
    langDir: 'lang/',
    vueI18nLoader: true,
    lazy: true,
    vueI18n: {
      pluralizationRules: {
        cs: function(choice, choicesLength) {
          return 0
        },
      },
    },
  },
],

Hi, I also seem to be facing the same problem as fibigerg (and have pretty much the same config as he does). The custom pluralization rules function isn't being called. The English default one is being used instead. Also on nuxt and vue-i18n v8.8.2.

Any chance you could take a look at what might be the reason @Raiondesu ?

Ok so upon some further digging, the problem is not in vue-i18n but rather in nuxt-i18n. As you can see here, nuxt-i18n takes the vueI18n options and stringifies them using JSON.stringify. That causes the functions to be removed and just returns an object pluralizationRules: {}.

So here's a nice workaround. Instead of adding pluralizationRules within vueI18n options, you can add a plugin:

export default ({ app }) => {
  app.i18n.pluralizationRules = {
    sl: slovenePluralization
  };
}

function slovenePluralization(number, choicesLength) {
  let option = null;

  if (number === 0) {
    option = 3;
  }

  if (number % 100 === 1) {
    option = 0;
  }

  if (number % 100 === 2) {
    option = 1;
  }

  if (number % 100 === 3 || number % 100 === 4) {
    option = 2;
  }

  if (option === null) {
    option = 3;
  }

  return option > choicesLength ? choicesLength : option;
}

and then you just have to register the plugin with ssr: true:

// nuxt.config.js

module.exports = {
  ...
  plugins: [
    { src: '~plugins/pluralization.js', ssr: true }
    ],
  ...
};

That way it works for SSR as well :)

Hope that helps. cc @fibigerg @AndrewBogdanovTSS

Thanks for a workaround @lukaVarga. But maybe it's a good point for improvement for nuxt-i18n library itself? Maybe it will logical to log a bug/improvement in their repo, what do you think?

@AndrewBogdanovTSS can't hurt, I just didn't have time to log it there yesterday. I'll open up an issue 馃憤

Thanks @lukaVarga, the workaround works. It is nice to have it separately in plugin, too.

No need to override VueI18n.prototype.getChoiceIndex. Update nuxt and vue-i18n to latest version, and use pluralizationRules option.

$ npm i --save [email protected]
$ npm i --save [email protected]

plugins/i18n.js

import Vue from 'vue'
import VueI18n from 'vue-i18n'

Vue.use(VueI18n)

function slavicPluralization (choice, choicesLength) {
  if (choice === 0) {
    return 0
  }

  const teen = choice > 10 && choice < 20
  const endsWithOne = choice % 10 === 1

  if (!teen && endsWithOne) {
    return 1
  }

  if (!teen && choice % 10 >= 2 && choice % 10 <= 4) {
    return 2
  }

  return (choicesLength < 4) ? 2 : 3
}

export default ({ app, store }) => {
  app.i18n = new VueI18n({
    locale: store.state.locale,
    fallbackLocale: 'en',
    messages: {
      'en': require('~/locales/en.json'),
      'ru': require('~/locales/ru.json')
    },
    pluralizationRules: {
      ru: slavicPluralization
    }
  })
}

nuxt.config.js

plugins: [
  '~/plugins/i18n.js'
]
Was this page helpful?
0 / 5 - 0 ratings