js-lingui: Memoized string-only translation does not update on `useLingui` re-render
Describe the bug
In v4, to ensure that messages tagged with the t macro get updated when the locale changes, we must subscribe components to the useLingui hook. This works reliably in the component’s return-to-render. However, if parts of the render are memoized using a hook such as useMemo, the value will not always be updated. Always, because this seems to only happen after switching the locale at least twice. The first change is registered. Yet, when i18n.locale is added to the hook’s dependencies, values are reliably re-computed.
To Reproduce
// LocaleProvider.tsx
// When the language changes, load and activate its message catalog.
useEffect(() => {
async function activate(language: SupportedLanguage): Promise<void> {
const { messages } = await import(`../../assets/locales/${language}/messages`);
i18n.load(language, messages);
i18n.activate(language);
setCachedLanguages((cachedLanguages) => {
return { ...cachedLanguages, [language]: true };
});
setShowLoadingSpinner(false);
}
activate(activeLanguage);
}, [activeLanguage]);
[...]
return (
<LocaleContext.Provider value={context}>
<I18nProvider i18n={i18n} {...props} />
</LocaleContext.Provider>
);
Does not work reliably:
const translatedMessage = useMemo(() => i18n._(msg`Unverified`), [i18n]);
console.log(translatedMessage); // Unverified
Works reliably:
const translatedMessage = useMemo(() => i18n._(msg`Unverified`), [i18n, i18n.locale]);
console.log(translatedMessage); // Sin verificar
Additional context Add any other context about the problem here.
- jsLingui version:
4.2.0 - Babel version:
@babel/core@7.21.5(via@lingui/cli@4.2.0) - Create React App:
5.0.1
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 15
I’m away for a few days now but believe there is a way to make this less verbose: we can expose the ‘t’ function from the context in such a way that it will change reference as we need. Then, the memo would depend on just ‘t’ and not ‘i18n’. I will take a look at this in two weeks or so. There might be some downsides that I haven’t considered.
Both versions below do indeed work, though I wish there was a shorter way to do a memoized string-only translation:
@vonovak For me depending on the
i18nin the context will not trigger the lazy translation to be changed once the locale is changed. It only works if I addi18n.localeto the dependency array as stated in this reply. But indeed it breaks eslint rules: “exhaustive-deps”.