i18n.exists reports false even if the translation exists.
🐛 Bug Report
I noticed that i18n.exists can report false even if the key exists and the t function correctly translates the value.
This breaks the rare use case where a React component can accept either a translation key or a string.
To Reproduce
Code Sandbox https://codesandbox.io/p/devbox/pedantic-haibt-f843tj
Check the console. I noticed that this only happens if the key is in a translation file that is loaded async.
console.log({
exists: i18n.exists("select.classification.BAR"),
value: t("select.classification.BAR"),
});
-> {exists: false, value: 'Bar'}
Expected behavior
The return value of the exists function should also resolve if the t function resolves to a valid key.
{exists: true, value: 'Bar'}
Your Environment
- runtime version: node 22, CodeSandbox as well.
- i18next version: 25.4.2, react-18next: 15.7.3
- os: Mac
const { t, i18n } = useTranslation("form"); binds the t function to the namespace form
i18n.exists is a function on i18next - it does not know about the namespace (not bound)
either use i18n.exists("form:select.classification.BAR") or i18n.exists("select.classification.BAR", { ns: 'form' })
Thank you for the quick reply.
What is the reason that i18n is not bound in this case? This is not intuitive since the i18n object is returned from the useTranslation function that has a namespace as its first agument. As a developer I would expect that it was at least considering this namespace.
because it's the one singleton raw unmutated i18n instance you passed in...you can't bind that to a namespace
Could you add a note to the docs to clarify that only the t function is bound to the namespace but not the i18n object?
Alternatively it should be possible bind the exists function of the returned i18n object of useTranslation to the namespace (e.g. with a proxy).
Could you add a note to the docs to clarify that only the t function is bound to the namespace but not the i18n object?
I updated the react-i18next docs to add the note clarifying that only the returned t is namespace-bound: https://react.i18next.com/latest/usetranslation-hook#usetranslation-params
So far no one else has requested exists() to be bound.
Alternatively it should be possible bind the exists function of the returned i18n object of useTranslation to the namespace (e.g. with a proxy).
You could implement a proxy that wraps i18n and auto-injects ns for selected methods, but it’s not recommended as a library-level change. i18n exposes many methods with different argument shapes and side-effects, so a proxy risks surprising/fragile behavior and subtle bugs.