---
createdAt: 2025-09-22
updatedAt: 2026-01-26
title: Intlayer v8 新功能 - 有什么新变化？
description: 了解 Intlayer v8 的新特性。在开发者体验、内容验证和字典管理方面带来重大改进。
keywords:
  - Intlayer
  - CMS
  - 开发者体验
  - 功能
  - React
  - Next.js
  - JavaScript
  - TypeScript
youtubeVideo: https://www.youtube.com/watch?v=ia6JmVf-kkU
slugs:
  - doc
  - releases
  - v8
---

# Intlayer v8 新功能 - 有什么新变化？

欢迎使用 Intlayer v8！此版本侧重于通过自动内容检测提升开发者体验、通过 schema 验证确保数据完整性，并为字典管理提供更细粒度的控制。

<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"
/>

## 目录

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

---

## 富内容演进：Markdown & HTML

Intlayer v8 对富内容的处理方式进行了重大改进，引入了 **HTML 节点**（v7 中不存在），并统一了与 **Markdown 节点**（v7 中已存在但经过增强）的 API。

### 统一的 `.use()` API

我们为 Markdown 和 HTML 节点引入了 `.use()` 方法。此方法允许你自定义渲染过程中使用的 HTML 标签或组件。

- **组件替换**：你可以轻松地将 HTML 标签或自定义组件替换为你自己的框架组件（例如，将 `<a>` 替换为 `NextLink`，或将 `<CustomCmp>` 替换为 React 组件）。
- **类型安全**：所有提供组件的函数都是完全类型化的，确保你接收到正确的 props。

### 默认渲染行为

在 v7 中，如果没有定义 provider，Markdown 节点会被渲染为原始字符串，通常需要外部库进行解析。

**在 v8 中，Intlayer 包含了其内部的 Markdown 解析器。** 默认情况下，Markdown 节点现在直接渲染为 HTML，无需任何外部库。

### 新的 Renderer 和 Provider 实用工具

我们引入了新的独立渲染函数和组件，以便在标准 `useIntlayer` 流程之外给你更多控制。

- **Markdown**: `MarkdownRenderer`, `useMarkdownRenderer`, `renderMarkdown`。（注意：`MarkdownProvider` 在 v7 中已存在，但现在与这些新工具集成）。
- **HTML**: `HTMLRenderer`, `useHTMLRenderer`, `renderHTML`, `HTMLProvider`。

