i18n revamp (WORK IN PROGRESS) #154
Replies: 9 comments 3 replies
-
We discussed some i18n things @Mohammer5 and I encountered here on slack. We were discussing the usecase for namespaces, and @amcgee noted that even though the string might be the same, the context could mean that the translation would be different. But we don't really provide context to translators. So one thing we could add is that we should start adding context for translators. |
Beta Was this translation helpful? Give feedback.
-
Related - static analysis of code to find untranslated UI strings dhis2/cli-style#256 (Thanks @ismay @martinkrulltott @HendrikThePendric) |
Beta Was this translation helpful? Give feedback.
-
See also dhis2/app-platform#98 (closed)
|
Beta Was this translation helpful? Give feedback.
-
Another requirement proposal: It'd be nice to be able to use markup / react components inside the translation string. i18n-react (or so) has a solution for this already. @cooper-joe made some designs for the new maintenance app where there were some styled withing translatable text (like bold text) |
Beta Was this translation helpful? Give feedback.
-
@Mohammer5 definitely! The challenge with |
Beta Was this translation helpful? Give feedback.
-
See also this thread: https://dhis2.slack.com/archives/C0BP0RABF/p1601970390067700. We also need to support localised pluralization, and allowing for translation context would be good as well. Currently I don't think we properly support that (but correct me if I'm wrong). |
Beta Was this translation helpful? Give feedback.
-
Regarding plurals, there is a problem with our current set up that is short-circuiting translations. This is currently happening for the interpretations component in d2-ui. Locally, the
Once extracted, the en.pot file looks like this:
But transifex does not accept pot files with translations in them (the msgstr[0] and msgstr[1]). So currently, the process stops here and updated po files are not being created on transifex. One potential workaround is to post-process the
Then we can configure transifex to push an
Which would be generated into the
Phil and I have been discussing this and agree that it would be very strange if we are the first organization to be running into this problem. So is there something I'm missing? One interesting fact - during the extract-pot process,
So maybe there are three solutions, given our current configuration:
|
Beta Was this translation helpful? Give feedback.
-
Without having a deep knowledge on the topics as you all do, I wanted to drop here two links.
Some context on why I am actually adding this. Hoping that it can serve us some sort of inspiration in out own problems. So that perhaps seeing how fb handles their translation we can get into a similar solution ourselves if wanted to build our own in-house solution for this. Happy to help further with this as I can :) |
Beta Was this translation helpful? Give feedback.
-
Whilst working on the sharing dialog I noticed we don't currently have a way to translate a text with multiple pluralizations. So for example: "{{ amountLikes }} likes for {{ amountArticles }} articles". Also, even a text with a single pluralization currently doesn't work out of the box (as Jennifer mentioned). On a related note, whilst going through this I started wondering if it might be viable to consider other upstream libraries (so besides i18n). i18n seems to be actively maintained, but mainly just by two people. Lately just one even. So documentation is lacking for example. As Christos mentioned, there are other libraries out there (like fbt, etc.), which might be a better fit than i18n for our purposes, and more stable and easier to use over the long run. |
Beta Was this translation helpful? Give feedback.
-
THIS IS A WORK IN PROGRESS, I will continue fleshing it out before sharing for comment
I'm opening this issue to discuss an overhaul of the internationalization (i18n) system. I'll start by laying out the challenges we face with the current system, and this issue will then coalesce into a specification for an overhaul of the platform-native i18n functionality.
The Problem(s)
Types of translations in DHIS2
There are three primary categories of strings in
Server-bundled translations For a long time, all translations were bundled into the DHIS2 core and accessible through an API endpoint. Pretty much all use of this system has been eliminated, but some strings still have their translations baked into the WAR file (notably bundled application names)
Application-bundled translations ...TODO
Dynamic translations Some strings are truly dynamic, created by the implementer of the instance when configuring their metadata model. These strings are created, updated, and accessed through the API and stored in the database. We won't be directly addressing this use-case in for application-bundled strings, but it's good to keep in mind.
A brief history of application-bundled translations
d2 (the ancient solution) -
d2-i18n (the legacy solution) -
Some info here: https://docs.google.com/document/d/19EK7XoMdzu4E0MMWOZMz1z3G55DJ2dmcMp5HUcggRfo
d2-app-scripts i18n (the current solution) -
There are a few straggling uses of the (relatively) ancient
d2
system in some of our libraries (notablyd2-ui
). I won't address the challenges with that system, as it is deprecated and should be removed.There may be some additional methods of translation out there, such as the one in
scheduler-app
which only supports English and Urdu and doesn't appear connected to Transifex (see dhis2/scheduler-app#46)Challenges with the
d2-i18n
"legacy" solutionUntil very recently, the "standard" fleet of internationalization tools for DHIS2 libraries and applications was :
...TODO
Challenges with the "current"
d2-app-scripts i18n
systemThis is almost a direct port of the previous system. It combines ported versions of
d2-i18n-extract
andd2-i18n-generate
into a single App Platform cli module (d2-app-scripts i18n
) and automatically runs the extract and generate steps when building an application or library with the platform. The components are:And here are some of the challenges:
default
). This is because the string requests don't include their own namespace (i18n.t('This is a test')
noti18n.t('namespace:This is a test')
). @jenniferarnesen wrote up a nice overview of how we might re-introduce namespacing here. This would require changing all instances ofi18n.t
in our sourcecode to include a namespace, and would require us to make sure the chosen namespace separator could never occur in the English string (:
is particularly problematic for this reason):
and_
, by default) which can happen. Instead, we should probably create a non-crypographic hash (sha1, for instance) of the English string and use that as the key - Transifex should pick up the default English translation and offer that to translators, so it should be an opaque change.i18n extract
command on pre-build and pre-start in applications, but this can lead to a couple subtle issues. Firstly, if the developer doesn't re-run build or start before committing code then the committed pot file will be "out of sync" with the strings in the source code (this can be alleviated with a pre-commit hooki18n extract && git add ./i18n
). In some cases, string extraction will also unnecessarily re-order keys in the.pot
file and/or will cause only the timestamp in the.pot
file to change. This could be avoided by removing the timestamp and ordering keys in a stable way.i18n generate
step generates javascript code in the application (or library's)/src/locales
directory. Not only is this confusing and error prone (invalid javascript can sometimes be generated when locales include a-
, for instance) but it requires the library or app developer to manually include the./locales/index.js
at least once for each entrypoint, and to mark it as code with side-effects.const str = i18n.t('Hello world')
at module initialization time, which means it always uses the English string.react-i18next
for VDOM-integrated translations.i18n.t
.react-i18next
supports this, but was initially avoided because of challenges with right-to-left support[SPEC] Requirements for a revamped i18n solution
...TODO
Lazy-loaded locale bundles or SSR
moment
bundles should for locales not in use should be omitted from the bundle (this is already done in the app platform).Dynamic locale selection
?locale=es
query-string, which would also allow for automated testing of localization in Cypress, for instance.?locale=<xyz>
Semantic Markup - ref Declaring language in HTML
html
lang
attribute should be correctly set (<html lang="nl">
), this will likely need to be done dynamically after page load unless we implement server-side rendering.<html>
should set their ownlang
tag (this is particularly important for untranslated text and for locale names)CSS - ref CSS for internationalization
A proposed design
...TODO
Things left unaddressed by this spec
Intl.NumberFormat
,Intl.DateTimeFormat
andIntl.ListFormat
respectively)new Intl.NumberFormat(i18n.language).format(value)
try/catch
as DHIS2 locales (passed as first argument) are not always ISO 639 compliantBeta Was this translation helpful? Give feedback.
All reactions