i18next / i18next-xhr-backend

[deprecated] can be replaced with i18next-http-backend
https://github.com/i18next/i18next-http-backend
MIT License
253 stars 75 forks source link

missing files prevent i18next from doing graceful language fallback #283

Closed theblahhh closed 5 years ago

theblahhh commented 6 years ago

Can we reopen this? (#261)

I'm trying to implement use i18next init with a promise that will resolve once it's completely initialized (so that parts of the app can know the i18next object is initialized- not just immediately after the callback, but also well after). But currently with this issue, it will immediately reject(), even before XHR backend tries out fall back languages.

How can I know when init() has really, truly failed (particularly the backend not being able to find any files)? Currently, if I instead just let it resolve (or use a try/catch) when no appropriate json file could be found, it returns the string keys as fallback for the t() function, and keeps going. On the other hand, if i reject, there's no graceful fallback as described in #261


}, (err, t) => { 
   //init callback
   if (err){
      console.error(err);
      reject('i18next init promise reject');
   }
   resolve('i18next init promise resolve');
});
jamuhl commented 6 years ago

guess you just can ignore that error -> there won't be an error if you do not consider failing loading a language is one (you can define your whitelist and load option so i18next will not even try to load languages you do not support).

theblahhh commented 6 years ago

I do want to allow stuff like "en-US" and "en-GB" to work though with a nonExplicitWhitelist: true option, however (where my whitelist is [en, de].

I can ignore the error for now I suppose, but I find it kinda unideal :T

jamuhl commented 6 years ago

i guess you provide only en so setting load: 'languageOnly' will avoid loading en-US including your whitelist for languages you have there should everything loadable therefor having a language not load would be an error.

theblahhh commented 6 years ago

In the future, we may want to support GB english. Especially an issue for traditional / simplified Chinese, so I'm not sure if that's a long term solution...

Edit: I suppose a temporary solution besides letting the error go through is to have a custom language detector, but other than that...

jamuhl commented 6 years ago

then just resolve your promise and treat the error just as a warning...like said...beside failed loads - there is no other error

jamuhl commented 6 years ago

or go through the errors and check if one is relevant for your loading demand

jamuhl commented 6 years ago

or what behaviour would you like to see?

theblahhh commented 6 years ago

There should still be some way to see if literally no jsons could be retrieved however.

Edit: Okay, so I guess I have to look for the final error that can't find anything. Edit2: I would assume that the callback for init() would be to see if initialization succeeds or fails. But right now, it'll have callback from a sort-of "half-fail", where the init succeeds, but the first backend fails. Having a promise there for example, means that a promise can resolve before the "retry" backend starts, which is bad for async behavior. I feel like it should only return an error when loading the backends really , actually fails, or provide some other means of knowing when that happens, like a promise or a different "on" function.

Basically I am in the situation, where I want to allow "en-US", "en-GB" to resolve to "en." Currently we only have "en" and "de", where "en" is the fallback. We would also like to know when i18next is done initing using a promise, so we can render react components (we are not using HOC).

jamuhl commented 6 years ago

what is "half-fail" the callback gets called once and only once with all the language-namespaces in error if not loaded. Do i miss something here? Do you get it called multiple times?

theblahhh commented 6 years ago

I'm saying that it will run the callback, even when the xhr-backend hasn't "really" failed, as in it hasn't tried the "pure" language yet, which is bad for async.

edit: Also, I got confused when you were saying "go through the errors and check if one is relevant for your loading demand" and thought you were saying the callback gets called more than once.

jamuhl commented 6 years ago

what is pure language? the fallback language...

it has - the callback gets called with all languages based on the detected language -> ['en-US', 'en', 'fallbackLng'] - it's done

do you call init twice?

jamuhl commented 6 years ago

it queues to load: https://github.com/i18next/i18next/blob/master/src/BackendConnector.js#L42

and when loaded if no pendings calls the callback: https://github.com/i18next/i18next/blob/master/src/BackendConnector.js#L116

theblahhh commented 6 years ago

I meant "pure language" as in "en" since that's the term used on gitbook.

Okay, if the callback gets called more than once, basically, the solution is to look for the last error, in which even the fallbackLng json could not be found, right?

I'll do that for now, then.

jamuhl commented 6 years ago

if the callback gets called multiple time...there is something wrong on your side...really the init callback gets called only once by design -> check the code

jamuhl commented 6 years ago

https://jsfiddle.net/134uonq0/1/ see yourself - open the console, change language to "de" run again -- loads en, de and callback is only called once

update: https://jsfiddle.net/3jxyh9mu/

theblahhh commented 6 years ago

When you said, "the callback gets called with all languages based on the detected language -> ['en-US', 'en', 'fallbackLng'] - it's done"

I assume you meant this flow happened: 1) User has language with "en-US", we only have "en" 2) We call init using detected language of "en-US" 3) Backend tries to find "en-US", it fails and runs the callback 4) Backend tries to find "en", it succeeds, and runs the callback

Anyway, if the callback only gets called once, I still can't know when 4) happens, or if it fails

jamuhl commented 6 years ago

no:

1) User has language with "en-US", we only have "en" 2) We call init using detected language of "en-US" 3) Backends loads both en-US and en 4) Init callback get called with error en-US could not be loaded

and it gets called once...and only once...

theblahhh commented 6 years ago

So how can I know that "en" has been loaded?

As opposed to the situation where both "en-US", "en" and the fallbackLng fail? Do I have to look for a specific type of error?

jamuhl commented 6 years ago

en won't be in the error (error is an array containing what gone wrong...not just true)

also if it would have been a temporal issue with loading from backend it would have done 5 retries loading those...so it's actually a language you do not provide

theblahhh commented 6 years ago

alright, I see. Thanks for clarifying things then. I will try to do that.

I'll close the issue and see if it works out.

theblahhh commented 6 years ago

Hi, sorry to reopen again. I don't think I can detect using the error array, since I'm using the i18next-chained-backend which returns "Error: non of the backend loaded data; at loadPosition" errors.

jamuhl commented 6 years ago

hm...guess we should add some extended object like { lng, ns, err } here https://github.com/i18next/i18next/blob/master/src/BackendConnector.js#L101 like done on the event https://github.com/i18next/i18next/blob/master/src/BackendConnector.js#L84

would that help?

theblahhh commented 6 years ago

Yea, that would definitely help.

On my end, I can remove the chained backend as a temporary solution.