#### 示例：Markdown 渲染工具

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

    **1. 使用组件：**

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

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

    **2. 使用 Hook：**

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

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

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

    **3. 使用实用函数：**

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

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

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

    **1. 使用组件：**

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

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

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

    **1. 使用组件：**

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

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

    **2. 使用 Hook：**

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

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

    **3. 使用实用函数：**

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

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

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

    **1. 使用服务：**

    ```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. 使用组件：**

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

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

    **2. 使用 Hook：**

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

    const render = useMarkdownRenderer();

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

    **3. 使用实用函数：**

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

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

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

    **1. 使用组件：**

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

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

    **2. 使用 Hook：**

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

    const render = useMarkdownRenderer();

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

    **3. 使用实用函数：**

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

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

  </Tab>
</Tabs>

#### 示例：HTML 渲染工具

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

    **1. 使用组件：**

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

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

    **2. 使用 Hook：**

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

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

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

    **3. 使用实用函数：**

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

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

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

    **1. 使用组件：**

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

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

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

    **1. 使用组件：**

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

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

    **2. 使用 Hook：**

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

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

    **3. 使用实用函数：**

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

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

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

    **1. 直接用法：**

    在 Angular 中，你可以使用标准的 `[innerHTML]` 绑定。

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

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

    **1. 使用组件：**

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

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

    **2. 使用 Hook：**

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

    const render = useHTMLRenderer();

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

    **3. 使用实用函数：**

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

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

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

    **1. 使用组件：**

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

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

    **2. 使用 Hook：**

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

    const render = useHTMLRenderer();

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

    **3. 使用实用函数：**

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

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

  </Tab>
</Tabs>

欲了解更多详情，请参阅 [HTML 内容文档](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dictionary/html.md) 和 [Markdown 文档](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dictionary/markdown.md)。

---

## 自定义 URL 重写

Intlayer v8 引入对 **自定义 URL 重写** 的支持，允许你定义与标准 `/locale/path` 结构不同的特定语言路径。此功能可显著提升本地 SEO，并为非英文用户提供更自然的使用体验。

**v8 的主要增强：**

- **Framework Formatters**: 新增 `nextjsRewrite`、`svelteKitRewrite`、`reactRouterRewrite`、`vueRouterRewrite`、`solidRouterRewrite`、`tanstackRouterRewrite`、`nuxtRewrite` 和 `viteRewrite`，为每种路由器提供符合惯用语法的模式。
- **`useRewriteURL` Hook**: 一个新的客户端 Hook，它在不触发路由导航的情况下静默地将地址栏更正为更友好的本地化 URL。
- **自动 SEO 重定向**: 内置代理现在会自动将用户从手动输入的规范路径（例如 `/fr/about`）重定向到它们更优雅的本地化版本（例如 `/fr/a-propos`）。

**示例配置：**

<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>

此功能通过 Intlayer 代理在 **Next.js** 和 **Vite** 中开箱即用，并且可以轻松集成到其他路由器，例如 **TanStack Router**、**React Router**、**Vue Router**、**SvelteKit** 和 **Solid Router**。

有关更多信息和集成指南，请参阅 [自定义 URL 重写文档](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/custom_url_rewrites.md)。

---

### 增强的插入值

在 v8 中，插入值现在除了字符串和数字之外，还能**接受 React 元素（或 Vue 节点）**。这允许你将丰富的交互式组件直接注入到插入模板中。

Intlayer 现在可以稳健地处理插入中的嵌套 React 和 Preact 节点，确保复杂的 UI 结构得到保留并正确渲染。

**示例：**

```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, // 数字
          // 或者
          name: "John", // 字符串
          // 或者
          name: <span>John</span>, // React 元素
        })}
      </div>
    );
    ```

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

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

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

    return (
      <div>
        {myInsertion({
          name: 2, // 数字
          // 或
          name: "John", // 字符串
          // 或
          name: <span>John</span>, // React 元素
        })}
      </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, // 数字
            // 或
            name: 'John', // 字符串
            // 或
            name: h('span', 'John'), // Vue 元素
          })"
        />
      </div>
    </template>
    ```

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

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

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

    return (
      <div>
        {myInsertion({
          name: 2, // 数字
          // 或
          name: "John", // 字符串
          // 或
          name: <span>John</span>, // Preact 元素
        })}
      </div>
    );
    ```

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

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

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

    return (
      <div>
        {myInsertion({
          name: 2, // 数字
          // 或
          name: "John", // 字符串
          // 或
          name: <span>John</span>, // Solid 元素
        })}
      </div>
    );
    ```

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

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

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

    <div>
      {myInsertion({
        name: 2, // 数字
        // 或
        name: "John", // 字符串
      })}
    </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>

## 内容 Schema 验证

Intlayer v8 为字典引入了 schema 验证。你现在可以在配置中使用 Zod 定义可重用的验证 schema，并将其应用到你的内容文件中。这可以确保你的内容始终遵循预期的结构，并在构建时捕获错误。

### 1. 定义 Schemas

在 `intlayer.config.ts` 中定义你的 schemas：

```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. 将 Schemas 应用到字典

在字典定义中引用 schema 键：

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

const aboutPageMetaContent = {
  key: "about-page-meta",
  schema: "seo-metadata", // <--
  content: {
    title: "关于我们公司 - 了解更多关于我们的信息",
    description: "了解我们公司的使命、价值观和团队。",
  },
} satisfies Dictionary;

export default aboutPageMetaContent;
```

如果内容不符合模式（例如，title 太短），构建过程将抛出错误。

---

### 增强的自动内容检测

在 v8 中，Intlayer 能智能检测内容字符串中的 Markdown 语法、HTML 标签和变量插入。这意味着通常可以省略像 `md()`、`html()` 或 `insert()` 这样的辅助函数。

此行为默认启用。您现在可以在全局的 `intlayer.config.ts` 中或针对每个字典细化此检测。

#### 细粒度控制

您可以启用或禁用特定类型的转换：

```typescript fileName="intlayer.config.ts"
export default {
  dictionary: {
    // contentAutoTransformation: false（默认）
    contentAutoTransformation: {
      markdown: true,
      html: true,
      insertion: false, // 禁用自动插入检测
    },
  },
};
```

**v7 行为（手动包裹）：**

```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 行为（自动检测）：**

```typescript fileName="src/example.content.ts"
export default {
  key: "my-key",
  contentAutoTransformation: true, // 也可以通过字典定义或在 intlayer.config.ts 中全局设置
  content: {
    myMarkdown: "## Hello World", // 自动检测为 Markdown
    myHTML: "<p>Hello World</p>", // 自动检测为 HTML
    myInsertion: "Hi {{name}}", // 自动检测为 Insertion（插入）
  },
};
```

底层的 JSON 结果保持不变，保留渲染所需的丰富类型信息：

```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}}"
    }
  }
}
```

---

## 本地化：新的 `useIntl` 钩子

现在在 React、Next.js 和 Vue 中可以使用新的 `useIntl()` 钩子。它提供了一个与语言环境绑定的 `Intl` 对象，能够自动使用当前语言来格式化数字、日期等，而无需手动传入 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>

---

## 工具：VSCode 扩展增强

Intlayer 的 VSCode 扩展在 v8 中迎来重大更新，以简化你的国际化工作流程：

- **启动时间**：打开项目时的性能改进。
- **缓存**：增强的缓存层，实现接近即时的验证和自动补全。
- **未使用键与重复键检测**：新增功能，可自动检测字典中的 **未使用键** 和 **重复键**，帮助你保持内容整洁且高效。

---

## 编译器优化

Intlayer v8 为 Markdown 和 HTML 编译器引入了新的缓存层。这确保在相同配置下相同的内容字符串只被解析一次，从而显著降低在重新渲染或在多个地方使用相同内容时的开销。

<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: [
        // 从组件中提取内容到字典
        [intlayerExtractBabelPlugin, getExtractPluginOptions()],
        // 优化导入，通过将 useIntlayer 替换为直接的字典导入
        [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()],
    });
    ```

> 对于 vue / svelte，您需要安装相应的编译器包：
>
> ```bash
> # 对于 Vue
> npm install @intlayer/vue-compiler
> ```
>
> ```bash
> # 对于 Svelte
> npm install @intlayer/svelte-compiler
> ```

  </Tab>
</Tabs>

---

## 灵活性：统一导入模式

`live` 布尔属性已被弃用，改用更为全面的 `importMode` 属性。这样可以明确定义 dictionaries 应如何加载：静态、动态，或通过实时同步。

### 模式

- **`static`**（默认）：dictionary 在构建时被打包。性能最佳。
- **`dynamic`**：dictionary 在运行时加载（例如，通过 JSON fetch 或 suspense）。
- **`fetch`**：dictionary 在运行时从 CMS/服务器 获取并同步。

**迁移：**

| v7 配置       | v8 配置                                  |
| :------------ | :--------------------------------------- |
| `live: true`  | `importMode: 'fetch'`                    |
| `live: false` | `importMode: 'static'`（或 `'dynamic'`） |

注意：在 Intlayer v8 中，`importMode` 属性已从 `build` 配置移动到 `intlayer.config.ts` 中的 `dictionary` 配置。这样可以为所有字典定义一个默认的导入模式，同时仍然可以在每个字典级别上覆盖该设置。

**全局配置示例：**

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

**字典示例：**

```typescript fileName="src/example.content.ts"
export default {
    key: 'my-key',
    importMode: "fetch", // 覆盖全局配置
    content: { ... }
}
```

---

## 字典位置控制

v8 引入了 `location` 属性，用于明确管理字典的位置以及它们如何同步。这在涉及本地文件和远程 CMS 内容的混合工作流中特别有用。

### 选项

- **`local`**：字典仅存在于本地。它不会被推送到远程 CMS。
- **`remote`**：字典由远程管理。一旦在 CMS 上推送，它将与本地分离。远程字典将从 CMS 拉取。
- **`local_and_remote`**：字典同时存在于两处。本地更改会被推送，远程更改会被拉取（同步）。

**示例：**

```typescript fileName="src/example.content.ts"
export default {
    key: 'my-key',
    location: "local", // 将此字典仅保存在本地
    content: { ... }
}
```

---

## 系统配置分离

Intlayer v8 将内容源配置与内部 system 和输出路径分离。这使得 `content` 属性更简洁，并且明确哪些设置由用户管理，哪些由 Intlayer 系统管理。

以下属性已从 `content` 移动到 `intlayer.config.ts` 中的新 `system` 属性：

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

**v7 行为：**

```typescript fileName="intlayer.config.ts"
export default {
  content: {
    contentDir: ["src"],
    dictionariesDir: ".intlayer/dictionary", // 与源配置混合
  },
};
```

**v8 行为：**

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

---

## 内容目录与代码目录分离

Intlayer v8 将内容定义文件的配置与代码转换的配置分离。这使得监视和扫描更加精确，从而提升构建性能。

此前，`contentDir` 同时用于监视 `.content.*` 文件和扫描代码中的 `useIntlayer` 调用。现在：

- **`contentDir`**：专用于内容声明文件。
- **`codeDir`**：专用于需要进行转换的应用代码（例如：剪枝、优化）。

**迁移：**

如果你之前设置过 `contentDir`，Intlayer v8 将把它也作为 `codeDir` 的默认值，但会记录一个警告。你应该在配置中显式定义 `codeDir`。

**v7 行为：**

```typescript fileName="intlayer.config.ts"
export default {
  content: {
    contentDir: ["src", "@packages/design-system"], // 同时用于内容和代码
  },
};
```

**v8 行为：**

```typescript fileName="intlayer.config.ts"
export default {
  content: {
    contentDir: ["src/content", "@packages/design-system"], // 仅在此监视 src/content/*.content.* 文件和 @packages/design-system/dist/*.content.* 文件
    codeDir: ["src", "@packages/design-system"], // 仅在此扫描用于代码转换的代码
  },
};
```

---

## 框架：Svelte 改进

在 Svelte 中的 Markdown 和 HTML 内容在被字符串化（stringified）时现在会自动解析为 HTML。这样与 Svelte 的 `{@html}` 语法一起使用更加方便，因为你现在可以直接传递内容节点。

---

## 从 v7 的迁移说明

### 配置更改

- **`live` 属性**：字典中的 `live` 属性已被移除。请改用 `importMode: 'fetch'`。
- **importMode**：配置中的 `build.importMode` 属性已被弃用。请改用 `dictionary.importMode`。
- **`contentDir` 和 `codeDir`**：`contentDir` 现在专用于内容文件。新增 `codeDir` 属性用于代码转换。如果未设置 `codeDir`，Intlayer 将回退到使用 `contentDir` 并记录一个警告。
- **模式验证**：要使用新的 `schema` 功能，请确保在项目中已安装 `zod`。

---

## 有用的链接

- [配置参考](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/configuration.md)
- [内容文件文档](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dictionary/content_file.md)
- [HTML 内容文档](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dictionary/html.md)
- [Markdown 内容文档](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dictionary/markdown.md)
- [自定义 URL 重写文档](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/custom_url_rewrites.md)
