作者:
    Creation:2026-08-23Last update:2026-08-30

    使用 Intlayer 翻译您的 Elysia 后端网站 | 国际化 (i18n)

    elysia-intlayer 是一个强大的国际化 (i18n) 插件,为 Elysia 应用程序设计,旨在通过根据客户端偏好提供本地化响应,使您的后端服务全球可访问。

    在 GitHub 上查看包实现

    实际应用场景

    • 用用户语言显示后端错误:当发生错误时,用用户的母语显示消息可以提高理解度并减少沮丧感。这对于可能在前端组件(如 toast 或模态框)中显示的动态错误消息特别有用。
    • 检索多语言内容:对于从数据库中提取内容的应用程序,国际化可确保您能够以多种语言提供此内容。这对于需要以用户偏好的语言显示产品描述、文章和其他内容的电子商务网站或内容管理系统等平台至关重要。
    • 发送多语言电子邮件:无论是交易电子邮件、营销活动还是通知,用收件人的语言发送电子邮件可以显著增加参与度和有效性。
    • 多语言推送通知:对于移动应用程序,用用户偏好的语言发送推送通知可以增强交互和保留。这种个人化的接触可以使通知感觉更相关和可操作。
    • 其他通信:来自后端的任何形式的通信(如短信消息、系统警报或用户界面更新)都受益于使用用户的语言,确保清晰性并增强整体用户体验。

    通过国际化后端,您的应用程序不仅尊重文化差异,而且更好地与全球市场需求相结合,这是在全球范围内扩展服务的关键步骤。

    快速开始

    ide.intlayer.org

    在 GitHub 上查看应用模板

    安装

    要开始使用 elysia-intlayer,请使用 npm 安装该包:

    bash
    npx intlayer init --interactive
    
    --interactive 标志是可选的。如果您是 AI 代理,请使用 intlayer-cli init
    此命令将检测您的环境并安装所需的包。例如:
    bash
    npm install intlayer elysia-intlayer
    
    Elysia 面向 Bun 运行时。elysia-intlayer 之所以依赖 AsyncLocalStorage(而不是基于 Node 的 Intlayer 插件所使用的 cls-hooked 库),正是因为 Bun 没有实现 async_hooks.createHook

    设置

    通过在项目根目录创建 intlayer.config.ts 来配置国际化设置:

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";
    
    const config: IntlayerConfig = {
      internationalization: {
        locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
        /**
         * 当找不到所请求的语言环境时,作为回退使用的默认语言环境。
         */
        defaultLocale: Locales.ENGLISH,
      },
    };
    
    export default config;
    

    声明您的内容

    创建和管理您的内容声明以存储翻译:

    src/index.content.ts
    import { t, type Dictionary } from "intlayer";
    
    const indexContent = {
      key: "index",
      content: {
        exampleOfContent: t({
          zh: "在中文中返回的内容示例",
          en: "Example of returned content in English",
          fr: "Exemple de contenu renvoyé en français",
          es: "Ejemplo de contenido devuelto en español",
        }),
      },
    } satisfies Dictionary;
    
    export default indexContent;
    
    您的内容声明可以在应用程序中的任何位置定义,只要它们包含在 contentDir 目录中(默认为 ./src)。并与内容声明文件扩展名匹配(默认为 .content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml})。
    有关更多详情,请参考 内容声明文档

    Elysia 应用设置

    设置您的 Elysia 应用以使用 elysia-intlayer

    src/index.ts
    import { Elysia } from "elysia";
    import { intlayer } from "elysia-intlayer";
    
    const app = new Elysia()
      // 加载国际化插件
      .use(intlayer())
      // 路由
      .get("/", ({ intlayer }) => ({
        // 用于此请求的语言环境,通过 `Accept-Language` 协商或从存储中读取
        locale: intlayer!.locale,
        greeting: intlayer!.t({
          zh: "你好",
          en: "Hello",
          fr: "Bonjour",
          es: "Hola",
        }),
        content: intlayer!.getIntlayer("index").exampleOfContent,
      }))
      .listen(3000);
    
    console.log(
      `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`
    );
    
    该插件通过 全局 derive 注册其上下文,Elysia 会将其类型标注为 Partial<{ intlayer: IntlayerContext }>。对于在 .use(intlayer()) 之后注册的路由,该值在运行时始终存在,因此请使用非空断言(intlayer!.locale)或可选链,以满足 strict 模式下的 TypeScript。

    路由上下文暴露以下内容:

    属性 描述
    locale 本次请求要使用的 locale,locale_storage 优先于 locale_detected
    locale_storage 客户端通过 cookie 或 header 显式请求的 locale。
    locale_detected 从请求头协商得到的 locale。
    defaultLocale intlayer.config.ts 中配置为 fallback 的 locale。
    t 翻译函数。
    getIntlayer 按 key 获取字典的函数。
    getDictionary 处理字典对象的函数。

    相同的辅助函数也以独立导出的形式提供。它们通过 AsyncLocalStorage 解析当前请求,因此你无需解构上下文即可调用:

    src/index.ts
    import { Elysia } from "elysia";
    import { intlayer, t, getDictionary, getIntlayer } from "elysia-intlayer";
    import dictionaryExample from "./index.content";
    
    const app = new Elysia()
      .use(intlayer())
      .get("/t_example", () =>
        t({
          zh: "在中文中返回的内容示例",
          en: "Example of returned content in English",
          fr: "Exemple de contenu renvoyé en français",
          es: "Ejemplo de contenido devuelto en español",
        })
      )
      .get("/getIntlayer_example", () => getIntlayer("index").exampleOfContent)
      .get(
        "/getDictionary_example",
        () => getDictionary(dictionaryExample).exampleOfContent
      )
      .listen(3000);
    
    请求上下文会在响应被映射后释放,因此独立的 helper 永远不会针对已经结束的请求进行解析。当在插件处理的请求之外调用时,它们会回退到配置的默认 locale。

    运行你的应用

    将 Intlayer 脚本添加到你的 package.jsonintlayer build 会将内容声明编译到 .intlayer 目录并生成 TypeScript 类型:

    package.json
    {
      "scripts": {
        "dev": "intlayer build && bun run --watch src/index.ts",
        "build": "intlayer build",
        "start": "bun run src/index.ts",
        "i18n:fill": "intlayer fill",
        "i18n:test": "intlayer test"
      }
    }
    

    然后启动服务器:

    bash
    bun run dev
    

    使用 Accept-Language 测试语言环境协商:

    bash
    curl -H "Accept-Language: fr" http://localhost:3000/
    # {"locale":"fr","greeting":"Bonjour","content":"Exemple de contenu renvoyé en français"}
    
    curl -H "Accept-Language: es" http://localhost:3000/
    # {"locale":"es","greeting":"Hola","content":"Ejemplo de contenido devuelto en español"}
    
    bun run src/index.ts 之前并非严格需要执行 intlayer build:插件在 Elysia 应用启动时也会准备字典。提前运行可以让生成的类型与你的编辑器保持同步,并避免首次请求时的构建开销。

    兼容性

    elysia-intlayer 完全兼容:

    它也能与各种环境中的任何国际化解决方案无缝协作,包括浏览器和 API 请求。

    默认情况下,插件按以下顺序解析语言环境:

    1. INTLAYER_LOCALE cookie。
    2. x-intlayer-locale 请求头。
    3. Accept-Language 请求头协商。

    你可以自定义用于语言环境检测的 cookie 和请求头:

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";
    
    const config: IntlayerConfig = {
      // ... 其他配置选项
      routing: {
        storage: [
          { type: "header", name: "my-locale-header" },
          { type: "cookie", name: "my-locale-cookie" },
        ],
      },
    };
    
    export default config;
    
    有关配置和高级主题的更多信息,请访问我们的文档

    配置 TypeScript

    elysia-intlayer 利用 TypeScript 的强大功能来增强国际化流程。TypeScript 的静态类型确保每个翻译键都被考虑到,降低了缺失翻译的风险,并提高了可维护性。

    确保自动生成的类型(默认位于 ./types/intlayer.d.ts)包含在你的 tsconfig.json 文件中。

    tsconfig.json
    {
      // ... 你现有的 TypeScript 配置
      "include": [
        // ... 你现有的 TypeScript 配置
        ".intlayer/**/*.ts", // 包含自动生成的类型
      ],
    }
    

    VS Code 扩展

    为了改进您使用 Intlayer 的开发体验,您可以安装官方的 Intlayer VS Code 扩展

    从 VS Code Marketplace 安装

    此扩展提供:

    • 自动完成翻译键。
    • 实时错误检测缺失的翻译。
    • 内联预览翻译内容。
    • 快速操作轻松创建和更新翻译。

    有关如何使用该扩展的更多详细信息,请参考 Intlayer VS Code 扩展文档

    Git 配置

    建议忽略 Intlayer 生成的文件。这样可以避免将它们提交到 Git 仓库。

    为此,你可以在 .gitignore 文件中添加以下说明:

    .gitignore
    # 忽略 Intlayer 生成的文件
    .intlayer
    

    常见问题

    Elysia 本身没有内置的 i18n 层,因此选择通常是:手动将诸如 i18next 之类的通用库接入钩子中,或者通过 elysia-intlayer 使用 Intlayerelysia-intlayer 会自动为您注册插件,按请求解析语言环境,并与前端共享相同的类型化内容。

    后端国际化的核心原因在于,用户阅读的大量文本并不经过前端:API 错误消息、事务性邮件、推送通知、短信以及导出的 PDF 文件。这些内容都需要根据接收者的语言进行解析,且应针对每个请求独立解析,而非按会话存储。

    请参阅 为什么选择 Intlayer

    极少。字典在构建前预先编译,仅包含您声明的语言环境,因此启动时无需加载整个大目录,处理请求路径时也无需读取文件系统。这在 Serverless 和 Edge 环境中尤为重要,因为体积直接决定冷启动耗时。请参阅 Bundle 体积优化

    可以,有两条迁移路径。您可以使用 i18next 迁移指南 逐步迁移内容。或者,您可以完全保留当前的 API:兼容性适配器 公开与 i18next 完全相同的 API,但底层由 Intlayer 字典驱动,因此只需更改导入语句,路由处理函数代码无需修改。

    可以。JSON 同步插件 将您的 /messages/{locale}/{namespace}.json 文件作为单一真实来源(source of truth),并双向生成 Intlayer 字典。PO 同步插件 对 gettext 目录执行相同的操作,而 按语言环境组织的文件 允许您按语言拆分内容,而不是将所有语言打包到一个文件中。

    不需要。运行 npx intlayer extract,Intlayer 会读取您的源码文件,提取面向用户的字符串,并在每个组件旁边生成 .content 文件,这样您只需审查 diff,而无需手动逐一复制字符串到语言目录中。请参阅 extract 命令

    在同一项目的前端部分,Intlayer Compiler 则更进一步,可以在构建时直接从 JSX、TSX、Vue 或 Svelte 源码生成字典,使应用的前后端共享同一套内容层,完全无需手动维护键名。

    共有 5 个工具,均为可选:

    • VS Code 扩展:从 useIntlayer 键跳转到声明它的内容文件,从组件中提取内容,并从命令面板或专属的 Intlayer 选项卡运行 build、fill、test、push 和 pull。
    • LSP 服务器:在任何支持 LSP 的编辑器中提供相同的感知能力,支持跳转到定义、查找所有引用、悬停预览翻译值、键和字段的自动补全,以及在键未声明时发出警告。它还可以解析 i18nextreact-i18nextnext-intluse-intl 调用,助力平滑迁移。
    • MCP 服务器:向 Cursor、VS Code、Claude Desktop、Claude Code 和 ChatGPT 公开 Intlayer 文档与 CLI,使 AI 助手能够基于最新文档进行准确回答,并能自行运行 intlayer fill 等命令。
    • Agent Skills:针对特定领域的技能(如 intlayer-configintlayer-cliintlayer-content,以及每个框架对应的专属技能),教导 AI 代理您的路由配置和内容节点类型。
    • ESLint 插件no-raw-text 规则标记硬编码字符串,并提供针对静态字典键和未使用内容的额外规则。