vue-i18n
vue-i18n copied to clipboard
Change the way missing translation keys are detected
Hello,
Our translations are handled with Crowdin and one particularity with Crowdin is that, if a key wasn't translated yet and we sync them; Crowdin will return the key with an empty string instead of returning the file without the missing keys.
The thing is that, vue-i18n considers the empty string as an already-translated key, so it will uses it instead of fallbacking to the default version (english).
It would be great to override this default rule, so I can say that: "If my key is missing OR my key is empty, fallback to the default version".
An implementation suggestion would be a handler in the config that returns true or false if the key passed should be considered as missing?
I just ran across this problem as well, also with Crowdin translations. As mentioned, an option when instantiating vue-i18n to consider empty string valid or not would be a good fix for this.
I would be willing to look into creating a PR for this if it will be considered for inclusion.
Welcome contribution! :)
Localisation services often provide option for deciding on behaviour of exporting empty translations. At least lokalise
does provide api option export_empty_as = base | skip | empty
.
@rchl You're right. Crowdin have this option in their settings for some file types but not for JSON. We asked them what's up the same day I opened this issue and they added it. So my issue is "fixed".
Nonetheless, this feature would be a nice-to-have.
@WilliamDASILVA Really. So it's possible to change it so that crowdin will not export empty strings? Where exactly do I set this?
@nekosaur Go to your project, then click on "Settings". Go to the "General" tab, represented by the sliders icons (the first one).
On the "Export" section, ensure the "Skip untranslated strings" is checked.


Hope that helps! And sorry for the off-topic comment.
@nekosaur Have you started work on this? If not I would like to have a go at it :)
@makeupsomething Some things got in the way for me, so have at it 👍
Does anyone have a fix for this yet? it would be really useful if we could set empty strings to be considered fallback. Thanks!
@ssuess
I have workaround example. Here I replace empty strings with translation keys (that is what I needed at my project), but you could also retrieve fallback language string here if you want.
This code is placed among app bootstrapping code, after Vue.use(VueI18n);
// We decorate translation-retrieving functions so that empty strings
// (effectively untranslated strings) are replaced with translation keys (like undefined strings are).
Vue.prototype.$t = function (key, locale, values) {
const result = this.$i18n.t(key, locale, values);
if (result === '') {
return key;
}
return result;
};
Vue.prototype.$tc = function (key, choice, locale, values) {
const result = this.$i18n.tc(key, choice, locale, values);
if (result === '') {
return key;
}
return result;
};
@ssuess I have workaround example. Here I replace empty strings with translation keys (that is what I needed at my project), but you could also retrieve fallback language string here if you want.
This code is placed among app bootstrapping code, after
Vue.use(VueI18n);
// We decorate translation-retrieving functions so that empty strings // (effectively untranslated strings) are replaced with translation keys (like undefined strings are). Vue.prototype.$t = function (key, locale, values) { const result = this.$i18n.t(key, locale, values); if (result === '') { return key; } return result; }; Vue.prototype.$tc = function (key, choice, locale, values) { const result = this.$i18n.tc(key, choice, locale, values); if (result === '') { return key; } return result; };
You code is working in most cases but it has a problem when render messages that include parameter. I would like to change the code as below to fix this issue
Vue.prototype.$t = function (...args) {
const result = this.$i18n.t.apply(this.$i18n, args)
if (result === '') {
return args[0]
}
return result
}
Vue.prototype.$tc = function (...args) {
const result = this.$i18n.tc.apply(this.$i18n, args)
if (result === '') {
return args[0]
}
return result
}
@lbngoc you're right, my code fails when parameters passed but locale is not — I forgot about this case. Actually I think it's bad decision in the library that these 2 signatures of t
and tc
functions exist. Makes me parse args
manually if I want to use locale or parameters (as I now need on my project).
FYI:
In vue-i18n@v9 (vue-i18n-next) and later, the composable style (composition) API will be integrated to t
.
https://github.com/intlify/vue-i18n-next/blob/master/examples/composable/plural/basic.html
And also $t
and $tc
are kept as legacy style APIs.
https://github.com/intlify/vue-i18n-next/tree/master/examples/legacy
Crowdin only fixed this for flat JSON files. But if you have something like { "abc": { "a": "A", "b": "" } } is still exports empty strings. So this improvement for vue-i81n would be very welcome.
For now, I've solved it with postTranslation:
postTranslation: (value, path) => {
if (value === "") {
const parts = path.split('.');
let message = i18n.messages[CONFIG.fallbackLocale];
for (const key of parts) {
if (key in message) {
message = message[key];
}
else {
return value;
}
}
return message;
}
return value;
}