i18n-node icon indicating copy to clipboard operation
i18n-node copied to clipboard

Key shown when not in other locale

Open thenitai opened this issue 11 years ago • 24 comments

Hi,

ExpressJS and Jade here. Using your fine library but running into an issue when changing locale. That is, that the key is being shown instead of the default locale (english in my case).

en.json contains this:

"select_language" : "Select language"

de.json does NOT contain it at all and what we see instead of "Select language" is the "select_language".

Using 0.4.1 (the one that comes by default when doing a npm install i18n)

Thanks for the feedback.

Kind Regards, Nitai

thenitai avatar Nov 09 '13 00:11 thenitai

Hey :)

in short: this is intended. Let me explain what happens:

by default i18n will return the "key" as is, as long there is no translation found for current language. The key itself is intended to be an expression like "please translate me" and will get returned until finally translated.

2nd thing is determining languages: i18n determines them by req headers in several ways. DefaultLanguage only get's set when req doesn't provide one of the configured languages, no matter of status of their underlying translations.

So in your case, i18n won't switch to DefaultLanguage but will try to translate that term in current language, without finding that translated term.

That behavior is borrowed from different gettext implementations where you start working with terms in a default language (mostly en), and will add i18n later by simply adding some i18n files. So i18n should return the given key as kind of "default term".

I am just thinking about a config switch to fallback to defaultLanguage on empty terms... should work, just needs some time + testing :)

mashpie avatar Nov 09 '13 09:11 mashpie

Thank you for your explanations. Coming from, say Java .properties files, the default behaviour is to fall back to English translation and show the English translated text, if the key could not be found in the current locale.

This makes totally sense, especially in a production environment. There you usually don't want that customers see a message like "please translate me". Say, I'm in German and instead of "Bitte wählen Sie eine Sprache" I see a "select_locals" (if that would be my key). I don't think that goes down well.

(Just a view of someone who has deployed a couple of applications) :-)

According to your answer above, you say that if I don't set any languages in the config, this behaviour will change? If you need someone to test, please call on me.

Thank you for all your work and time. Much appreciated.

thenitai avatar Nov 09 '13 15:11 thenitai

both scenarios have their pros and cons (actually I do use both depending on use case, for more than 15years now). OK no need to discuss as there is a solution: implementing a config switch, which could even be env depended. that way you can condigure to get untranslated terms on dev and foreign language terms on prod...

mashpie avatar Nov 10 '13 09:11 mashpie

Yes a config setting would be awesome. Thank you for making an awesome library even better :-)

thenitai avatar Nov 10 '13 18:11 thenitai

:+1: A config Setting for 'partial' fallback!

dirwin517 avatar May 06 '15 15:05 dirwin517

+1

pedrodelgallego avatar Aug 14 '15 13:08 pedrodelgallego

+1 for having a fallback system between supported locales if keys in one locale is only partially translated.

I've seen this has been also discussed on 18n-node-2 : https://github.com/jeresig/i18n-node-2/pull/29

rkorach avatar Apr 14 '16 14:04 rkorach

well fallbacks are in for a while now, see https://github.com/mashpie/i18n-node/blob/master/test/i18n.fallbacks.js and https://github.com/mashpie/i18n-node#list-of-all-configuration-options

anything still missing for you?

mashpie avatar Apr 14 '16 14:04 mashpie

Sorry, I may have understood it wrong.

The way I understand the doc

  • if the user locale is not in the declared locales it automatically fallbacks to the defaultLocale
  • with the fallback config parameter, you can force a user (unsupported) locale to fallback to one of the declared locales, different from the defaultLocale

What I am looking for - maybe 'fallback' wasn't a good term to use

  • I declare 3 locales, and always force one of these locales, (say [en, fr, de], with fr as default)
  • if one key is translated in 'fr' and 'en', but not in 'de', currently the german user will see the key displayed. I'd like i18n to display the 'en' translation if german translation not ready.

I couldn't manage to make this work, but let me know if I got everything wrong I'll try that once again.

