Formatting is broken when switching language
See original GitHub issuevue & vue-i18n version
Vue version: 2.6.11 Vue-i18n version: 8.18.2
Reproduction Link
https://codesandbox.io/s/elastic-shockley-wjw0z
Steps to reproduce
When using a formatter like the one provided by the official documentation, and switching locale, the formatter is not aware of this change.
(INFO: I tried this version of the formatter but it seems broken : TypeError: fn(...).map is not a function
)
So I added this method to the formatter:
// Formatter.js
changeLocale(locale) {
this._locale = locale;
this._formatter = new MessageFormat(locale);
}
Then I can use this method when switching locale:
// App.vue
switchLocale(locale) {
this.$i18n.locale = locale;
this.$i18n.formatter.changeLocale(locale);
},
I don’t know if it’s the proper way to do this, but it solves partially my problem. Maybe there is another way to achieve this?
BUT, there’s still a bug, formatted messages doesn’t update when the translation string is exactly the same in both languages! Example:
const translations = {
fr: {
test: {
number: {
first: "Mon nombre est {myNumber, number, integer}",
second: "{myNumber, number, integer}" // exact same string in 'en' and 'fr'
},
date: {
first: "Ma date est {myDate, date, medium}",
second: "{myDate, date, medium}" // exact same string in 'en' and 'fr'
}
}
},
en: {
test: {
number: {
first: "My number is {myNumber, number, integer}",
second: "{myNumber, number, integer}" // exact same string in 'en' and 'fr'
},
date: {
first: "My date is {myDate, date, medium}",
second: "{myDate, date, medium}" // exact same string in 'en' and 'fr'
}
}
}
};
What is Expected?
When I use translation strings in a template and I switch locale, I expect the strings to be formatted in the chosen locale.
Number first
- template:
{{ $t('test.number.first', { myNumber: 2440 }) }}
- expected output:
- en:
My number is 2,440
✔️ - fr:
Mon nombre est 2 440
✔️
- en:
Number second
- template:
{{ $t('test.number.second', { myNumber: 2440 }) }}
- expected output:
- en:
2,440
✔️ - fr:
2 440
❌
- en:
Date first
- template:
{{ $t('test.date.first', { myDate: '2020-08-28 13:47:38+02:00' }) }}
- expected output:
- en:
My date is Aug 28, 2020
✔️ - fr:
Ma date est 28 août 2020
✔️
- en:
Date second
- template:
{{ $t('test.date.second', { myDate: '2020-08-28 13:47:38+02:00' }) }}
- expected output:
- en:
Aug 28, 2020
✔️ - fr:
28 août 2020
❌
- en:
What is actually happening?
Number second
- actual output:
- fr:
2,440
- fr:
Date second
- actual output:
- fr:
Aug 28, 2020
- fr:
As I said before, the concerned translation strings are those that are exactly the same in ‘en’ and ‘fr’, so I guess it could be a cache issue?
Any idea how to solve this?
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:11
Top GitHub Comments
@kazupon @Pochwar
The current issue is solved by doing below⬇️.
Question 1: injecting method into formatter
@Pochwar with help of
changeLocale(locale)
method that you’ve added we can fix format by adding space in the messages field.like this:
Previously it was written like
Please check this in your env and let me know.
Question 2
About setting up the formatter config correctly, it looks that current formatter config could not know when the
locale
has changed/updated from vue component. Once theFormatter class
constructor is set its locale as default value, in this case it is ‘en’, after language switch btn pressed it could not updatelocale
accordingly.However
this.$i18n.formatter.changeLocale(locale)
is called when button pressed andswitchLocale()
is called, in this case formatter can get updated.So I am looking into config now. Once I get the idea, will update you shortly.
Hi @Pochwar and @Azjargal13,
I guess I found this issue too late. Maybe you have figure out the solution yet. Anyway, just to be sure, here it is.
You were right about the cache. It is a problem. You have to realize that messages serve as keys in the instantiated cache object. On the contrary, values represent MessageFormat configs. So, when you interpolate the key “second” for French, this key already exists. In this case, the key for English and French is the same, so the code has no reason to update the MessageFormat config because of this check.
If we know this, the solution is pretty straightforward. We need to define a cache, which is capable to hold separate locale objects. Then we need to refactor the code to work with these locale objects. Moreover, I decided to cache localised instances of MessageFormat. Below, you have the result.
I tested the code out, and it works as you need.