i18next:调用getFixedT函数时未找到匹配的重载。

huangapple go评论69阅读模式
英文:

i18next: No overload matches this call when calling getFixedT function

问题

我在TS应用程序中使用i18next库(不是React),并遇到了一个意外的Typescript错误。

在调用getFixedT函数时,出现了类型不匹配的错误。我为lngns都传递了字符串,但却收到期望null的错误。

复现步骤

我在i18next.d.ts中有以下类型定义:

// i18next.d.ts
import "i18next";
import definitions from "../i18n/locales/definitions/en.json";
import errors from "../i18n/locales/errors/en.json";

const NAMESPACES = {
  definitions: "definitions",
  errors: "errors",
};

declare module "i18next" {
  interface CustomTypeOptions {
    ns: typeof NAMESPACES.errors | typeof NAMESPACES.definitions;
    returnNull: false;
    resources: {
      en: {
        definitions: typeof definitions;
        errors: typeof errors;
      }
    };
  }
}

我的资源文件按命名空间定义,如下:

// src/i18n/locales/resources.ts
import definitions_de from './definitions/de.json';
import definitions_en from './definitions/en.json';
import errors_de from './errors/de.json';
import errors_en from './errors/en.json';

export const resources = {
  de: {
    definitions: definitions_de,
    errors: errors_de,
  },
  en: {
    definitions: definitions_en,
    errors: errors_en,
  },
  // <etc>
}

我在此处初始化i18nInstance并导出它:

// src/i18n/index.ts
import i18n, { createInstance, InitOptions } from 'i18next';
import { fallbackLng, NAMESPACES } from '../constants';
import { resources } from './locales/resources';

const i18nInstance = createInstance();

void i18nInstance
  .init({
    fallbackLng, // use en if detected language is not available
    defaultNS: NAMESPACES.errors,
    resources,
    load: 'currentOnly', // only load the detected language
    ns: [NAMESPACES.definitions, NAMESPACES.errors], // namespaces
    saveMissing: true, // send not translated keys to endpoint
    returnNull: false,
  } as InitOptions);

export default i18nInstance;

在我的代码中,我调用getFixedT函数如下:

const locale = "en";
const t = i18nInstance.getFixedT(locale, NAMESPACES.errors)

t("path.to.definition", { variable: "value" });

我收到以下ts错误:

No overload matches this call.
  Overload 1 of 2, '(lng: null, ns: Namespace<"en"> | null, keyPrefix?: KeyPrefix<Namespace<"en">>): TFunction<Namespace<"en">, KeyPrefix<Namespace<"en">>, Namespace<...>>', gave the following error.
    Argument of type 'Locale' is not assignable to parameter of type 'null'.
      Type '"de"' is not assignable to type 'null'.
  Overload 2 of 2, '(lng: string | readonly string[], ns?: Namespace<"en"> | null | undefined, keyPrefix?: undefined): TFunction<Namespace<"en">, undefined, Namespace<"en">>', gave the following error.
    Argument of type 'string' is not assignable to parameter of type 'Namespace<"en"> | null | undefined'.ts(2769)
  • i18next版本: ^22.4.9
  • 操作系统: Mac
英文:

I'm using the i18next library in a TS app (not React) and getting an unexpected Typescript error.

I'm getting a type mismatch when calling the getFixedT function. I'm passing strings for both lng and ns, yet getting errors expecting null.

To Reproduce

I have the following type definition in i18next.d.ts:

// i18next.d.ts
import &quot;i18next&quot;;
import definitions from &quot;../i18n/locales/definitions/en.json&quot;;
import errors from &quot;../i18n/locales/errors/en.json&quot;;

const NAMESPACES = {
  definitions: &quot;definitions&quot;,
  errors: &quot;errors&quot;,
};

declare module &quot;i18next&quot; {
	interface CustomTypeOptions {
		ns: typeof NAMESPACES.errors | typeof NAMESPACES.definitions;
		returnNull: false;
		resources: {
			en: {
				definitions: typeof definitions;
				errors: typeof errors;
			}
		};
	}
}

My resource files are defined by namespace, like so:

// src/i18n/locales/resources.ts
import definitions_de from &#39;./definitions/de.json&#39;;
import definitions_en from &#39;./definitions/en.json&#39;;
import errors_de from &#39;./errors/de.json&#39;;
import errors_en from &#39;./errors/en.json&#39;;

