本地化你的 React 应用的 Tailwind 方式:无需键值和 JSON,只用代码

发布: (2026年2月9日 GMT+8 01:47)
6 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的正文内容(除代码块和 URL 之外的文字),我将把它翻译成简体中文并保持原有的 Markdown 格式。

那么,你想本地化你的应用

大多数 i18n 方案会把你引向一种熟悉的模式:

  • 巨大的 JSON/YAML 文件
  • 通过键名繁琐地“命名”你的翻译
  • 虚构的字符串插值语法
  • 不断在 UI 代码和翻译文件之间来回切换

这虽然可行,但随着时间的推移,这种繁琐的流程会让人感到有些乏味。

我记得几年前,我第一次接触 Tailwind CSS 时,惊讶于只写必要内容后,我能够更快地交付真实的 UI。我希望在 i18n 上也能获得同样的体验。

介绍 react‑scoped‑i18n 🌐

核心思想很简单:不再使用全局翻译文件和键名,而是把翻译直接放在渲染它们的组件旁边。

i18n 通常是怎样的?

// en.json
{
  "profile": {
    "header": "Hello, {{name}}"
  }
}

// es.json
{
  "profile": {
    "header": "Hola, {{name}}"
  }
}
// Header.tsx
export const Header = () => {
  const { t } = useI18n();

  return (
    <h1>{t("profile.header", { name: "John" })}</h1>
  );
};

这种方法可行且经过实战检验,但也带来了一些痛点:

  • 没有额外工具时,TypeScript 并不能提供太多帮助。
  • 翻译键几乎不提供关于实际渲染内容的上下文。
  • 无法在代码库中搜索渲染的文本并直接找到使用它的组件。
  • 字符串插值使用自定义语法。

“scoped” 方法是什么样的?

// Header.tsx
export const Header = () => {
  const { t } = useI18n();

  const name = "John";

  return (
    <h1>{t({
      en: `Hello, ${name}`,
      es: `Hola, ${name}`,
    })}</h1>
  );
};

没有键,没有庞大的 JSON 文件,也没有自定义插值语法——只有纯代码!

注意: 这并不是要取代完整的 i18n 平台。它是为需要快速本地化的代码驱动应用提供的一种替代方案。

这种方法的最大好处

类型安全 🩵

因为它只是代码,所有内容都是类型安全的。

createI18nContext({
  languages: ["en", "es", "sl"],
  fallbackLanguage: "en", // inferred from `languages` above
});

如果缺少翻译,TypeScript 会在编译时提示:

// ❌ Property 'es' is missing in type { en: string; sl: string; }
t({
  en: "Hello",
  sl: "Pozdravljeni",
});

缺失的翻译或不支持的语言会成为编译时错误,而不是运行时的意外。 😄

不需要为键命名

内容本身就是键。搜索渲染后的文本会直接定位到对应的组件——极大提升开发体验。 😊

无额外构建步骤

该库在 React Context 生态系统中直接工作。安装后,初始化上下文,用导出的 Provider 包裹你的应用,即可使用。

开箱即用的数字、日期、时间和货币格式化 ‼️

react‑scoped‑i18n 利用原生 Intl API,只要使用标准的地区标识符(enen‑GBeses‑ES …),即可获得完整的格式化支持,无需额外配置。

类型安全的“共享”翻译

对于在整个应用中共享的字符串,请通过 commons API 定义它们:

createI18nContext({
  languages: ["en", "es"],
  fallbackLanguage: "en",
  commons: {
    continue: {
      en: "Continue",
      es: "Continuar",
    },
  },
});

然后以类型安全的方式使用它们,支持 IDE 自动完成:

{t(commons.continue)}

复数化(受 ICU 启发,但不严格遵循 ICU)

tPlural 允许每种语言仅定义它实际需要的类别。

{tPlural(count, {
  en: {
    one: `You have one apple.`,
    many: `You have ${count} apples.`,
  },
  sl: {
    one: `Imaš eno jabolko.`,
    two: `Imaš dve jabolki.`, // dual form in Slovenian
    many: `Imaš ${count} jabolk.`,
  },
})}

你也可以针对 ICU 类别之外的特定数值:

{tPlural(count, {
  en: {
    one: `You have one apple.`,
    many: `You have ${count} apples.`,
    42: `You have THE PERFECT amount of apples!`,
  },
  es: {
    one: `Tienes una manzana.`,
    many: `Tienes ${count} manzanas.`,
  },
})}

当这不是合适的选择

(继续你的原始内容……)

合适的情况

这种方法从设计上就是以开发者为中心的,因此如果你的工作流依赖于:

  • 外部翻译人员
  • “Crowdin”、 “Lokalise” 或类似工具
  • 非技术编辑者编辑翻译文件
  • 大量 支持的语言

那么这可能不是合适的方法。

但是如果翻译是以代码形式编写和维护的,并且你的支持语言数量是 中小规模,开发者体验会出乎意料地好。

如果你感兴趣,项目是开源的。你可以查看:

  • GitHub:
  • npm:

欢迎提供任何反馈!

0 浏览
Back to Blog

相关文章

阅读更多 »

React-测验应用

React Quiz App 🧠 该项目展示了对 React 基础、基于组件的架构以及高效状态管理的实践理解。Live demo...