fix: make i18n consistently functional #98
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #95
There were a few bugs in the way we did i18n generation and handled the singleton runtime. This solves those issues for now, though there are still improvements to be made.
I removed the
i18n.changeLanguage('en')
andmoment.locale('en')
calls from the i18n template (yay everything living in one repo!), since it's superfluous and also wrong. This call was injected multiple places in the running code (one for each library or module that used the i18n setup), causing non-deterministic language selection.I also created a singular place to set the language and default namespace - the AuthBoundary in
app-shell-adapter
- with a newuseLocale
hook. This has the added benefit of defaulting to the browser-defined locale, rather than always to english, and then overrides that with the DHIS2 user's locale once a session is established.We also only load the moment locale for the current locale, rather than loading all of them (possibly multiple times) from the generated
locales/index.js
files. This fragments the bundle a bit (each locale gets its own chunk generated by webpack for the dynamic import) but should reduce the main bundle size if we have loads of different languages (the dream).The tradeoff I had to make here was this - previously, since every component had its own instance of
d2-i18n
and thereforei18next
(yeah, not exactly size-efficient) we would callsetDefaultNamespace
on that instance and rely on that to look up the correct string for each call toi18n.t
. When we switched to using a single instance ofi18n
this broke down. As a stopgap measure I've set the namespace to 'default', since we don't really use namespaces anyway (all strings from all languages for the whole app are included in the js bundle...). The keys are merged, so if there are different translations for a particular english string one will clobber the other, but this is probably OK for now.The other possible downside of this is that if we use
cli-app-scripts
to build external libraries (currently we only do this forapp-shell-adapter
which is internal) and change the behavior in the future (re-adding namespaces) we'll still have some strings injected to thedefault
namespace until we upgrade and re-build that external library.In this example my browser locale is Spanish, the Admin user is set to French, and the System user is set to English.
I went halfway down the road of building a babel plugin to inject the namespace into the string key of
i18n.t
calls, but I stopped because it might not be the right approach - we may instead want to stub out theimport '@dhis2/d2-i18n'
module and replace it with something we control, something that has afixedT
with a set namespace. Here's my half-complete plugin, worth further investigation...Side note: the headerbar, which has very few strings and is present in every application, is only in English...