diff --git a/packages/react/src/I18nProvider.test.tsx b/packages/react/src/I18nProvider.test.tsx
index 0ba70bb62..f22df660c 100644
--- a/packages/react/src/I18nProvider.test.tsx
+++ b/packages/react/src/I18nProvider.test.tsx
@@ -3,7 +3,7 @@ import { act, render } from "@testing-library/react"
import { I18nProvider, useLingui } from "./I18nProvider"
import { I18n, setupI18n } from "@lingui/core"
-import { useMemo } from "react"
+import { useMemo, useCallback } from "react"
describe("I18nProvider", () => {
it(
@@ -226,4 +226,40 @@ describe("I18nProvider", () => {
expect(getByText("Ahoj světe")).toBeTruthy()
})
+
+ it("keeps memoized useLingui().i18n locale in sync on locale change", () => {
+ const i18n = setupI18n({
+ locale: "en",
+ messages: {
+ en: {},
+ cs: {},
+ },
+ })
+
+ const ComponentWithMemoizedI18n = () => {
+ const { i18n } = useLingui()
+
+ const getLocale = useCallback(
+ (i18nInstance: I18n) => i18nInstance.locale,
+ [],
+ )
+ const currentLocale = useMemo(() => getLocale(i18n), [getLocale, i18n])
+
+ return
{currentLocale}
+ }
+
+ const { getByTestId } = render(
+
+
+ ,
+ )
+
+ expect(getByTestId("locale").textContent).toBe("en")
+
+ act(() => {
+ i18n.activate("cs")
+ })
+
+ expect(getByTestId("locale").textContent).toBe("cs")
+ })
})
diff --git a/packages/react/src/I18nProvider.tsx b/packages/react/src/I18nProvider.tsx
index a8e3b5791..142e77f42 100644
--- a/packages/react/src/I18nProvider.tsx
+++ b/packages/react/src/I18nProvider.tsx
@@ -54,17 +54,20 @@ export const I18nProvider = ({
* of creating a separate Provider/Consumer pair.
*
* We can't use useMemo hook either, because we want to recalculate value manually.
+ *
+ * We wrap `i18n` in a Proxy to create a new reference on each context update.
+ * This ensures React correctly invalidates memoized values that depend on `i18n`.
*/
const makeContext = useCallback(
() => ({
- i18n,
+ i18n: new Proxy(i18n, {}),
defaultComponent,
_: i18n.t.bind(i18n),
}),
[i18n, defaultComponent],
)
- const [context, setContext] = useState(makeContext())
+ const [context, setContext] = useState(makeContext)
/**
* Subscribe for locale/message changes