我如何将缺失的翻译变成编译时的 TypeScript 错误

发布: (2026年3月5日 GMT+8 02:18)
4 分钟阅读
原文: Dev.to

Source: Dev.to

运行时缺失翻译的问题

大多数 React i18n 库只在运行时捕获缺失的翻译,导致用户在开发者注意之前就看到破碎的 UI。

使用基于键的库(如 react‑i18next)的示例:

const { t } = useTranslation();

return {t("welcome.message")};
// en.json
{
  "welcome": {
    "message": "Welcome back!"
  }
}

// es.json
{
  "welcome": {}
  // oops – forgot this one
}

TypeScript 无法知道 es.json 中缺少 "welcome.message"。西班牙语用户会看到原始键字符串,问题只有在切换语言时才会显现。有些库提供键映射的代码生成,但这会增加构建步骤,并且只能保证键的存在,无法保证实际内容。


编译时解决方案:react-scoped-i18n

react-scoped-i18n 不使用引用外部文件的字符串键,而是直接将翻译作为普通对象字面量传递给 t() 函数:

const { t } = useI18n();

return (
  {t({
    en: `Welcome back, ${name}!`,
    es: `¡Bienvenido de nuevo, ${name}!`,
  })}
);

参数是普通对象,TypeScript 可以对其进行完整的类型检查。


设置 Provider

一次性创建 i18n 配置:

// i18n/index.ts
import { createI18n } from "react-scoped-i18n";

export const { useI18n, I18nProvider } = createI18n({
  languages: ["en", "es", "sl"],
  defaultLanguage: "en",
});

createI18n 会根据 languages 数组生成类型:

type Language = "en" | "es" | "sl";
type Translations = Record;

t() 函数期望一个 Translations 对象,这意味着 每个语言键都必须存在。遗漏任意语言会触发 TypeScript 错误:

return (
  {t({
    en: `Welcome back, ${name}!`,
    es: `¡Bienvenido de nuevo, ${name}!`,
    // TypeScript Error: Property 'sl' is missing in type
    // '{ en: string; es: string; }' but required in type 'Translations'
  })}
);

无需代码生成、构建步骤或插件——类型约束直接来源于你的配置。


处理复数形式

复数形式使用 tPlural() 管理,同样要求每种语言的完整性:

const { tPlural } = useI18n();

return (
  {tPlural(count, {
    en: {
      one: `You have one apple.`,
      many: `You have ${count} apples.`,
    },
    es: {
      one: `Tienes una manzana.`,
      many: `Tienes ${count} manzanas.`,
    },
    sl: {
      one: `Imaš eno jabolko.`,
      two: `Imaš dve jabolki.`, // Slovenian dual form
      many: `Imaš ${count} jabolk.`,
    },
  })}
);

在类型层面,所有可能的类别(negative、zero、one、two、many 等)对每种语言都是可用的;你只需定义实际需要的形式。这使得支持双数、六元复数或其他复杂复数规则的语言时,无需硬编码。


权衡与适用场景

  • 优点

    • 编译时保证每个受支持语言都有对应的翻译。
    • 无需外部代码生成或构建时工具。
    • 编写组件时即可获得即时反馈。
  • 缺点

    • 内联翻译不适合依赖外部翻译平台(Crowdin、Lokalise 等)的工作流。
    • 随着支持语言数量的增加,组件文件会变得更大、更嘈杂。三到五种语言还算舒适,十种就会显得沉重。

对于自行维护翻译的小团队来说,这种权衡通常是值得的。


试一试

react-scoped-i18n 是开源项目,代码托管在 GitHub:

react-scoped-i18n on GitHub

0 浏览
Back to Blog

相关文章

阅读更多 »