react-i18next: TS error with multiple namespace when passing the namespace as an option to t

🐛 Bug Report

I am referring to this comment:

https://github.com/i18next/react-i18next/issues/1396#issuecomment-961345092

@pedrodurek have you updated the TS docs to reflect that? I don’t see any reference to that.

Also, I have a similar but slightly different scenario than on #1396 , and I want to know if it is supposed to be supported or not.

function App() {
  const { t } = useTranslation();
  return (
    <div className="App">
        <p>{t("key.on.ns1")}</p> {/*No TS error */}
        <p>{t("otherKey.present.inNs2", { ns: "ns2" })}</p> {/* TS error */}
    </div>
  );
}

As you can see, if I don’t provide the namespace the tFunction is not able to understand that in the second case it should compare against the keys of ns2 and it fails, because it only compares agains keys on ns1. I can workaround this using to different t functions configuring each one for each namespace, so this works fine:

function App() {
  const { t } = useTranslation();
  const { t:t2 } = useTranslation('ns2');
  return (
    <div className="App">
        <p>{t("key.on.ns1")}</p> {/*No TS error */}
        <p>{t("otherKey.present.inNs2")}</p> {/*No TS error */}
    </div>
  );
}

To my understanding, and reading the docs, if you don’t provide any namespace to the useTranslation function you can access any namespace using the { ns } option, but seems that such feature does not apply to TS?

Also, I see that is it not possible to provide more than one namespace and then use the { ns } option. If you provide two namespaces like useTranslation(['ns1','ns2']) the only way to use a namespace is with t('ns2:theKey'). Anything else will not typecheck. Is that expected?

Your Environment

  • runtime version: browser
  • i18next version: 11.14.3
  • os: Mac
  • TS: 4.4.4

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 10
  • Comments: 28 (5 by maintainers)

Most upvoted comments

Same issue here, the TS type-safe feature should be updated

example:

const { t } = useTranslation(['common', 'home'])

t('key') 
// ❌ TS error: No overload matches this call (but the 'common' namespace should be applied here by default)

t('common:key') 
// ✅ works fine

t('key', { ns: 'common' }) 
// ❌ the key 'common' should be type-safe, but it doesn't
// ❌ 'key' still has "No overload matches this call" error

@pedrodurek I know you are good in this type of issues 😉

this. Also should support the fact that the first element in array is the default type so we only specify the namespace for the second namespace.

I agree with both of you…use what ever suits you best…that’s the flexibility i18next likes to give.

But - my personal preference - is not using natural language for keys out of following reasons:

  • the long text like keys are added to every JSON in every language (bigger file sizes are the result)
  • text in keys are hard to be changed afterwards (typos, postediting by linguists, …)
  • using proper translation management software the keys are not really relevant for translators

In general the complete signature calls for the t function have been updated…t(‘key’, { ns: ‘app’ }) and t(‘app:key’) should both work

https://github.com/i18next/i18next/blob/master/test/typescript/custom-types/t.test.ts#L40

Have you tried with the new i18next and react-i18next versions? https://www.i18next.com/overview/typescript

I found a possible solution that’s working fine with react-i18next v11.

useTranslation expects ns?: N | Readonly<N>, so using as const will do the trick and namespace will be inferred correctly.

// ❌ Inferred namespace is ("ns1" | "ns2")[]
const { t } = useTranslation(['ns1', 'ns2']);
t('ns1:key.on.ns1');
t('ns2:otherKey.present.inNs2');

// ✅ Inferred namespace is Namespace<"ns1" | "ns2">
const { t } = useTranslation(['ns1', 'ns2'] as const);
t('ns1:key.on.ns1');
t('ns2:otherKey.present.inNs2');

I have similar errors.

The access via “notification:” is not found with Typescript but is working.

 // Error no overload matched
 t("notification:error:loginFailed");

“typescript”: “^4.6.3” “react-i18next”: “^11.16.2”,

import commonEN from "./en/common.json";
import notificationEN from "./de/notification.json";
import commonDE from "./de/common.json";
import notificationDE from "./de/notification.json";

export const defaultNS = "common";
export const resources = {
   en: {
      common: commonEN,
      notification: notificationEN,
   },
   de: {
      common: commonDE,
      notification: notificationDE,
   },
} as const;
import "react-i18next";
import { defaultNS, resources } from "../../i18n/config";

declare module "react-i18next" {
   interface CustomTypeOptions {
      defaultNS: typeof defaultNS;
      resources: typeof resources["de"];
   }
}

image

I think “notifications” should be listed too, but is not the case…

Quite aggressive stale bot… Can this be unflagged?

Hello @pedrodurek , I got that option from this places: https://react.i18next.com/latest/usetranslation-hook#loading-namespaces https://react.i18next.com/guides/multiple-translation-files

And I think some other place I don’t remember