Author:
    Creation:2026-06-14Last update:2026-06-14

    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, Variants, and Dynamic Records.

    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/next-i18next
    • @intlayer/vue-i18n

    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 optimised 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.
    • Tokenised 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 & Dynamic Records

    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.content.ts
    import { t, type Dictionary } from "intlayer";export default {  key: "faq",  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;

    Usage:

    ts
    // Fetch all itemsconst allFaqs = useIntlayer("faq"); // -> { question: string, answer: string }[]// Fetch single item by indexconst faq = useIntlayer("faq", { item: 1 }); // -> { question: string, answer: string }

    2. Variants

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

    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" });

    3. Dynamic Records

    Define dictionaries whose entries are loaded dynamically at runtime via query IDs:

    product.content.ts
    import { t, type Dictionary } from "intlayer";export default {  key: "product-copy",  meta: {    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", {  id: "prod_123",  category: "books",});

    Dynamic Loading & Bundle Size Optimisations

    To keep bundles extremely small, Intlayer v9 supports dynamic lazy loading.

    In your configuration, set importMode to 'dynamic' or 'fetch':

    intlayer.config.ts
    export default {  dictionary: {    importMode: "dynamic", // "static" | "dynamic" | "fetch"  },};

    At build time, @intlayer/swc and @intlayer/babel scan your files and replace useIntlayer / getIntlayer calls with tree-shakeable wrappers (useDictionary / useDictionaryDynamic). Only the content required for the selected collection item, variant, or locale is loaded, preventing your production bundle from containing unused translations.


    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:

    • 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, id }. If you previously passed a locale string directly, you can still do so, but using the options object is recommended for advanced selections.