export const resources = {
	de: {
		definitions: definitions_de,
		errors: errors_de,
	},
	en: {
		definitions: definitions_en,
		errors: errors_en,
	},
        // &lt;etc&gt;
}

I init i18nInstance and export it here:

// src/i18n/index.ts
import i18n, { createInstance, InitOptions } from &#39;i18next&#39;;
import { fallbackLng, NAMESPACES } from &#39;../constants&#39;;
import { resources } from &#39;./locales/resources&#39;;

const i18nInstance = createInstance();

void i18nInstance
	.init({
		fallbackLng, // use en if detected language is not available
		defaultNS: NAMESPACES.errors,
		resources,
		load: &#39;currentOnly&#39;, // only load the detected language
		ns: [NAMESPACES.definitions, NAMESPACES.errors], // namespaces
		saveMissing: true, // send not translated keys to endpoint
		returnNull: false,
	} as InitOptions);

export default i18nInstance;

In my code, I'm calling the getFixedT function likes so:

const locale = &quot;en&quot;;
const t = i18nInstance.getFixedT(locale, NAMESPACES.errors)

t(&quot;path.to.definition&quot;, { variable: &quot;value&quot; });

I get the following ts error:

No overload matches this call.
  Overload 1 of 2, &#39;(lng: null, ns: Namespace&lt;&quot;en&quot;&gt; | null, keyPrefix?: KeyPrefix&lt;Namespace&lt;&quot;en&quot;&gt;&gt;): TFunction&lt;Namespace&lt;&quot;en&quot;&gt;, KeyPrefix&lt;Namespace&lt;&quot;en&quot;&gt;&gt;, Namespace&lt;...&gt;&gt;&#39;, gave the following error.
    Argument of type &#39;Locale&#39; is not assignable to parameter of type &#39;null&#39;.
      Type &#39;&quot;de&quot;&#39; is not assignable to type &#39;null&#39;.
  Overload 2 of 2, &#39;(lng: string | readonly string[], ns?: Namespace&lt;&quot;en&quot;&gt; | null | undefined, keyPrefix?: undefined): TFunction&lt;Namespace&lt;&quot;en&quot;&gt;, undefined, Namespace&lt;&quot;en&quot;&gt;&gt;&#39;, gave the following error.
    Argument of type &#39;string&#39; is not assignable to parameter of type &#39;Namespace&lt;&quot;en&quot;&gt; | null | undefined&#39;.ts(2769)
  • i18next version: ^22.4.9
  • os: Mac

答案1

得分: 2

我能够重现您的问题,并找到了2个问题以及一个解决方案 😊

首先,根据https://www.i18next.com/overview/typescript的说法,resources应该只包含命名空间(不包裹在语言代码中)。例如,您可以使用您的resources.ts,并进行以下更改:

declare module "i18next" {
    interface CustomTypeOptions {
        // 我移除了 `ns`,因为它在 i18n 中不受支持
        returnNull: false;
        resources: typeof resources['en']; // 等同于 typeof { definitions: {...}, errors: {...} }
    }
}

在进行上述更改后,我得到了这个错误:

参数的类型 'string' 不能赋值给类型 'Namespace<"definitions" | "errors"> | null | undefined'.ts(2769)

剩下的问题是TypeScript不能推断出您的命名空间键的类型(每个键都被视为普通字符串,而不是字面值)。我们可以通过as const修复这个问题:

// 使用 as const
export const NAMESPACES = {
  definitions: "definitions",
  errors: "errors",
} as const;
英文:

I was able to reproduce your issue and found 2 problems, and a solution 🙃

> Namespace<"en"> | null | undefined

First, according to https://www.i18next.com/overview/typescript, resources should contain just the namespaces (without wrapping them in language code). For example, you can use your resources.ts, and do:

declare module &quot;i18next&quot; {
interface CustomTypeOptions {
// I removed `ns`, as it is not supported in i18n
returnNull: false;
resources: typeof resources[&#39;en&#39;]; // equivalent of typeof { definitions: {...}, errors: {...} }
}
}

After above change, I got this error:
> Argument of type 'string' is not assignable to parameter of type '`Namespace<"definitions" | "errors"> | null | undefined'.ts(2769)

Remaining problem is that TypeScript can not infer the type of your namespace keys (each key was treated as a plain string, instead of a literal value). We can fix that with as const:

// As const
export const NAMESPACES = {
definitions: &quot;definitions&quot;,
errors: &quot;errors&quot;,
} as const;

huangapple
  • 本文由 发表于 2023年3月7日 11:18:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/75657744.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定