-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
i18n: add support for multiple instances and reactivity to the i18n library #19210
Comments
I considered this early on, though at the time it felt to me the value wasn't very high in contrast with the overhead required to be able to achieve this (multiple, separate APIs when wanting or not wanting reactive translations, higher-order components, etc). A hooks-based solution might be a little more seamless these days. To me, on how it applies to the real-world: How often are we expecting this locale data to change? For most users, I expect it's assigned once and never changes again. In that light, the current solution seemed acceptable enough in simplifying the developer experience, even if at the expense of reactivity. Aside: Doesn't switching language on WordPress.com trigger a full-page reload? So even if it's technically possible for those strings to be reactively updated, it doesn't seem to be in use. Has there been much concern over this? Overall though, I think it could make sense to offer options like the ones you suggestion, in addition to the current defaults. One thing I'm not sure of is where it would make sense for the React-specific implementation to exist in code. Currently, On the specific point of instances: It could be argued to be something where the use-case is specific enough to warrant using the underlying Tannin library instead, which does support this, and is generally less opinionated. |
I think the strongest use case here is server-side rendering, where the current solution is simply unusable. The
When you change the language in your account setting, then yes, Calypso will be reloaded. But this could be removed today if we wanted. The reasons for doing it mostly disappeared over the last year or two. Calypso has two, rather minor but still neat, features that change translations at runtime without reload:
These couldn't work without reactive translations.
That's a good point. I think the React wrappers should be in a separate package:
Yes, a
I think that Tannin is a low-level library and that developers don't want to have |
Just to add another i18n related example: https://www.i18next.com/overview/supported-frameworks |
I've been working on React bindings which I'd be happy to contribute to Gutenberg: |
Related to this, if we had a package like this, it seems like it could also be a more appropriate home for cc @nerrad |
On the points made in the thread:
|
That's a good point. With that in mind, I don't feel too strongly one way or the other in whether it live in |
It's very similar to What are the use cases for element interpolation outside an i18n context? |
Any string interpolation that doesn't require localization (which admittedly in the WP context would be suspect). One particular use-case might be some sort of template interpolation? I've personally always thought it odd that Regardless, my preference isn't a hill to die on. If folks want this in a |
With #28465 merged, I believe this is complete. Migration of existing usage to the new |
The
@wordpress/i18n
library is currently a very simple module (60 lines of code when comments are ignored) that acts as a singleton with essentially two methods:setLocaleData( data )
stores the supplied translation data in an internal global variable__( text )
looks up a text in the global variable and returns a translation from thereIn this issue, I'm arguing that this design is insufficient for many WordPress-related use cases, and proposing several enhancements, all of them 100% backwards compatible.
Problem 1: multiple instances and server-side rendering
Consider building a Node.js server with Express.js that used React to render a localized login form. The code would look like this:
When handling a route like
/login/de
, the request handler reads a localization data file for German, loads them into the@wordpress/i18n
library, and then render the<LoginForm>
component into string and send the string in the HTTP response. The__()
calls inside the<LoginForm>
component will use the data for German.This kind of code has one very obvious shortcoming: when handling two requests in parallel, e.g.,
/login/de
and/login/es
, both handlers will share one instance of@wordpress/i18n
and will be overwriting each other's data. The language of the rendered login page will be somewhat random.At the same time, with the current
@wordpress/i18n
, we can't do any better.For Node.js apps that use server-side rendering, for example, rich admin apps like Calypso or headless WordPress frontends like Frontity, using
@wordpress/components
and@wordpress/i18n
to create UIs is not a reliable option.The solution I'm proposing has two parts:
I18N
class:I18N
instance to a React tree in context:This renders two versions of the login form, each with independent locale data and not influencing each other, given that the
LoginForm
component uses the translation functions from context:Note that we had to add just one line (the
useContext
hook) to the component to make it use__()
from the context rather than from the global.Using this new capabilities, our Express.js can easily be fixed.
Problem 2: reactive translations
Using the React context for passing the translation functions and data is useful also for other use cases outside server-side rendering. Unlike the original
@wordpress/i18n
, all localized React components will be automatically rerendered when the context changes. That can be used to implement features like:I18N
instance and they will trigger a React rerender.Backward compatibility:
The
@wordpress/i18n
library can provide a default instance ofI18N
and export its method as functions:and the i18n React context can use this instance as its default value, too:
Then, when a React component uses the
const { __ } = useContext( I18NContext )
hook, and there is no provider in the JSX tree, it won't crash -- it will use the default instance.That provides 100% backward API compatibility without any breaking changes. And lets us update
@wordpress/components
to use context instead of a global to get the__
function, without breaking any existing usages.Prior art:
Popular community libraries like
react-intl
or@lingui/react
use the same patterns as described here: core object instances, React context and reactive helpers. See also this recent big overview article about React i18n libraries.i18n-calypso
used in Calypso provides reactive helpers (localize
HOC anduseTranslate
hook), can have multiple instances and can be extended to use React context.The text was updated successfully, but these errors were encountered: