---
createdAt: 2025-09-22
updatedAt: 2026-01-26
title: New Intlayer v8 - What's new?
description: Discover what's new in Intlayer v8. Major improvements in developer experience, content validation, and dictionary management.
keywords:
  - Intlayer
  - CMS
  - Developer Experience
  - Features
  - React
  - Next.js
  - JavaScript
  - TypeScript
youtubeVideo: https://www.youtube.com/watch?v=ia6JmVf-kkU
slugs:
  - doc
  - releases
  - v8
---

# New Intlayer v8 - What's new?

Welcome to Intlayer v8! This release focuses on enhancing developer experience with automatic content detection, ensuring data integrity with schema validation, and providing more control over dictionary management.

<iframe
  src="https://www.youtube.com/embed/ia6JmVf-kkU"
  className="m-auto overflow-hidden rounded-lg border-0 max-md:size-full max-md:h-[700px] md:aspect-16/9 md:w-full"
  title="Demo Video - New Intlayer v8 - What's new?"
  sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
  loading="lazy"
/>

## Table of contents

<TOC levels={[2]} maxDepth={1} />

---

## Rich Content Evolution: Markdown & HTML

Intlayer v8 brings major improvements to how rich content is handled, introducing **HTML nodes** (which didn't exist in v7) and unifying the API with **Markdown nodes** (which existed in v7 but have been enhanced).

### The Unified `.use()` API

We introduced the `.use()` method for both Markdown and HTML nodes. This method allows you to customise the HTML tags or components used during rendering.

- **Component Replacement**: You can easily replace HTML tags or custom components with your own framework components (e.g., replace `<a>` with `NextLink` or `<CustomCmp>` with a React component).
- **Type Safety**: All functions for providing components are fully typed, ensuring you receive the correct props.

### Default Rendering Behaviour

In v7, if no provider was defined, Markdown nodes were rendered as raw strings, often requiring external libraries to parse them.

**In v8, Intlayer includes its own internal Markdown parser.** By default, Markdown nodes are now rendered directly as HTML without needing any external libraries.

### New Renderer & Provider Utilities

We have introduced new standalone renderer functions and components to give you more control outside of the standard `useIntlayer` flow.

- **Markdown**: `MarkdownRenderer`, `useMarkdownRenderer`, `renderMarkdown`. (Note: `MarkdownProvider` existed in v7 but now integrates with these new tools).
- **HTML**: `HTMLRenderer`, `useHTMLRenderer`, `renderHTML`, `HTMLProvider`.

#### Examples: Markdown Rendering Tools

<Tabs group='framework'>
  <Tab label="React / Next.js" value="react">

    **1. Using the Component:**

    ```tsx
    import { MarkdownRenderer } from "react-intlayer";

    <MarkdownRenderer
      forceBlock={true}
      components={{
        h1: ({ children }) => <h1 className="text-2xl">{children}</h1>
      }}
    >
      {"# My Title"}
    </MarkdownRenderer>
    ```

    **2. Using the Hook:**

    ```tsx
    import { useMarkdownRenderer } from "react-intlayer";

    const renderMarkdown = useMarkdownRenderer({
      components: {
        h1: ({ children }) => <h1 className="text-red-500">{children}</h1>
      }
    });

    return <div>{renderMarkdown("# My Title")}</div>;
    ```

    **3. Using the Utility Function:**

    ```tsx
    import { renderMarkdown } from "react-intlayer";

    const html = renderMarkdown("# My Title", {
      forceBlock: true
    });
    ```

  </Tab>
  <Tab label="Vue" value="vue">

    **1. Using the Component:**

    ```vue
    <script setup>
    import { MarkdownRenderer } from "vue-intlayer";
    </script>

    <template>
      <MarkdownRenderer :forceBlock="true" content="# My Title" />
    </template>
    ```

  </Tab>
  <Tab label="Svelte" value="svelte">

    **1. Using the Component:**

    ```svelte
    <script>
      import { MarkdownRenderer } from "svelte-intlayer";
    </script>

    <MarkdownRenderer forceBlock={true} value="# My Title" />
    ```

    **2. Using the Hook:**

    ```svelte
    <script>
      import { useMarkdownRenderer } from "svelte-intlayer";
      const render = useMarkdownRenderer();
    </script>

    {@html render("# My Title")}
    ```

    **3. Using the Utility Function:**

    ```svelte
    <script>
      import { renderMarkdown } from "svelte-intlayer";
    </script>

    {@html renderMarkdown("# My Title")}
    ```

  </Tab>
  <Tab label="Angular" value="angular">

    **1. Using the Service:**

    ```typescript
    import { Component } from "@angular/core";
    import { IntlayerMarkdownService } from "angular-intlayer";

    @Component({ ... })
    export class MyComponent {
      constructor(private markdownService: IntlayerMarkdownService) {}

      render(markdown: string) {
        return this.markdownService.renderMarkdown(markdown);
      }
    }
    ```

  </Tab>
  <Tab label="Solid" value="solid">

    **1. Using the Component:**

    ```tsx
    import { MarkdownRenderer } from "solid-intlayer";

    <MarkdownRenderer forceBlock={true}>
      {"# My Title"}
    </MarkdownRenderer>
    ```

    **2. Using the Hook:**

    ```tsx
    import { useMarkdownRenderer } from "solid-intlayer";

    const render = useMarkdownRenderer();

    return <div>{render("# My Title")}</div>;
    ```

    **3. Using the Utility Function:**

    ```tsx
    import { renderMarkdown } from "solid-intlayer";

    return <div>{renderMarkdown("# My Title")}</div>;
    ```

  </Tab>
  <Tab label="Preact" value="preact">

    **1. Using the Component:**

    ```tsx
    import { MarkdownRenderer } from "preact-intlayer";

    <MarkdownRenderer forceBlock={true}>
      {"# My Title"}
    </MarkdownRenderer>
    ```

    **2. Using the Hook:**

    ```tsx
    import { useMarkdownRenderer } from "preact-intlayer";

    const render = useMarkdownRenderer();

    return <div>{render("# My Title")}</div>;
    ```

    **3. Using the Utility Function:**

    ```tsx
    import { renderMarkdown } from "preact-intlayer";

    return <div>{renderMarkdown("# My Title")}</div>;
    ```

  </Tab>
</Tabs>

#### Examples: HTML Rendering Tools

<Tabs group='framework'>
  <Tab label="React / Next.js" value="react">

    **1. Using the Component:**

    ```tsx
    import { HTMLRenderer } from "react-intlayer";

    <HTMLRenderer
      components={{
        p: ({ children }) => <p className="mb-4">{children}</p>
      }}
    >
      {"<p>Hello World</p>"}
    </HTMLRenderer>
    ```

    **2. Using the Hook:**

    ```tsx
    import { useHTMLRenderer } from "react-intlayer";

    const renderHTML = useHTMLRenderer({
      components: {
        strong: ({ children }) => <b className="font-bold">{children}</b>
      }
    });

    return <div>{renderHTML("<p>Hello <strong>World</strong></p>")}</div>;
    ```

    **3. Using the Utility Function:**

    ```tsx
    import { renderHTML } from "react-intlayer";

    const html = renderHTML("<p>Hello World</p>");
    ```

  </Tab>
  <Tab label="Vue" value="vue">

    **1. Using the Component:**

    ```vue
    <script setup>
    import { HTMLRenderer } from "vue-intlayer";
    </script>

    <template>
      <HTMLRenderer content="<p>Hello World</p>" />
    </template>
    ```

  </Tab>
  <Tab label="Svelte" value="svelte">

    **1. Using the Component:**

    ```svelte
    <script>
      import { HTMLRenderer } from "svelte-intlayer";
    </script>

    <HTMLRenderer value="<p>Hello World</p>" />
    ```

    **2. Using the Hook:**

    ```svelte
    <script>
      import { useHTMLRenderer } from "svelte-intlayer";
      const render = useHTMLRenderer();
    </script>

    {@html render("<p>Hello World</p>")}
    ```

    **3. Using the Utility Function:**

    ```svelte
    <script>
      import { renderHTML } from "svelte-intlayer";
    </script>

    {@html renderHTML("<p>Hello World</p>")}
    ```

  </Tab>
  <Tab label="Angular" value="angular">

    **1. Direct Usage:**

    In Angular, you can use the standard `[innerHTML]` binding.

    ```html
    <div [innerHTML]="'<p>Hello World</p>'"></div>
    ```

  </Tab>
  <Tab label="Solid" value="solid">

    **1. Using the Component:**

    ```tsx
    import { HTMLRenderer } from "solid-intlayer";

    <HTMLRenderer>
      {"<p>Hello World</p>"}
    </HTMLRenderer>
    ```

    **2. Using the Hook:**

    ```tsx
    import { useHTMLRenderer } from "solid-intlayer";

    const render = useHTMLRenderer();

    return <div>{render("<p>Hello World</p>")}</div>;
    ```

    **3. Using the Utility Function:**

    ```tsx
    import { renderHTML } from "solid-intlayer";

    return <div>{renderHTML("<p>Hello World</p>")}</div>;
    ```

  </Tab>
  <Tab label="Preact" value="preact">

    **1. Using the Component:**

    ```tsx
    import { HTMLRenderer } from "preact-intlayer";

    <HTMLRenderer>
      {"<p>Hello World</p>"}
    </HTMLRenderer>
    ```

    **2. Using the Hook:**

    ```tsx
    import { useHTMLRenderer } from "preact-intlayer";

    const render = useHTMLRenderer();

    return <div>{render("<p>Hello World</p>")}</div>;
    ```

    **3. Using the Utility Function:**

    ```tsx
    import { renderHTML } from "preact-intlayer";

    return <div>{renderHTML("<p>Hello World</p>")}</div>;
    ```

  </Tab>
</Tabs>

For more details, see the [HTML Content Documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/dictionary/html.md) and [Markdown Documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/dictionary/markdown.md).

---

## Custom URL Rewrites

Intlayer v8 introduces support for **Custom URL Rewrites**, allowing you to define locale-specific paths that differ from the standard `/locale/path` structure. This is a powerful feature for improving local SEO and providing a more natural user experience for non-English speakers.

**Key enhancements in v8:**

- **Framework Formatters**: New `nextjsRewrite`, `svelteKitRewrite`, `reactRouterRewrite`, `vueRouterRewrite`, `solidRouterRewrite`, `tanstackRouterRewrite`, `nuxtRewrite`, and `viteRewrite` to provide idiomatic pattern syntax for each router.
- **`useRewriteURL` Hook**: A new client-side hook that silently corrects the address bar to the "pretty" localised URL without triggering router navigations.
- **Automatic SEO Redirects**: Built-in proxies now automatically redirect users from manually typed canonical paths (e.g., `/fr/about`) to their prettier localised versions (e.g., `/fr/a-propos`).

**Example Configuration:**

<Tabs group='routers'>
  <Tab label="Next.js" value="nextjs">

    ```typescript fileName="intlayer.config.ts"
    import { Locales, type IntlayerConfig } from "intlayer";
    import { nextjsRewrite } from "intlayer/routing";

    const config: IntlayerConfig = {
      internationalization: {
        locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
        defaultLocale: Locales.ENGLISH,
      },
      routing: {
        mode: "prefix-no-default",
        rewrite: nextjsRewrite({
          "/[locale]/about": {
            fr: "/[locale]/a-propos",
            es: "/[locale]/acerca-de",
          },
          "/[locale]/products/[id]": {
            fr: "/[locale]/produits/[id]",
            es: "/[locale]/productos/[id]",
          },
        }),
      },
    };

    export default config;
    ```

  </Tab>
    <Tab label="React Router" value="reactrouter">

    ```typescript fileName="intlayer.config.ts"
    import { Locales, type IntlayerConfig } from "intlayer";
    import { reactRouterRewrite } from "intlayer/routing";

    const config: IntlayerConfig = {
      internationalization: {
        locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
        defaultLocale: Locales.ENGLISH,
      },
      routing: {
        mode: "prefix-all",
        rewrite: reactRouterRewrite({
          "/:locale/about": {
            fr: "/:locale/a-propos",
            es: "/:locale/acerca-de",
          },
          "/:locale/products/:id": {
            fr: "/:locale/produits/:id",
            es: "/:locale/productos/:id",
          },
        }),
      },
    };

    export default config;
    ```

  </Tab>
  <Tab label="Vite (Vue, Solid, Svelte)" value="vite">

    ```typescript fileName="intlayer.config.ts"
    import { Locales, type IntlayerConfig } from "intlayer";
    import { viteRewrite } from "intlayer/routing";

    const config: IntlayerConfig = {
      internationalization: {
        locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
        defaultLocale: Locales.ENGLISH,
      },
      routing: {
        mode: "prefix-all",
        rewrite: viteRewrite({
          "/:locale/about": {
            fr: "/:locale/a-propos",
            es: "/:locale/acerca-de",
          },
          "/:locale/products/:id": {
            fr: "/:locale/produits/:id",
            es: "/:locale/productos/:id",
          },
        }),
      },
    };

    export default config;
    ```

  </Tab>
  <Tab label="Nuxt" value="nuxt">

    ```typescript fileName="intlayer.config.ts"
    import { Locales, type IntlayerConfig } from "intlayer";
    import { nuxtRewrite } from "intlayer/routing";

    const config: IntlayerConfig = {
      internationalization: {
        locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
        defaultLocale: Locales.ENGLISH,
      },
      routing: {
        mode: "prefix-all",
        rewrite: nuxtRewrite({
          "/[locale]/about": {
            fr: "/[locale]/a-propos",
            es: "/[locale]/acerca-de",
          },
          "/[locale]/products/[id]": {
            fr: "/[locale]/produits/[id]",
            es: "/[locale]/productos/[id]",
          },
        }),
      },
    };

    export default config;
    ```

  </Tab>
  <Tab label="SvelteKit" value="sveltekit">

    ```typescript fileName="intlayer.config.ts"
    import { Locales, type IntlayerConfig } from "intlayer";
    import { svelteKitRewrite } from "intlayer/routing";

    const config: IntlayerConfig = {
      internationalization: {
        locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
        defaultLocale: Locales.ENGLISH,
      },
      routing: {
        mode: "prefix-all",
        rewrite: svelteKitRewrite({
          "/[locale]/about": {
            fr: "/[locale]/a-propos",
            es: "/[locale]/acerca-de",
          },
          "/[locale]/products/[id]": {
            fr: "/[locale]/produits/[id]",
            es: "/[locale]/productos/[id]",
          },
        }),
      },
    };

    export default config;
    ```

  </Tab>
</Tabs>

This feature is supported out-of-the-box in **Next.js** and **Vite** through the Intlayer proxies, and can be easily integrated into other routers like **TanStack Router**, **React Router**, **Vue Router**, **SvelteKit**, and **Solid Router**.

For more information and integration guides, see the [Custom URL Rewrites Documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/custom_url_rewrites.md).

---

### Enhanced Insertion Values

In v8, insertion values can now **accept React elements (or Vue nodes)** in addition to strings and numbers. This allows you to inject rich, interactive components directly into your insertion templates.

Intlayer now robustly handles nested React and Preact nodes within insertions, ensuring that complex UI structures are preserved and rendered correctly.

**Example:**

```typescript fileName="src/example.content.ts"
import { insert } from "intlayer";

export default {
  key: "my-key",
  content: {
    myInsertion: insert("Hi {{name}}"),
  },
};
```

<Tabs group='framework'>
  <Tab label="Next.js" value="nextjs">

    ```tsx
    import { useIntlayer } from "next-intlayer";

    const { myInsertion } = useIntlayer("my-key");

    return (
      <div>
        {myInsertion({
          name: 2, // number
          // or
          name: "John", // string
          // or
          name: <span>John</span>, // React element
        })}
      </div>
    );
    ```

  </Tab>
  <Tab label="React" value="react">

    ```tsx
    import { useIntlayer } from "react-intlayer";

    const { myInsertion } = useIntlayer("my-key");

    return (
      <div>
        {myInsertion({
          name: 2, // number
          // or
          name: "John", // string
          // or
          name: <span>John</span>, // React element
        })}
      </div>
    );
    ```

  </Tab>
  <Tab label="Vue" value="vue">

    ```vue
    <script setup>
    import { h } from "vue";
    import { useIntlayer } from "vue-intlayer";

    const { myInsertion } = useIntlayer("my-key");
    </script>

    <template>
      <div>
        <component
          :is="myInsertion({
            name: 2,
            // or
            name: 'John',
            // or
            name: h('span', 'John'),
          })"
        />
      </div>
    </template>
    ```

  </Tab>
  <Tab label="Preact" value="preact">

    ```tsx
    import { useIntlayer } from "preact-intlayer";

    const { myInsertion } = useIntlayer("my-key");

    return (
      <div>
        {myInsertion({
          name: 2, // number
          // or
          name: "John", // string
          // or
          name: <span>John</span>, // Preact element
        })}
      </div>
    );
    ```

  </Tab>
  <Tab label="Solid" value="solid">

    ```tsx
    import { useIntlayer } from "solid-intlayer";

    const { myInsertion } = useIntlayer("my-key");

    return (
      <div>
        {myInsertion({
          name: 2, // number
          // or
          name: "John", // string
          // or
          name: <span>John</span>, // Solid element
        })}
      </div>
    );
    ```

  </Tab>
  <Tab label="Svelte" value="svelte">

    ```svelte
    <script>
      import { useIntlayer } from "svelte-intlayer";

      const { myInsertion } = useIntlayer("my-key");
    </script>

    <div>
      {myInsertion({
        name: 2, // number
        // or
        name: "John", // string
      })}
    </div>
    ```

  </Tab>
  <Tab label="Angular" value="angular">

    ```typescript
    import { Component } from "@angular/core";
    import { useIntlayer } from "angular-intlayer";

    @Component({
      selector: "app-insertion-example",
      template: `
        <div>
          {{ content().myInsertion({
            name: 'John'
          }) }}
        </div>
      `,
    })
    export class InsertionExampleComponent {
      content = useIntlayer("my-key");
    }
    ```

  </Tab>
</Tabs>

## Content Schema Validation

Intlayer v8 introduces schema validation for dictionaries. You can now define reusable validation schemas in your configuration using Zod and apply them to your content files. This ensures your content always adheres to the expected structure, catching errors at build time.

### 1. Define Schemas

Define your schemas in `intlayer.config.ts`:

```typescript fileName="intlayer.config.ts"
import { z } from "zod";

export default {
  schemas: {
    "seo-metadata": z.object({
      title: z.string().min(50).max(60),
      description: z.string().min(150).max(160),
    }),
  },
};
```

### 2. Apply Schemas to Dictionaries

Reference the schema key in your dictionary definition:

```typescript fileName="src/example.content.ts"
import { type Dictionary } from "intlayer";

const aboutPageMetaContent = {
  key: "about-page-meta",
  schema: "seo-metadata", // <--
  content: {
    title: "About Our Company - Learn More About Us",
    description: "Discover our company's mission, values, and team.",
  },
} satisfies Dictionary;

export default aboutPageMetaContent;
```

If the content doesn't match the schema (e.g., title is too short), the build process will raise an error.

---

### Enhanced Automatic Content Detection

In v8, Intlayer intelligently detects Markdown syntax, HTML tags, and variable insertions in your content strings. This means you can often omit helper functions like `md()`, `html()`, or `insert()`.

This behaviour is enabled by default. You can now fine-tune this detection either globally in your `intlayer.config.ts` or per dictionary.

#### Granular Control

You can enable or disable specific types of transformations:

```typescript fileName="intlayer.config.ts"
export default {
  dictionary: {
    // contentAutoTransformation: false (default)
    contentAutoTransformation: {
      markdown: true,
      html: true,
      insertion: false, // Disable automatic insertion detection
    },
  },
};
```

**v7 behaviour (Manual wrapping):**

```typescript fileName="src/example.content.ts"
import { md, insert } from "intlayer";

export default {
  key: "my-key",
  content: {
    myMarkdown: md("## Hello World"),
    myInsertion: insert("Hi {{name}}"),
  },
};
```

**v8 behaviour (Automatic detection):**

```typescript fileName="src/example.content.ts"
export default {
  key: "my-key",
  contentAutoTransformation: true, // Can also be set by dictionary definition or globally in intlayer.config.ts
  content: {
    myMarkdown: "## Hello World", // Automatically detected as Markdown
    myHTML: "<p>Hello World</p>", // Automatically detected as HTML
    myInsertion: "Hi {{name}}", // Automatically detected as Insertion
  },
};
```

The underlying JSON result remains the same, preserving the rich type information needed for rendering:

```json
{
  "key": "my-key",
  "content": {
    "myMarkdown": {
      "nodeType": "markdown",
      "markdown": "## Hello World"
    },
    "myHTML": {
      "nodeType": "html",
      "html": "<p>Hello World</p>"
    },
    "myInsertion": {
      "nodeType": "insertion",
      "insertion": "Hi {{name}}"
    }
  }
}
```

---

## Localization: new `useIntl` hook

A new `useIntl()` hook is now available in React, Next.js and Vue. It provides a locale-bound `Intl` object that automatically uses the current language for formatting numbers, dates, and more, without needing to manually pass the locale.

<Tabs group='framework'>
  <Tab label="Next.js" value="nextjs">

    ```tsx
    import { useIntl } from "next-intlayer";

    const intl = useIntl();

    const formattedPrice = new intl.NumberFormat({
      style: "currency",
      currency: "USD",
    }).format(123.45);
    ```

  </Tab>
  <Tab label="React" value="react">

    ```tsx
    import { useIntl } from "react-intlayer";

    const intl = useIntl();

    const formattedPrice = new intl.NumberFormat({
      style: "currency",
      currency: "USD",
    }).format(123.45);
    ```

  </Tab>
  <Tab label="Vue" value="vue">

    ```vue
    <script setup>
    import { useIntl } from "vue-intlayer";

    const intl = useIntl();

    const formattedPrice = new intl.NumberFormat({
      style: "currency",
      currency: "USD",
    }).format(123.45);
    </script>
    ```

  </Tab>
  <Tab label="Preact" value="preact">

    ```tsx
    import { useIntl } from "preact-intlayer";

    const intl = useIntl();

    const formattedPrice = new intl.NumberFormat({
      style: "currency",
      currency: "USD",
    }).format(123.45);
    ```

  </Tab>
  <Tab label="Solid" value="solid">

    ```tsx
    import { useIntl } from "solid-intlayer";

    const intl = useIntl();

    const formattedPrice = new intl.NumberFormat({
      style: "currency",
      currency: "USD",
    }).format(123.45);
    ```

  </Tab>
  <Tab label="Svelte" value="svelte">

    ```svelte
    <script>
      import { useIntl } from "svelte-intlayer";

      const intl = useIntl();

      const formattedPrice = new intl.NumberFormat({
        style: "currency",
        currency: "USD",
      }).format(123.45);
    </script>
    ```

  </Tab>
  <Tab label="Angular" value="angular">

    ```typescript
    import { Component, computed } from "@angular/core";
    import { useIntl } from "angular-intlayer";

    @Component({
      selector: "app-intl-example",
      template: `<div>{{ formattedPrice() }}</div>`,
    })
    export class IntlExampleComponent {
      intl = useIntl();

      formattedPrice = computed(() =>
        new (this.intl().NumberFormat)({
          style: "currency",
          currency: "USD",
        }).format(123.45)
      );
    }
    ```

  </Tab>
</Tabs>

---

## Tooling: VSCode Extension Enhancements

The Intlayer VSCode extension receives major updates in v8 to streamline your internationalisation workflow:

- **Starting Time**: Performance improvements when opening a project.
- **Caching**: Enhanced caching layer for near-instant validation and autocompletion.
- **Unused Keys & Duplicated Keys Detection**: New features to automatically detect **unused keys** and **duplicated keys** across your dictionaries, helping you keep your content clean and efficient.

---

## Compiler Optimizations

Intlayer v8 includes a new caching layer for the Markdown and HTML compiler. This ensures that identical content strings with the same configuration are only parsed once, significantly reducing the overhead during re-renders or when using the same content in multiple places.

<Tabs group='bundler'>
  <Tab label="Next.js" value="nextjs">
  
    ```typescript fileName="babel.config.js"
      const {
      intlayerExtractBabelPlugin,
      intlayerOptimizeBabelPlugin,
      getExtractPluginOptions,
      getOptimizePluginOptions,
    } = require('@intlayer/babel');

    module.exports = {
      presets: ['next/babel'],
      plugins: [
        // Extract content from components into dictionaries
        [intlayerExtractBabelPlugin, getExtractPluginOptions()],
        // Optimize imports by replacing useIntlayer with direct dictionary imports
        [intlayerOptimizeBabelPlugin, getOptimizePluginOptions()],
      ],
    };
    ```

  </Tab>
  <Tab label="Vite" value="vite">
   
    ```typescript fileName="vite.config.js"
    import { defineConfig } from 'vite';
    import {intlayer, intlayerCompiler} from 'vite-intlayer';

    export default defineConfig({
      plugins: [intlayer(), intlayerCompiler()],
    });
    ```

> For vue / svelte you will need to install the appropriate compiler package:
>
> ```bash
> # For Vue
> npm install @intlayer/vue-compiler
> ```
>
> ```bash
> # For Svelte
> npm install @intlayer/svelte-compiler
> ```

  </Tab>
</Tabs>

---

## Flexibility: Unified Import Mode

The `live` boolean property has been deprecated in favour of a more comprehensive `importMode` property. This allows for explicit definition of how dictionaries should be loaded: statically, dynamically, or via live sync.

### Modes

- **`static`** (Default): Dictionary is bundled at build time. Best for performance.
- **`dynamic`**: Dictionary is loaded at runtime (e.g., via JSON fetch or suspense).
- **`fetch`**: Dictionary is fetched from the CMS/Server at runtime and synchronised.

**Migration:**

| v7 Config     | v8 Config                             |
| :------------ | :------------------------------------ |
| `live: true`  | `importMode: 'fetch'`                 |
| `live: false` | `importMode: 'static'` (or 'dynamic') |

Note: In Intlayer v8, the `importMode` property has been moved from the `build` configuration to the `dictionary` configuration in `intlayer.config.ts`. This allows you to define a default import mode for all your dictionaries while still being able to override it on a per-dictionary basis.

**Global Configuration Example:**

```typescript fileName="intlayer.config.ts"
export default {
  dictionary: {
    importMode: "dynamic", // Global default
  },
  // ...
};
```

**Dictionary Example:**

```typescript fileName="src/example.content.ts"
export default {
    key: 'my-key',
    importMode: "fetch", // Overrides global config
    content: { ... }
}
```

---

## Dictionary Location Control

v8 introduces the `location` property to explicitly manage where dictionaries live and how they synchronise. This is particularly useful for hybrid workflows involving both local files and remote CMS content.

### Options

- **`local`**: The dictionary exists only locally. It will not be pushed to the remote CMS.
- **`remote`**: The dictionary is managed remotely. Once pushed on the CMS, it will be detached from the local one. The remote dictionary will be pulled from the CMS.
- **`local_and_remote`**: The dictionary exists in both places. Local changes are pushed, and remote changes are pulled (synchronised).

**Example:**

```typescript fileName="src/example.content.ts"
export default {
    key: 'my-key',
    location: "local", // Keep this dictionary local-only
    content: { ... }
}
```

---

## System Configuration Separation

Intlayer v8 separates the configuration of content sources from internal system and output paths. This declutters the `content` property and makes it clear which settings are intended for user management vs. those that are managed by the Intlayer system.

The following properties have been moved from `content` to a new `system` property in `intlayer.config.ts`:

- `dictionariesDir`
- `moduleAugmentationDir`
- `unmergedDictionariesDir`
- `typesDir`
- `mainDir`
- `configDir`
- `cacheDir`
- `outputFilesPatternWithPath`

**v7 behaviour:**

```typescript fileName="intlayer.config.ts"
export default {
  content: {
    contentDir: ["src"],
    dictionariesDir: ".intlayer/dictionary", // Mixed with source config
  },
};
```

**v8 behaviour:**

```typescript fileName="intlayer.config.ts"
export default {
  content: {
    contentDir: ["src"],
  },
  system: {
    dictionariesDir: ".intlayer/dictionary", // Clearly separated
  },
};
```

---

## Content and Code Directory Separation

Intlayer v8 separates the configuration for content definition files from the configuration for code transformation. This allows for more precise watching and scanning, improving build performance.

Previously, `contentDir` was used for both watching `.content.*` files and scanning code for `useIntlayer` calls. Now:

- **`contentDir`**: Specifically for your content declaration files.
- **`codeDir`**: Specifically for your application code that needs transformation (e.g., pruning, optimisation).

**Migration:**

If you previously had `contentDir` set, Intlayer v8 will use it as the default for `codeDir` as well, but will log a warning. You should explicitly define `codeDir` in your configuration.

**v7 behaviour:**

```typescript fileName="intlayer.config.ts"
export default {
  content: {
    contentDir: ["src", "@packages/design-system"], // Used for both content and code
  },
};
```

**v8 behaviour:**

```typescript fileName="intlayer.config.ts"
export default {
  content: {
    contentDir: ["src/content", "@packages/design-system"], // Only watch for src/content/*.content.* files here and @packages/design-system/dist/*.content.* files
    codeDir: ["src", "@packages/design-system"], // Only scan for code transformation here and @packages/design-system/src/*.content.* files
  },
};
```

---

## Framework: Svelte Improvements

Markdown and HTML content in Svelte now automatically parse to HTML when stringified. This makes it much easier to use with Svelte's `{@html}` syntax, as you can now simply pass the content node directly.

---

## Migration notes from v7

### Configuration Changes

- **`live` property**: The `live` property in dictionaries is removed. Use `importMode: 'fetch'` instead.
- **importMode**: The `build.importMode` property in configuration has been deprecated. Use `dictionary.importMode` instead.
- **`contentDir` and `codeDir`**: `contentDir` is now specifically for content files. A new `codeDir` property has been added for code transformation. If `codeDir` is not set, Intlayer will fallback to `contentDir` and log a warning.
- **Schema Validation**: To use the new `schema` feature, ensure you have `zod` installed in your project.

---

## Useful links

- [Configuration Reference](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/configuration.md)
- [Content File Documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/dictionary/content_file.md)
- [HTML Content Documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/dictionary/html.md)
- [Markdown Content Documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/dictionary/markdown.md)
- [Custom URL Rewrites Documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/custom_url_rewrites.md)
