无法与react-i18next一起使用类型安全(CustomTypeOptions)

问题描述 投票:0回答:2

我最近成功地使用react-18next 实现了我的应用程序内的本地化需求。我有一个小包,其中包含本地化文件、react-i18next 设置,并导出另一个应用程序中引用的类以获取 i18n 实例并将其传递给包装我的组件的类。

这已部署并按预期工作。

我偶然发现了这里的文档(https://react.i18next.com/latest/typescript#create-a-declaration-file),它说你能够使 t 函数完全类型安全。我很想实现这个,这样我就能够在编译时捕获不匹配的关键错误,而不是需要在应用程序中寻找每个案例。

不过,我在实现这种所需的类型安全方面遇到了一些麻烦,并且不确定这是否是我做错了,或者可能是打字中的错误(我假设是前者,因为其他人似乎没有任何问题就可以安全工作) ).

版本:

  • react-i18next“^11.15.6”
  • i18next“^21.6.14”
  • 反应“16.14.0”
  • 打字稿4.1+

Repo 结构(不包括 package.json、tsconfig.json 等):

  • 源代码
    • 翻译
      • translations_en.json
      • translations_es.json
    • MyTranslationManager.ts
    • react-i18next.d.ts

翻译文件不使用任何嵌套字符串,并按语言分隔(“_en”与“_es”)。每种语言都有其本地化格式的所有所需字符串。文件格式如下:

{
  "string1": "First string",
  "string2": "Second string"
}

在我的实时(工作)设置中,这就是我初始化实例的方式:

import translationEN from "./translations/translations_en.json";

export class MyTranslationManager {
  private readonly i18nInstance: i18nType;
  constructor() {
        this.i18nInstance = i18n.createInstance();

        const defaultResources = {
            en: { translation: { ...translationEN } },
        };

        this.language = "en";

        this.i18nInstance
            .use(initReactI18next)
            .init({
                resources: defaultResources,
                lng: "en",
                keySeparator: false, // we do not use nested translation resources
                interpolation: {
                    escapeValue: false, // React already prevents XSS
                },
            });
}

// 致力于类型安全

按照文档中的指示,我创建一个react-i18next.d.s 文件来重新声明“react-i18next”模块 - 特别是 CustomTypeOptions 接口:

import "react-i18next";
import translationEN from "./translations/translations_en.json";

declare module "react-i18next" {
    interface CustomTypeOptions {
        resources: typeof translationEN;
    }
}

我没有为 CustomTypeOptions 声明“defaultNS”选项,因为我依赖于默认命名空间“translation”。

当我尝试使用上述代码编译项目时,出现以下 TS2344 问题:

node_modules/react-i18next/ts4.1/index.d.ts:203:25 - error TS2344:
Type 'string' does not satisfy the constraint 'Namespace<"btn_cancel" | "btn_save" | ... 86 more ... | "msg_unsavedChanges">'.

203   N extends Namespace = DefaultNamespace,

react-i18next/ts4.1/index.d.ts 中尝试设置 Namespace = DefaultNamespace 的每一行都会抛出错误。

我将index.d.ts中尽可能多的代码复制到Typescript Playground中,尝试深入了解这里发生的情况,并且我能够重现编译错误。

将鼠标悬停在 Typescript 游乐场中的以下项目上可以提供一些有趣的见解:

  • DefaultResources 将解析为 { “btn_cancel”: string; “btn_ok”:字符串; }
  • DefaultNamespace 将解析为“ type DefaultNamespace = T extends "btn_cancel" | “btn_ok”? T:字符串“
    • 我假设这是通过使用 Fallback 类型来设置的,该类型通过 keyof 从 DefaultResources 传入每个键...

链接到游乐场。

我的问题是,为什么语言文件的键被设置为命名空间?这是设计使然吗?我是否以错误的方式导入资源?

我注意到这里的示例(https://github.com/i18next/react-i18next/blob/master/example/react-typescript4.1/no-namespaces/%40types/react-i18next/index.d。 ts)仅显示文档指向的旧版本,即使用 DefaultResources 类型而不是 CustomTypeOptions。任何关于使用没有命名空间的新方法的指导将不胜感激:)

reactjs i18next react-i18next
2个回答
0
投票

对于任何使用

[email protected]
[email protected]
的人来说,遵循此处的文档对我来说是成功的(截至发布本文时):

https://www.i18next.com/overview/typescript

我现在正在

t()
函数中获取翻译类型


0
投票

我经常遇到这个问题,因此我创建了一个非常轻量级的包,旨在确保 100% 类型安全的国际化。随意使用它。访问我的

i18n-type-safe
GitHub 存储库。 按照简单的设置说明进行操作。你就一切准备就绪了!

© www.soinside.com 2019 - 2024. All rights reserved.