Search code examples
typescriptnext.jsi18nextreact-i18nextnext-i18next

Using i18next with TypeScript: How to Support Prefixed Namespace Keys in the t Function


I am using i18next with typescript and generating resource types from JSON with translation resources with i18next-resources-for-ts. Everything works well, but I'm facing an issue when using prefixed namespaces with the t function from the useTranslation() hook. I am not looking for useTranslation('common') or t('auth.login.text', { ns: 'common' }), which works fine and is typed correctly.

Here's a simplified version of my i18next.d.ts:

import 'i18next';
import common from '../public/locales/en/common.json';

const resources = {
  common,
} as const;

declare module 'i18next' {
  interface CustomTypeOptions {
    returnNull: false;
    defaultNS: 'common';
    resources: typeof resources;
  }
}

and set up of i18next.ts

import commonDe from '../public/locales/de/common.json';
import commonEn from '../public/locales/de/common.json';
import i18next from 'i18next';
import { initReactI18next } from 'react-i18next';

const resources = {
  de: {
    common: commonDe,
  },
  en: {
    common: commonEn,
  },
};

export const defaultNS = 'common';

i18next
  .use(initReactI18next)
  .init({
    resources,
    ns: [defaultNS],
    defaultNS,
    lng: 'en',
    interpolation: {
      escapeValue: false,
    },
    returnNull: false,
  });

export default i18next;

The problem arises when attempting to use a prefixed namespace in the t function:

const { t } = useTranslations();
t('common:auth.login.text')

Then types doesn't work.

I know that I could specify ns as options for t function or select it already in useTranslation hook. But I would also like to support the prefixed way as above in the translation key.

Any suggestions or ideas on how to achieve this would be greatly appreciated. Thank you!


Solution

  • Thanks to @hokwanhung points I got to a working solution.

    As he perfectly described, my issue was in react-i18next. But in my case, I need to use useTranslations() with an array argument, simple string doesn't work.

    const { t } = useTranslation('common'); // doesn't enable keys with namespace prefixes in my case
    

    Working solution with settings in question:

    const { t } = useTranslation(['common']); // use array here
    t('common:auth.login.text'); // works fine now