作者:
    Creation:2026-06-14Last update:2026-06-29

    New Intlayer v9 - What's new?

    Welcome to Intlayer v9! This major release marks a huge milestone in simplifying the migration path to Intlayer with Compat Adapter Packages for major i18n libraries (react-i18next, next-intl, vue-i18n, etc.) and adds support for rich content structures: Collections and Variants.

    Table of contents


    Compat Adapter Packages

    Migrating to Intlayer from popular i18n libraries is now easier than ever. We have created five compat packages that expose the exact same public APIs as standard i18n libraries but delegate all translation work to Intlayer at runtime.

    Expose Same Public API with Strict Typing

    By replacing imports, you get all the benefits of Intlayer (including compile-time type safety against your actual dictionaries) with minimal code changes:

    • @intlayer/i18next
    • @intlayer/react-i18next
    • @intlayer/next-intl
    • @intlayer/react-intl
    • @intlayer/next-i18next
    • @intlayer/vue-i18n
    • @intlayer/lingui

    For example, simply change:

    ts
    import { useTranslation } from "react-i18next";

    to:

    ts
    import { useTranslation } from "@intlayer/react-i18next";

    Your keys will now be strictly typed against your Intlayer dictionaries, offering full dot-path auto-completion in your IDE!

    Bundler Alias Plugins (Vite, Next.js, Turbopack)

    To allow migrating without rewriting all your import statements manually, each compat adapter package includes a custom bundler plugin (Vite or Next.js) under the /plugin subpath.

    These plugins automatically rewrite existing imports (e.g. react-i18next or next-intl) to their @intlayer/* equivalents at build time.

    Next.js (Webpack / Turbopack) Example

    Instead of withIntlayer, wrap your Next.js configuration with the compat plugin:

    next.config.ts
    import { createNextI18nPlugin } from "@intlayer/next-i18next/plugin";import type { NextConfig } from "next";const withIntlayer = createNextI18nPlugin();const nextConfig: NextConfig = {};export default withIntlayer(nextConfig);

    Vite (React, Vue, Solid, Svelte) Example

    vite.config.ts
    import vueI18nVitePlugin from "@intlayer/vue-i18n/plugin";export default defineConfig({  plugins: [vueI18nVitePlugin()],});

    Mutualized Runtime Resolver

    All compat adapters now route translation resolution through a single, highly optimized runtime parser: @intlayer/core/messageFormat.

    • Interpolate Message: Resolves standard {{var}} (whitespace & dot-paths), ICU formatted args ({v, number, percent} etc.), and bare {var} templates.
    • Message Node Resolver: Resolves nested nodes: insert(), plural() (CLDR plural rules), enu() (enumeration), gender(), HTML tags, arrays, and callable function nodes.
    • Tokenized Tag Parser: Supports inline XML/HTML tags and numbered tags (e.g., <1>children</1>) to power rich-text rendering out of the box.

    Feature Spec: Collections & Variants

    Intlayer v9 expands beyond static key-value objects, allowing dictionaries to declare dynamic layout structures that are fully typed end-to-end.

    1. Collections

    Define a CMS-managed list of ordered items (e.g. FAQs, products, or blog lists):

    faq.1.content.ts
    import { t, type Dictionary } from "intlayer";export default {  key: "faq",  item: 1,  content: {    question: t({ en: "What is Intlayer?", fr: "Qu'est-ce qu'Intlayer ?" }),    answer: t({ en: "An i18n toolkit.", fr: "Une boîte à outils i18n." }),  },} satisfies Dictionary;
    faq.2.content.ts
    import { t, type Dictionary } from "intlayer";export default {  key: "faq",  item: 2,  content: {    question: t({ en: "Is it free?", fr: "Est-ce gratuit ?" }),    answer: t({ en: "Yes, open-source.", fr: "Oui, open-source." }),  },} satisfies Dictionary;

    Usage:

    ts
    // Fetch all items as an arrayconst allFaqs = useIntlayer("faq"); // -> { question: string, answer: string }[]// Fetch a single item by indexconst faq = useIntlayer("faq", { item: 2 }); // -> { question: string, answer: string }

    2. Variants

    Deliver A/B tests, seasonal headers, feature flags, or custom landing pages:

    String variants (e.g. A/B testing)

    hero.content.ts
    import { t, type Dictionary } from "intlayer";export default {  key: "hero-banner",  variant: "default",  content: {    control: t({ en: "Welcome", fr: "Bienvenue" }),    black_friday: t({ en: "Shop now", fr: "Acheter maintenant" }),  },} satisfies Dictionary;

    Usage:

    ts
    const banner = useIntlayer("hero-banner", { variant: "black_friday" });

    Object variants (e.g. Dynamic Records)

    product.content.ts
    import { t, type Dictionary } from "intlayer";export default {  key: "product-copy",  variant: {    id: "prod_123",    category: "books",  },  content: {    title: t({ en: "Clean Code", fr: "Code Propre" }),  },} satisfies Dictionary;

    Usage:

    ts
    // Fetches only the requested item dynamically (requires Suspense)const product = useIntlayer("product-copy", {  variant: { id: "prod_123", category: "books" },});

    Vite Plugin: 捆绑编译器和代理

    intlayer() Vite 插件现在直接捆绑了编译器区域设置路由代理,因此大多数项目只需在 vite.config.ts 中使用单个插件:

    vite.config.ts
    import { defineConfig } from "vite";import { intlayer } from "vite-intlayer";export default defineConfig({  plugins: [intlayer()],});
    • Compiler: 当 compiler.enabled 被设置为 true 且配置了 compiler.output 路径时,自动激活。您不再需要单独注册 intlayerCompiler()
    • Proxy: 根据新的 routing.enableProxy 选项自动激活(默认为 true)。它在开发、预览和生产 SSR 中连接区域设置检测 / 重定向 / 重写中间件。您不再需要单独注册 intlayerProxy()

    routing.enableProxy 选项

    新的 routing.enableProxy 选项控制是否启用区域语言路由代理。默认值为 true。当您想自己处理区域语言路由时,可以禁用它:

    intlayer.config.ts
    import type { IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  routing: {    enableProxy: false, // 默认值: true  },};export default config;

    独立的 intlayerCompiler()intlayerProxy() 插件仍然可用于高级设置。将它们与 intlayer() 一起注册是安全的 — 每个插件会自动去重并且仅运行一次。


    默认禁用编译器

    从 Intlayer v9 开始,编译器默认被禁用compiler.enabled 现在默认为 false)。要启用对 .content.ts 文件的构建时提取,请在配置中设置 compiler.enabled: true

    intlayer.config.ts
    import type { IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  compiler: {    enabled: true, // 默认值:false —— 自 v9 起启用编译器所必需    output: ({ fileName }) => `./${fileName}.content.ts`,  },};export default config;

    当编译器被禁用时,Intlayer 会跳过构建时提取步骤,并依赖您已声明的字典。仅当您希望打包器插件(@intlayer/swc@intlayer/babelintlayer() Vite 插件)自动提取内容时才启用它。


    React Native:单包导入

    在 React Native 或 Expo 应用中,您不再需要同时管理 react-intlayerreact-native-intlayerreact-native-intlayer 包现在重新导出了完整的 react-intlayer API(hooks、工具函数以及 /format/html/markdown 子路径),并且其 IntlayerProvider 会自动应用 React Native 的 polyfills。

    从单一的 react-native-intlayer 包中导入所有内容:

    tsx
    import {  IntlayerProvider,  useIntlayer,  useLocale,} from "react-native-intlayer";
    bash
    npm install intlayer react-native-intlayer
    react-intlayer 导入仍然有效,但现在推荐使用 react-native-intlayer 作为 React Native 的单一入口点 —— 它的 provider 提供了面向 web 的 react-intlayer provider 所不包含的 polyfills。

    CMS SDK:将 Intlayer 用作无头内容数据库

    Intlayer v9 在 @intlayer/api 中提供了一个简洁、自动鉴权的 SDK,用于以编程方式与 CMS 交互——获取项目、获取字典,以及从你自己的服务器、脚本或 CI 推送或更新它们。鉴权(OAuth2 client_credentials)会自动处理并刷新。

    SDK 拆分为两个独立的导入,因此你的打包产物只包含你实际使用的领域:

    1. createIntlayerCMS —— 一个轻量的鉴权器,持有凭据和受管理的令牌(不打包任何领域客户端)。
    2. dictionaryEndpointprojectEndpoint、… —— 按领域划分的端点绑定器,各自从其独立子路径导入。
    cms.ts
    import { createIntlayerCMS } from "@intlayer/api";import { dictionaryEndpoint } from "@intlayer/api/dictionary";// 配置是可选的:凭据会回退到 INTLAYER_CLIENT_ID /// INTLAYER_CLIENT_SECRET(由 `@intlayer/config/built` 解析)。const cms = createIntlayerCMS();// 读取const { data: dictionaries } = await dictionaryEndpoint(cms).getDictionaries();// 写入 —— 像数据库一样使用 CMSawait dictionaryEndpoint(cms).pushDictionaries([myDictionary]);
    安全:CMS 凭据授予对内容的写入权限。务必只在服务端创建鉴权器——切勿将 clientId / clientSecret 发送到浏览器。

    Migration notes from v8

    If you are upgrading from v8, note that the v9 does not include breaking changes. But here are the key changes:

    • 默认禁用编译器compiler.enabled 现在默认为 false。如果您依赖对 .content.ts 文件的构建时提取,请在 intlayer.config.ts 中设置 compiler.enabled: true
    • Locales & Dialects: If using external i18n dependencies, add their respective compat adapter plugins in your configuration or bundler setup to automatically rewrite imports.
    • Custom Selectors: When calling useIntlayer, the second parameter is now reserved for an option object containing { locale, item, variant }. If you previously passed a locale string directly, you can still do so, but using the options object is recommended for advanced selections.