-
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
[EXPERIMENTAL] react-i18n: client-side locale switching #27973
Conversation
There's an issue touches on this: #19210 |
Yes, correct, this PR originated from the discussion on that issue. Apologies for not linking to it in the description. |
return formats.filter( ( format ) => | ||
includes( supportedFormats, format.id ) | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using useMemo
would be beneficial here, avoiding translating, sorting and filtering the array over and over on each render:
const formats = useMemo( () => {
return [ ... ].sort( ... );
}, [ __ ] );
const filteredFormats = useMemo( () => {
return formats.filter( ... );
}, [ formats, supportedFormats ] );
return filteredFormats;
In a next step I'll factor out the REST API integration (effect to load new translations upon locale changing) out of the I assume this can be easily moved to a second follow-up PR too. |
localeMap.get( locale ).setLocaleData( data ); | ||
setLocaleMap( | ||
new Map( localeMap.set( locale, localeMap.get( locale ) ) ) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be just setLocaleMap( new Map( localeMap ) )
. The set( get() )
bit doesn't do anything. We just need to update state with a new copy of the map that's not ===
to the previous one.
|
||
return { | ||
locale, | ||
__, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's very useful to bind the __
functions to create unique instances on every context change: return { __: __.bind() }
. Without this, after setLocaleData()
the i18n
object is still the same and therefore the __
function is still the same. Even though the translation data have changed and components should be updated.
If the __
value doesn't change, usages like this will fail to rerender and update:
const Heading = React.memo( ( { __ } ) => {
return <h1>{ __( 'Warning' ) }</h1>;
} );
const Box = ( text ) => {
const { __ } = useTranslate();
return (
<div>
<Heading __={ __ } />
<p>{ __( 'Hello' ) }</p>
</div>
);
}
A component that uses React.memo
or React.PureComponent
will rerender only when props change, and for <Heading />
and setLocaleData()
they don't.
This scenario will happen any time there is a withTranslate
higher-order component, which passes __
down as a prop, and a Redux-connect
-ed component, which by default behaves as pure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, good call!
This could be factored out into three independent parts: The const i18n = createI18n();
<Provider i18n={ i18n } /> and makes the localization data available to the entire React tree, with reactive updates. Updates are made when the This Such a The only wrinkle is the fact that the Calypso The other little difference is the naming of the hook: The second part is the map of locale data for different languages. This can be kept separately from the The third part would be the code that async-loads the locale data from REST API or any other source. |
Makes sense to me! I think I could easily update this PR accordingly.
I see! So
Are you imagining this to also hold the |
We worked on I'd also favor the idea of keeping |
I don't know at this moment, but I think there's a good way how to figure it out: @sirreal wrote a very similar language switching code for the WordPress.com Gutenboarding project. That's a React app that runs almost completely outside Gutenberg and WordPress, and it just uses the If we compare the two implementations, we could get some clues about which parts are generic and reusable and which are app-specific. I'll return to this work on Monday 🙂 |
For reference, the work is open source here:
|
In #28465 I'm proposing a If this PR is rebased on top of that one, it should only contain the code that maintains a map of |
Description
Explores possibilities of client-side locale switching using a new
react-i18n
package containing a React context provider.As discussed in #19210
After the fact I learned that this is similar to what Automattic has been working on here.
How has this been tested?
There's some dummy dropdown in there at the moment for easier testing.
Screenshots
Types of changes
New feature (non-breaking change which adds functionality)
Checklist: