diff --git a/__tests__/useTranslation.test.js b/__tests__/useTranslation.test.js
index adcd3ac..e19e093 100644
--- a/__tests__/useTranslation.test.js
+++ b/__tests__/useTranslation.test.js
@@ -1,4 +1,4 @@
-import React, { useState } from 'react'
+import React, { useEffect, useState } from 'react'
import { render, cleanup, fireEvent } from '@testing-library/react'
import I18nProvider from '../src/I18nProvider'
import useTranslation from '../src/useTranslation'
@@ -1549,5 +1549,33 @@ describe('useTranslation', () => {
const { container } = render()
expect(container.textContent).toContain(expected)
})
+
+ test('`t` is stable', () => {
+ const Inner = ({ effect }) => {
+ const { t } = useTranslation()
+
+ useEffect(() => {
+ const text = t('ns:interpolation', {
+ count: 3,
+ })
+ effect(text)
+ }, [effect, t])
+ }
+
+ globalThis.__NEXT_TRANSLATE__ = {
+ namespaces: {
+ ns: {
+ interpolation: 'There are {{count}} cats.',
+ },
+ },
+ lang: 'en',
+ config: {},
+ }
+
+ const effect = jest.fn()
+ const { rerender } = render()
+ rerender()
+ expect(effect).toBeCalledTimes(1)
+ })
})
})
diff --git a/package.json b/package.json
index bd8e084..8c9d11d 100644
--- a/package.json
+++ b/package.json
@@ -48,7 +48,7 @@
"scripts": {
"build": "yarn clean && cross-env NODE_ENV=production && yarn tsc",
"clean": "yarn clean:build && yarn clean:examples",
- "clean:build": "del lib appWith* Dynamic* I18n* index context loadNa* setLang* Trans* useT* withT* getP* getC* *.d.ts getT transC* wrapT* types formatElements AppDirI18nProvider* createTrans*",
+ "clean:build": "del lib appWith* Dynamic* I18n* index context loadNa* setLang* Trans* useT* withT* getP* getC* *.d.ts getT transC* wrapT* types formatElements isServer AppDirI18nProvider* createTrans*",
"clean:examples": "del examples/**/.next examples/**/node_modules examples/**/yarn.lock",
"example": "yarn example:complex",
"example:basic": "yarn build && yarn --cwd examples/basic && yarn --cwd examples/basic dev",
diff --git a/src/createTranslation.tsx b/src/createTranslation.tsx
index 8509903..1197f57 100644
--- a/src/createTranslation.tsx
+++ b/src/createTranslation.tsx
@@ -1,3 +1,5 @@
+import { useMemo } from 'react'
+import isServer from './isServer'
import transCore from './transCore'
import wrapTWithDefaultNs from './wrapTWithDefaultNs'
@@ -6,12 +8,17 @@ export default function createTranslation(defaultNS?: string) {
const { lang, namespaces, config } = globalThis.__NEXT_TRANSLATE__ ?? {}
const localesToIgnore = config.localesToIgnore || ['default']
const ignoreLang = !lang || localesToIgnore.includes(lang)
- const t = transCore({
- config,
- allNamespaces: namespaces,
- pluralRules: new Intl.PluralRules(ignoreLang ? undefined : lang),
- lang,
- })
+ const getT = () => {
+ const t = transCore({
+ config,
+ allNamespaces: namespaces,
+ pluralRules: new Intl.PluralRules(ignoreLang ? undefined : lang),
+ lang,
+ })
- return { t: wrapTWithDefaultNs(t, defaultNS), lang }
+ return wrapTWithDefaultNs(t, defaultNS)
+ }
+
+ const t = isServer() ? getT() : useMemo(getT, [defaultNS])
+ return { t, lang }
}
diff --git a/src/isServer.tsx b/src/isServer.tsx
new file mode 100644
index 0000000..dfd4c73
--- /dev/null
+++ b/src/isServer.tsx
@@ -0,0 +1,3 @@
+export default function isServer() {
+ return typeof window === 'undefined'
+}