rkorach avatar Apr 14 '16 17:04 rkorach

Let's try to sum up a little:

So you are trying to achieve a "partial" translation, right? The only intended "fallback" is the key itself.

__('Hi Dear') will put "Hi Dear" until translated in the corresponding fr.json file:

{
    "Hi Dear": "Salut mon cher"
}

all fallback logics right now happen in stage of language guessing and represent the current state for all phrases managed.

So what you want is a fallback for translating certain phrases which will lead to mixed translated output with one phrase in fr and another de and probably some untranslated in en. I won't discuss on user experience...

use cases covered right now are:

  1. use key as fallback for any untranslated phrase (ie: "return original pharse until translated in my locale")
  2. use defaultLocale for all phrases in case of request with unsupported locale (ie: "use en unless requested locale is handled")
  3. use an explicit fallback for all phrases from one locale to another (ie: "use de for request in ch")

so what you want is

use a master translation for all untranslated phrases (ie: "I translated 'Greeting' with 'Hello' in en but not yet in de and expect "Hello" from defaultLocale en instead of "Greeting" for all supported and unsupported languages which by itself will also have to follow 1-3 from above)

it could work (@see https://github.com/mashpie/i18n-node/blob/master/i18n.js#L834) by declaring multiple fallbacks, but I haven't tried yet:

i18n.configure({
  // setup supported locales
  locales:['en', 'fr', 'de'],

  // fall back to en phrases for untranslated phrases
  fallbacks:{'fr': 'en', 'de': 'en'},

  // default locale for any unsported requests
  defaultLocale: 'fr'
});

mashpie avatar May 23 '16 10:05 mashpie

tl;dr: the Translation Management service I use (PhraseApp) now has a configuration to to exactly this.

I still might prefer the feature to be in the i18n module.

You got it perfectly right. As for the user experience, I agree with you. Sometimes though hot features could use a quick launch instead of waiting for translations. As long as you are aware of what you do (and don't mix several languages at the same place). Anyway, let's keep the debate aside.

I did try the fallback strategy in the past (I thought this is how it worked), and tried it again now to be sure but no, fallback only seems to work if the language is not in the locales array when configuring i18n.

I thought of a dirty hack (check if a translation is equal to its key and if so force to defaultLocale translation) , but it would have been really ugly to scale it to the whole code base.

Quick note: missing translation falling back to the key is blocking for me since I use an object notation for my keys.

Luckily for me, PhraseApp does provide this feature now.

Thanks a lot for your time Marcus.

rkorach avatar Jul 12 '16 21:07 rkorach

Regarding the original request, I believe that Paxa's (unmeged) "retryInDefaultLocale" PR attempted to provide a basic fix for this, using the configured default locale as a fallback: https://github.com/mashpie/i18n-node/pull/206/commits/ee0da09cfe21c2f82f57913f94eacc2e2e4b7c15

It had an infinite recursion bug though, which I've fixed here: https://github.com/eloquence/i18n-node/commit/b2e67a8ea81da6fa5c473fcfc428e5b37f818cfa

eloquence avatar May 16 '17 01:05 eloquence

Was this ever implemented?

The discussion about a "master language" that you always fall back on is exactly what I am in need of.

I can't even get a single fallback to work right now, if the key isn't defined in one language, but is in the other, I still get the key value back when querying.

FlyveHest avatar Apr 08 '18 20:04 FlyveHest

This issue is still relevant!

kaaax0815 avatar May 25 '21 11:05 kaaax0815

How could we live without fallbacks for so many years?!

In short: i18n is about "translate on phrase to mutliple languages" while l10n is responsible to deliver one translation to the user... Or in a bit longer: https://blog.mozilla.org/l10n/2011/12/14/i18n-vs-l10n-whats-the-diff/

So for i18n (transfare one 'hello' into multiple 'Hi', 'Salut', 'Hei', 'Witam', 'Olá') we are set. For l10n we are not. Despite some features, that can be configured like:

  // fallback from Dutch to German and from any localized German (de-at, de-li etc.) to German
  fallbacks: { nl: 'de', 'de-*': 'de' },

  // you may alter a site wide default locale
  defaultLocale: 'en',

  // will return translation from defaultLocale in case current locale doesn't provide it
  retryInDefaultLocale: false,

Because, okay - over time i18n and l10n got used more and more as synonyms and so we finally that ended up in adding some basic l10n to i18n.

Still I think the desired feature is best outlined in vue-i18n fallback strategy: https://kazupon.github.io/vue-i18n/guide/fallback.html with lot's of options to rethink the l10n part of the whole i18n story in addition to what we have.

But to come back to you @kaaax0815 : What part of "The issue" do you refer to, exactly?

Maybe, just in case, you could add some failing tests to https://github.com/mashpie/i18n-node/blob/master/test/i18n.retryInDefaultLocale.js that should properly resolve and describe your issue better?

mashpie avatar May 25 '21 15:05 mashpie

@mashpie Very cool comment! I have a bit which I wanted to localize. The user could set an env bar to a local and its not avaible use the default. I found a work around for my particular approach. By checking if the env var lang is in the languages array if not use the default. A native approach would be nicer, but not necessarily needed

kaaax0815 avatar May 25 '21 15:05 kaaax0815

doesn't that config option do the trick?

  // will return translation from defaultLocale in case current locale doesn't provide it
  retryInDefaultLocale: false,

while talking about env var lang... do you use i18n within a cli or http context?

If talking about cli usage only, I'd recommend y18n https://www.npmjs.com/package/y18n to be much better focused on your use case.

mashpie avatar May 25 '21 16:05 mashpie

@mashpie I use it for my discord bot. and retryInDefaultLocale: false didnt work maybe because i run setLocale and this changes the default lang asaik

kaaax0815 avatar May 25 '21 16:05 kaaax0815

of course it should be set to true - setLocale does not change defaultLocale. setLocale sets the locale on the registered object, see

https://github.com/mashpie/i18n-node#some-words-on-register-option

and

https://github.com/mashpie/i18n-node/blob/master/test/i18n.setLocale.js

mashpie avatar May 25 '21 16:05 mashpie

i meant true. my bad. it didnt work nevertheless

kaaax0815 avatar May 25 '21 16:05 kaaax0815

Briefly looking at your repository it seams, that you are using a global singleton for both: cli and web requests. And I can't find any configure() at all, which means that i18n will act as a singleton sharing state between all and everything within your app.

This will lead to issues with concurrency as any change to the current locale will change locales in all given contexts. In addition, without configuration there is no context nor request object and this results in a defaultLanguage of nullor undefined - so without any defaults there is nothing to look up, right?

So, please: Use an instance. Configure that instance with i18n.configure({...}). Bind that to a context thru register on configure manually or use i18n.init(req, res, next) to automatically bind to req and res objects as context.

And please if and only if you insist on directly using i18n as a global singleton, do so by configuring it with the register: global option. Checkout examples in tests, esp. this one: https://github.com/mashpie/i18n-node/blob/master/test/i18n.api.global.js

mashpie avatar May 25 '21 17:05 mashpie

@mashpie I do configure a instance here: https://github.com/kaaaxcreators/Discord-MusicBot/blob/824527b00dc96d514c93db81b4e681bf7101a972/src/index.ts#L52 and because i dont have any express or stuff like that i dont have any req or res

kaaax0815 avatar May 25 '21 20:05 kaaax0815

Ok, registers to global. So setLocale should work for that Single process. Same as __()

I was looking at Server.ts and commands...

https://github.com/kaaaxcreators/Discord-MusicBot/blob/824527b00dc96d514c93db81b4e681bf7101a972/src/server.ts

Importing i18n module won’t ensure it‘s configured when used.

To get that straight: you want to use i18n for command line only. Not for req/res cycle of a webserver?

mashpie avatar May 25 '21 21:05 mashpie

I use my webserver only to show static text nothing translatet, so no i do Not want to use i18n for req/res cycle

kaaax0815 avatar May 25 '21 21:05 kaaax0815