vue-i18n
vue-i18n copied to clipboard
tc decimal handling
vue & vue-i18n version vue 2.6.8 vue-i18n 8.11.2
Steps to reproduce
{{ $tc('daysCounter', days, {count: days}) }}
i18n: {
messages: {
daysCounter: ' 0 jour | {count} jour | {count} jours'
}
}
What is Expected? if days is 0.5 or 1.5 the singular option should be selected and output '0.5 jour' or '1.5 jour'
What is the result? vue-i18n displays '0 jours | 0.5 jour | 0.5 jours'
This is because $tc
's second argument is supposed to be a index to choose message from case of 0 | 1 | 2 and more
, so it must be int
right now.
I think you may get expcted result if you round
or ceil
before passing days
to $tc
I made an example of that: http://jsfiddle.net/5mxgauwf/1/
I think $tc
should warn if it received a non-int value (float, string, array or whatever).
Warning like $tc's second argument should be int but ... given. If you want to pass non-int number to the chosen message, consider $tc(messageKey, round(f), {count: f})
so that we can avoid confusing like this situation.
I think we can add int
-ness check and warning around inside the below
https://github.com/kazupon/vue-i18n/blob/6ffc60190d4d7910964186fd3904b77fd422a399/src/index.js#L517-L525
I have same issue about decimals and I think it could be a good idea to let this situation documented.
Same issue here.
Same issue here too.
Keep in mind that pluralization rules are vastly different in different languages. Since I'm not fluent in French, I don't know the rules here, but I can safely say that e.g. both English and German treat 1.5 as a plural form (=> "1.5 days" / "1,5 Tage"), not singular.
There's nothing preventing you from defining your own plural rule and I think this would be the safest way to handle the problem described here – not artificially limiting counts to integers.
in french, plural is when number >= 2 so 0.5 and 1.5 are singular, 2.5 is plural
you could take inspiration on rails :
👋 I just faced this issue and found a clean solution by applying this logic on pluralizationRules
when creating i18n
instance. 🎉 🎉 🎉
// `choiceOptions` relates to the number of options for the specified translation
// `i18n.tc()` accepts 2 or 3 options, so the code is covering both cases
// In case of translation having only 2 options, empty and single options will be the same
// `choiceOptions` value is the length of options for that translation
const getOptionsByTranslationChoices = (choiceOptions) => choiceOptions === 3 ? {
returnAsEmpty: 0,
returnAsSingle: 1,
returnAsPlural: 2,
} :
{
returnAsEmpty: 0,
returnAsSingle: 0,
returnAsPlural: 1,
};
/**
* A helper function for applying decimals as plural for english speakers
* @param {number} [choice] - Number passed to `i18n.tc()` function as value to be resolved
* @param {number} [choiceOptions] - `3` or `2`: Number of options available on the translation file to that specific key
* @returns {number} 0: `empty`, 1: `single`, 2: `plural`
*/
const applyingDecimalsAsPluralForEnglishSpeakers = (choice, choiceOptions) => {
// These codes are related to `vue-i18n` internals to pluralize resolution
// - 0: it should return empty value as result
// - 1: it should return single value as result
// - 2: it should return plural value as result
const { returnAsEmpty, returnAsSingle, returnAsPlural } = getOptionsByTranslationChoices(choiceOptions);
// Returns empty if receives `0` as value
if (choice === 0) {
return returnAsEmpty;
}
// NOTE: In english, decimals are also plural
// This function always receives value as `number`, so it's safe to assume
// decimal values as result of `!Number.isInteger()` and return as plural
if (!Number.isInteger(choice)) {
return returnAsPlural;
}
// Otherwise, check if number is more than 1 to return as plural or single
return choice > 1 ? returnAsPlural : returnAsSingle;
};
// In this example, I'm applying this rule only for `en`
const pluralizationRules = {
'en':applyingDecimalsAsPluralForEnglish,
};
const _i18n = createI18n({
// ...
// Applying the rule
pluralizationRules,
});