Автор:
    Создание:2025-02-07Последнее обновление:2026-05-19

    Markdown / Форматированный текст

    Intlayer поддерживает форматированный текстовый контент, определенный с использованием синтаксиса Markdown. Это позволяет легко писать и поддерживать контент со сложным форматированием, такой как блоги, статьи и многое другое.

    Объявление Markdown-контента

    Вы можете объявить Markdown-контент с помощью функции md или просто как строку (если она содержит синтаксис Markdown).

    Начиная с версии 8.10.0, вы можете объявлять Markdown-контент непосредственно в файлах .content.md. Intlayer автоматически обнаружит и проанализирует Markdown-контент.

    Начиная с версии 8.10.0, вы можете объявлять содержимое Markdown непосредственно в файлах .content.md. Intlayer будет автоматически обнаруживать и анализировать содержимое Markdown.

    markdown-file.en.content.md
    ---
    key: my-markdown-content
    description: Мой контент
    locale: en
    ---
    
    # Мой контент
    
    Вот пример Markdown-контента
    

    Поле locale в front-matter определяет локаль контента. Оно необязательно. Если оно не указано, Intlayer будет использовать локаль по умолчанию, которая также используется в качестве резервной локали (fallback), если перевод для конкретной локали недоступен.

    Пример структуры файлов:

    text
    content/
    ├── en/
    │   └── markdown-file.en.content.md
    ├── fr/
    
    │   └── markdown-file.fr.content.md
    └── es/
      └── markdown-file.es.content.md
    

    Вы можете добавить в front-matter любые свойства, определенные в определении словаря

    Используйте функцию md для явного объявления Markdown-контента. Это полезно, если вы хотите гарантировать, что строка будет обрабатываться как Markdown, даже если она не содержит явного синтаксиса.

    markdownDictionary.content.ts
    import { md, type Dictionary } from "intlayer";
    
    const markdownDictionary = {
    key: "app",
    content: {
      myMarkdownContent: md("## My title \n\nLorem Ipsum"),
    },
    } satisfies Dictionary;
    
    export default markdownDictionary;
    

    Если строка содержит общие признаки Markdown (такие как заголовки, списки, ссылки и т. д.), Intlayer автоматически преобразует ее.

    markdownDictionary.content.ts
    export default {
    key: "app",
    contentAutoTransformation: true, // Включить автоматическое обнаружение Markdown контента — можно установить глобально в intlayer.config.ts
    content: {
      myMarkdownContent: "## My title \n\nLorem Ipsum",
    },
    };
    

    Рендеринг Markdown

    Intlayer предоставляет два независимых способа рендеринга Markdown:

    1. Через useIntlayer — Intlayer автоматически преобразует узел md в нативный вывод фреймворка (JSX, VNode, HTML-строка).

      • Frontmatter парсится и предоставляется как .metadata. Вы можете переопределить рендеринг на двух уровнях — глобально с помощью MarkdownProvider (или эквивалента для вашего фреймворка) и локально для каждого узла с помощью .use(). Оба метода можно комбинировать; .use() имеет приоритет над MarkdownProvider, который, в свою очередь, имеет приоритет над поведением по умолчанию.
    2. Вспомогательные утилиты<MarkdownRenderer />, useMarkdownRenderer() и renderMarkdown() являются автономными инструментами, которые принимают только необработанные строки Markdown (raw strings). Они не зависят от useIntlayer и не работают с декорированными узлами, которые он возвращает.

    Рендеринг Markdown поддерживает MDX — используйте любой JSX компонент или компонент фреймворка по имени прямо в вашем Markdown.

    1. Автоматический рендеринг (через useIntlayer)

    Markdown-узлы могут быть отрисованы напрямую как JSX.

    App.tsx
    import { useIntlayer } from "react-intlayer";
    import { MarkdownProvider } from "react-intlayer/markdown";
    
    const AppContent = () => {
    const { myMarkdownContent } = useIntlayer("app");
    
    return <div>{myMarkdownContent}</div>;
    };
    
    const App = () => (
    <MarkdownProvider
      components={{
        h1: ({ children }) => <h1 style={{ color: "red" }}>{children}</h1>,
        MyButton: (props) => <button {...props} />, // MDX-компонент
      }}
    >
      <AppContent />
    </MarkdownProvider>
    );
    
    Если MarkdownProvider отсутствует, intlayer будет отрисовывать markdown, используя стандартный парсер Markdown в JSX.

    Вы также можете предоставить локальные переопределения для конкретных узлов, используя метод .use():

    tsx
    {myMarkdownContent.use({
    h1: ({ children }) => <h1 style={{ color: "red" }}>{children}</h1>,
    })}
    

    Вы можете получить Markdown в виде строки:

    tsx
    {myMarkdownContent.value}
    {String(myMarkdownContent)}
    {myMarkdownContent.toString()}
    

    И вы можете получить доступ к метаданным вашего markdown, например:

    tsx
    {myMarkdownContent.metadata}
    {myMarkdownContent.metadata.title}
    

    Markdown-узлы могут быть отрисованы напрямую как JSX.

    App.tsx
    import { useIntlayer } from "next-intlayer";
    import { MarkdownProvider } from "next-intlayer/markdown";
    
    const AppContent = () => {
    const { myMarkdownContent } = useIntlayer("app");
    
    return <div>{myMarkdownContent}</div>;
    };
    
    const App = () => (
    <MarkdownProvider
      components={{
        h1: ({ children }) => <h1 style={{ color: "red" }}>{children}</h1>,
        MyButton: (props) => <button {...props} />, // MDX-компонент
      }}
    >
      <AppContent />
    </MarkdownProvider>
    );
    
    Если MarkdownProvider отсутствует, intlayer будет отрисовывать markdown, используя стандартный парсер Markdown в JSX.

    Вы также можете предоставить локальные переопределения для конкретных узлов, используя метод .use():

    tsx
    {myMarkdownContent.use({
    h1: ({ children }) => <h1 style={{ color: "red" }}>{children}</h1>,
    })}
    

    Вы можете получить Markdown в виде строки:

    tsx
    {myMarkdownContent.value}
    {String(myMarkdownContent)}
    {myMarkdownContent.toString()}
    

    И вы можете получить доступ к метаданным вашего markdown, например:

    tsx
    {myMarkdownContent.metadata}
    {myMarkdownContent.metadata.title}
    

    В Vue контент Markdown можно отрендерить с помощью встроенного элемента component или напрямую как узел.

    App.vue
    <script setup>
    import { useIntlayer } from "vue-intlayer";
    const { myMarkdownContent } = useIntlayer("app");
    </script>
    
    <template>
    <component :is="myMarkdownContent" />
    </template>
    

    Настройте глобально через плагин intlayerMarkdown (поддерживает пользовательские компоненты MDX):

    main.ts
    import { intlayerMarkdown } from "vue-intlayer/markdown";
    
    app.use(intlayerMarkdown, {
    components: {
      h1: (props) => h('h1', { style: { color: 'green' } }, props.children),
      MyButton: (props) => h('button', props), // Компонент MDX
    },
    });
    
    Если плагин intlayerMarkdown не установлен, Intlayer будет выполнять рендеринг с использованием компилятора по умолчанию.

    Вы также можете предоставить локальные переопределения для конкретных узлов, используя метод .use():

    vue
    <component :is="myMarkdownContent.use({
    h1: (props) => h('h1', { style: { color: 'red' } }, props.children),
    })" />
    

    Вы можете получить Markdown в виде строки:

    vue
    {{ myMarkdownContent.value }}
    {{ String(myMarkdownContent) }}
    {{ myMarkdownContent.toString() }}
    

    И вы можете получить доступ к метаданным вашего markdown, например:

    vue
    <component :is="myMarkdownContent.metadata" />
    <component :is="myMarkdownContent.metadata.title" />
    

    Svelte по умолчанию рендерит Markdown как HTML-строку. Используйте {@html} для его рендеринга.

    App.svelte
    <script lang="ts">
    import { useIntlayer } from "svelte-intlayer";
    import { MarkdownProvider } from "svelte-intlayer/markdown";
    import MyHeading from "./MyHeading.svelte";
    
    const content = useIntlayer("app");
    </script>
    
    <MarkdownProvider components={{ h1: MyHeading }}>
    {@html $content.myMarkdownContent}
    </MarkdownProvider>
    
    Если MarkdownProvider отсутствует, Intlayer будет рендерить markdown с использованием компилятора по умолчанию.

    Вы также можете предоставить локальные переопределения для конкретных узлов, используя метод .use():

    svelte
    {@html $content.myMarkdownContent.use({ ... })}
    

    Вы можете получить Markdown в виде строки:

    svelte
    {$content.myMarkdownContent.value}
    {String($content.myMarkdownContent)}
    {$content.myMarkdownContent.toString()}
    

    И вы можете получить доступ к метаданным вашего markdown, например:

    svelte
    {$content.myMarkdownContent.metadata}
    {$content.myMarkdownContent.metadata.title}
    

    Preact поддерживает узлы Markdown непосредственно в JSX.

    App.tsx
    import { useIntlayer } from "preact-intlayer";
    import { MarkdownProvider } from "preact-intlayer/markdown";
    
    const AppContent = () => {
    const { myMarkdownContent } = useIntlayer("app");
    return <div>{myMarkdownContent}</div>;
    };
    
    const App = () => (
    <MarkdownProvider
      components={{
        h1: ({ children }) => <h1 style={{ color: "red" }}>{children}</h1>,
        MyButton: (props) => <button {...props} />, // Компонент MDX
      }}
    >
      <AppContent />
    </MarkdownProvider>
    );
    
    Если MarkdownProvider отсутствует, intlayer будет отрисовывать markdown, используя стандартный парсер Markdown в JSX.

    Вы также можете предоставить локальные переопределения для конкретных узлов, используя метод .use():

    tsx
    {myMarkdownContent.use({
    h1: ({ children }) => <h1 style={{ color: "red" }}>{children}</h1>,
    })}
    

    Вы можете получить Markdown в виде строки:

    tsx
    {myMarkdownContent.value}
    {String(myMarkdownContent)}
    {myMarkdownContent.toString()}
    

    И вы можете получить доступ к метаданным вашего markdown, например:

    tsx
    {myMarkdownContent.metadata}
    {myMarkdownContent.metadata.title}
    

    Solid поддерживает узлы Markdown непосредственно в JSX.

    App.tsx
    import { useIntlayer } from "solid-intlayer";
    import { MarkdownProvider } from "solid-intlayer/markdown";
    
    const AppContent = () => {
    const { myMarkdownContent } = useIntlayer("app");
    return <div>{myMarkdownContent}</div>;
    };
    
    const App = () => (
    <MarkdownProvider
      components={{
        h1: (props) => <h1 style={{ color: "red" }}>{props.children}</h1>,
        MyButton: (props) => <button {...props} />, // Компонент MDX
      }}
    >
      <AppContent />
    </MarkdownProvider>
    );
    
    Если MarkdownProvider отсутствует, intlayer будет отрисовывать markdown, используя стандартный парсер Markdown в JSX.

    Вы также можете предоставить локальные переопределения для конкретных узлов, используя метод .use():

    tsx
    {myMarkdownContent.use({
    h1: (props) => <h1 style={{ color: "red" }}>{props.children}</h1>,
    })}
    

    Вы можете получить Markdown в виде строки:

    tsx
    {myMarkdownContent.value}
    {String(myMarkdownContent)}
    {myMarkdownContent.toString()}
    

    И вы можете получить доступ к метаданным вашего markdown, например:

    tsx
    {myMarkdownContent.metadata}
    {myMarkdownContent.metadata.title}
    

    Angular использует директиву [innerHTML] для рендеринга контента Markdown.

    app.component.ts
    import { Component } from "@angular/core";
    import { useIntlayer } from "angular-intlayer";
    
    @Component({
    selector: "app-root",
    template: `<div [innerHTML]="content().myMarkdownContent"></div>`,
    })
    export class AppComponent {
    content = useIntlayer("app");
    }
    
    Если провайдер IntlayerMarkdown не настроен, Intlayer будет выполнять рендеринг с использованием компилятора по умолчанию.

    Вы также можете предоставить локальные переопределения для конкретных узлов, используя метод .use():

    typescript
    content().myMarkdownContent.use({
    h1: { class: "text-3xl font-bold" },
    })
    

    Вы можете получить Markdown в виде строки:

    typescript
    content().myMarkdownContent.value
    String(content().myMarkdownContent)
    content().myMarkdownContent.toString()
    

    И вы можете получить доступ к метаданным вашего markdown, например:

    typescript
    content().myMarkdownContent.metadata
    content().myMarkdownContent.metadata.title
    

    2. Вспомогательные утилиты (только строки Markdown)

    Эти утилиты отображают сырые строки Markdown и независимы от useIntlayer. Используйте их, когда вам нужно отобразить Markdown из источников, отличных от ваших словарей.

    Компонент <MarkdownRenderer />

    Отобразите строку Markdown с конкретными параметрами.

    tsx
    import { MarkdownRenderer } from "react-intlayer/markdown";
    
    <MarkdownRenderer forceBlock={true} tagfilter={true}>
    {"# My Title"}
    </MarkdownRenderer>
    

    Hook useMarkdownRenderer()

    Получить предварительно настроенную функцию рендера.

    tsx
    import { useMarkdownRenderer } from "react-intlayer/markdown";
    
    const renderMarkdown = useMarkdownRenderer({
    forceBlock: true,
    components: { h1: (props) => <h1 {...props} className="custom" /> }
    });
    
    return renderMarkdown("# My Title");
    

    Утилита renderMarkdown()

    Автономная утилита для рендеринга вне компонентов.

    tsx
    import { renderMarkdown } from "react-intlayer/markdown";
    
    const jsx = renderMarkdown("# My Title", { forceBlock: true });
    

    Компонент <MarkdownRenderer />

    Отрендерить строку Markdown с конкретными опциями.

    tsx
    import { MarkdownRenderer } from "next-intlayer/markdown";
    
    <MarkdownRenderer forceBlock={true} tagfilter={true}>
    {"# My Title"}
    </MarkdownRenderer>
    

    Hook useMarkdownRenderer()

    Получить предварительно настроенную функцию рендеринга.

    tsx
    import { useMarkdownRenderer } from "next-intlayer/markdown";
    
    const renderMarkdown = useMarkdownRenderer({
    forceBlock: true,
    components: { h1: (props) => <h1 {...props} className="custom" /> }
    });
    
    return renderMarkdown("# My Title");
    

    Утилита renderMarkdown()

    Самостоятельная утилита для рендеринга вне компонентов.

    tsx
    import { renderMarkdown } from "next-intlayer/markdown";
    
    const jsx = renderMarkdown("# My Title", { forceBlock: true });
    

    Компонент <MarkdownRenderer />

    vue
    <script setup>
    import { MarkdownRenderer } from "vue-intlayer/markdown";
    </script>
    
    <template>
    <MarkdownRenderer :forceBlock="true" content="# My Title" />
    </template>
    

    Компонент <MarkdownRenderer />

    svelte
    <script lang="ts">
    import { MarkdownRenderer } from "svelte-intlayer/markdown";
    </script>
    
    <MarkdownRenderer forceBlock={true} value="# My Title" />
    

    useMarkdownRenderer() Hook

    svelte
    <script lang="ts">
    import { useMarkdownRenderer } from "svelte-intlayer/markdown";
    const render = useMarkdownRenderer();
    </script>
    
    {@html render("# My Title")}
    

    Утилита renderMarkdown()

    svelte
    <script lang="ts">
    import { renderMarkdown } from "svelte-intlayer/markdown";
    </script>
    
    {@html renderMarkdown("# My Title")}
    

    Компонент <MarkdownRenderer />

    tsx
    import { MarkdownRenderer } from "preact-intlayer/markdown";
    
    <MarkdownRenderer forceBlock={true}>
    {"# My Title"}
    </MarkdownRenderer>
    

    useMarkdownRenderer() Hook

    tsx
    import { useMarkdownRenderer } from "preact-intlayer/markdown";
    
    const render = useMarkdownRenderer();
    
    return <div>{render("# My Title")}</div>;
    

    renderMarkdown() Утилита

    tsx
    import { renderMarkdown } from "preact-intlayer/markdown";
    
    return <div>{renderMarkdown("# My Title")}</div>;
    

    <MarkdownRenderer /> компонент

    tsx
    import { MarkdownRenderer } from "solid-intlayer/markdown";
    
    <MarkdownRenderer forceBlock={true}>
    {"# My Title"}
    </MarkdownRenderer>
    

    Hook useMarkdownRenderer()

    tsx
    import { useMarkdownRenderer } from "solid-intlayer/markdown";
    
    const render = useMarkdownRenderer();
    
    return <div>{render("# My Title")}</div>;
    

    Утилита renderMarkdown()

    tsx
    import { renderMarkdown } from "solid-intlayer/markdown";
    
    return <div>{renderMarkdown("# My Title")}</div>;
    

    Сервис IntlayerMarkdownService

    Отрендеринг Markdown строки с использованием сервиса.

    typescript
    import { IntlayerMarkdownService } from "angular-intlayer/markdown";
    
    export class MyComponent {
    constructor(private markdownService: IntlayerMarkdownService) {}
    
    renderMarkdown(markdown: string) {
      return this.markdownService.renderMarkdown(markdown);
    }
    }
    

    Глобальная конфигурация с MarkdownProvider

    MarkdownProvider (или его эквивалент для конкретного фреймворка) настраивает pipeline рендеринга Markdown для всего приложения. Это применяется как к автоматическому рендерингу useIntlayer, так и к вспомогательным утилитам. Параметры, установленные здесь, являются значениями по умолчанию — .use() переопределяет их на уровне узла.

    AppProvider.tsx
    import { MarkdownProvider } from "react-intlayer/markdown";
    
    export const AppProvider = ({ children }) => (
    <MarkdownProvider
      components={{
        h1: (props) => <h1 style={{color: 'green'}} {...props} />,
        a: ({ href, ...props }) => <a style={{color: 'red'}} {...props} />,
        MyCustomJSXComponent: (props) => <span style={{color: 'red'}} {...props} />,
      }}
    >
      {children}
    </MarkdownProvider>
    );
    
    MDX поддерживается — любое имя компонента, используемое внутри вашего Markdown (например <MyCustomJSXComponent />), разрешается по отношению к карте components.

    Вы также можете использовать свой собственный renderer Markdown:

    AppProvider.tsx
    import { MarkdownProvider } from "react-intlayer/markdown";
    
    export const AppProvider = ({ children }) => (
    <MarkdownProvider
      renderMarkdown={async (md) => {
        // Используйте динамический импорт, чтобы уменьшить размер bundle приложения
        const { renderMarkdown } = await import('react-intlayer/markdown');
        return renderMarkdown(md);
      }}
    >
      {children}
    </MarkdownProvider>
    );
    
    Динамический импорт вашего renderer Markdown — это хороший способ уменьшить размер bundle приложения.
    AppProvider.tsx
    import { MarkdownProvider } from "next-intlayer/markdown";
    
    export const AppProvider = ({ children }) => (
    <MarkdownProvider
      components={{
        h1: (props) => <h1 style={{color: 'green'}} {...props} />,
        a: ({ href, ...props }) => <a style={{color: 'red'}} {...props} />,
        MyCustomJSXComponent: (props) => <span style={{color: 'red'}} {...props} />,
      }}
    >
      {children}
    </MarkdownProvider>
    );
    
    MDX поддерживается — любое имя компонента, используемое внутри вашего Markdown (например <MyCustomJSXComponent />), разрешается по отношению к карте components.

    Вы также можете использовать свой собственный renderer Markdown:

    AppProvider.tsx
    import { MarkdownProvider } from "next-intlayer/markdown";
    
    export const AppProvider = ({ children }) => (
    <MarkdownProvider
      renderMarkdown={async (md) => {
        // Используйте динамический импорт, чтобы уменьшить размер bundle приложения
        const { renderMarkdown } = await import('next-intlayer/markdown');
        return renderMarkdown(md);
      }}
    >
      {children}
    </MarkdownProvider>
    );
    
    Динамический импорт вашего renderer Markdown — это хороший способ уменьшить размер bundle приложения.
    main.ts
    import { createApp } from "vue";
    import { intlayer } from "vue-intlayer";
    import { intlayerMarkdown } from "vue-intlayer/markdown";
    import App from "./App.vue";
    
    const app = createApp(App);
    
    app.use(intlayer);
    app.use(intlayerMarkdown, {
    components: {
      h1: (props) =>
      h('h1', { style: { color: 'orange' }, ...props }, props.children),
      ComponentDemo: () => h('div', { style: { background: 'grey' } }, 'DEMO'),
      bold: (props) => h('strong', props),
      code: (props) => h('code', props),
    },
    });
    
    app.mount("#app");
    
    MDX поддерживается — любое имя компонента, используемое внутри вашего Markdown (например <MyCustomJSXComponent />), разрешается по отношению к карте components.

    Вы также можете использовать свой собственный renderer Markdown:

    main.ts
    import { createApp } from "vue";
    import { intlayer } from "vue-intlayer";
    import { intlayerMarkdown } from "vue-intlayer/markdown";
    import App from "./App.vue";
    
    const app = createApp(App);
    
    app.use(intlayer);
    app.use(intlayerMarkdown, {
    renderMarkdown: async (md) => {
      const { renderMarkdown } = await import('vue-intlayer/markdown');
      return renderMarkdown(md);
    },
    });
    
    app.mount("#app");
    
    Динамический импорт вашего renderer Markdown — это хороший способ уменьшить размер bundle приложения.
    App.svelte
    <script lang="ts">
    import { MarkdownProvider } from "svelte-intlayer/markdown";
    import MyHeading from "./MyHeading.svelte";
    </script>
    
    <MarkdownProvider
    components={{
      h1: MyHeading,
    }}
    >
    <slot />
    </MarkdownProvider>
    
    MDX поддерживается — любое имя компонента, используемое внутри вашего Markdown (например <MyCustomJSXComponent />), разрешается по отношению к карте components.

    Вы также можете использовать свой собственный renderer Markdown:

    App.svelte
    <script lang="ts">
    import { MarkdownProvider } from "svelte-intlayer/markdown";
    </script>
    
    <MarkdownProvider
    renderMarkdown={async (md) => {
      const { renderMarkdown } = await import('svelte-intlayer/markdown');
      return renderMarkdown(md);
    }}
    >
    <slot />
    </MarkdownProvider>
    
    Динамический импорт вашего renderer Markdown — это хороший способ уменьшить размер bundle приложения.
    AppProvider.tsx
    import { MarkdownProvider } from "preact-intlayer/markdown";
    
    export const AppProvider = ({ children }) => (
    <MarkdownProvider
      components={{
        h1: ({ children }) => <h1 className="text-2xl font-bold">{children}</h1>,
      }}
    >
      {children}
    </MarkdownProvider>
    );
    
    MDX поддерживается — любое имя компонента, используемое внутри вашего Markdown (например <MyCustomJSXComponent />), разрешается по отношению к карте components.

    Вы также можете использовать свой собственный renderer Markdown:

    AppProvider.tsx
    import { MarkdownProvider } from "preact-intlayer/markdown";
    
    export const AppProvider = ({ children }) => (
    <MarkdownProvider
      renderMarkdown={async (md) => {
        const { renderMarkdown } = await import('preact-intlayer/markdown');
        return renderMarkdown(md);
      }}
    >
      {children}
    </MarkdownProvider>
    );
    
    Динамический импорт вашего renderer Markdown — это хороший способ уменьшить размер bundle приложения.
    AppProvider.tsx
    import { MarkdownProvider } from "solid-intlayer/markdown";
    
    export const AppProvider = (props) => (
    <MarkdownProvider
      components={{
        h1: (props) => <h1 className="text-2xl font-bold">{props.children}</h1>,
      }}
    >
      {props.children}
    </MarkdownProvider>
    );
    
    MDX поддерживается — любое имя компонента, используемое внутри вашего Markdown (например <MyCustomJSXComponent />), разрешается по отношению к карте components.

    Вы также можете использовать свой собственный renderer Markdown:

    AppProvider.tsx
    import { MarkdownProvider } from "solid-intlayer/markdown";
    
    export const AppProvider = (props) => (
    <MarkdownProvider
      renderMarkdown={async (md) => {
        const { renderMarkdown } = await import('solid-intlayer/markdown');
        return renderMarkdown(md);
      }}
    >
      {props.children}
    </MarkdownProvider>
    );
    
    Динамический импорт вашего renderer Markdown — это хороший способ уменьшить размер bundle приложения.
    app.config.ts
    import { createIntlayerMarkdownProvider } from "angular-intlayer/markdown";
    
    export const appConfig: ApplicationConfig = {
    providers: [
      createIntlayerMarkdownProvider({
        components: {
          h1: { class: "text-2xl font-bold" },
        },
      }),
    ],
    };
    
    MDX поддерживается — любое имя компонента, используемое внутри вашего Markdown (например <MyCustomJSXComponent />), разрешается по отношению к карте components.

    Вы также можете использовать свой собственный renderer Markdown:

    app.config.ts
    import { createIntlayerMarkdownProvider } from "angular-intlayer/markdown";
    
    export const appConfig: ApplicationConfig = {
    providers: [
      createIntlayerMarkdownProvider({
        renderMarkdown: async (md) => {
          const { renderMarkdown } = await import('angular-intlayer/markdown');
          return renderMarkdown(md);
        },
      }),
    ],
    };
    
    Динамический импорт вашего renderer Markdown — это хороший способ уменьшить размер bundle приложения.

    Suspense

    Рендерер Markdown в Intlayer загружается динамически. Несмотря на оптимизацию, базовый фрагмент парсера составляет около 55 КБ. Его синхронная загрузка задерживает первоначальный рендеринг страницы и ухудшает First Contentful Paint (FCP).

    Чтобы предотвратить блокировку пользовательского интерфейса, Intlayer интегрируется с API React Suspense. Он загружает парсер в фоновом режиме и выдает Promise во время загрузки.

    Оберните любой компонент, рендерящий Intlayer Markdown, в границу <Suspense>. Это отобразит локализованное резервное состояние во время загрузки фрагмента, позволяя остальной части вашего DOM рендериться немедленно.

    Предупреждение: Если вы не предоставите границу <Suspense>, React приостановит работу на корневом уровне или заблокирует рендеринг всего дерева компонентов до тех пор, пока фрагмент размером 55 КБ не будет полностью загружен.

    В маршрутизаторе Next.js App Router вы можете использовать либо React Suspense для клиентских компонентов, либо файл loading.tsx для серверных компонентов.

    Клиентский компонент:

    components/MyComponent.tsx
    "use client";
    import { useIntlayer } from "next-intlayer";
    import { Suspense } from "react";
    
    const MyComponent = () => {
      const markdownContent = useIntlayer("my-markdown");
    
      return (
        <Suspense fallback={<div>Loading...</div>}>{markdownContent}</Suspense>
      );
    };
    

    Серверный компонент с loading.tsx:

    app/loading.tsx
    export default function Loading() {
      return <div>Loading...</div>;
    }
    
    app/page.tsx
    import { useIntlayer } from "next-intlayer/server";
    
    const MyPage = () => {
      const markdownContent = useIntlayer("my-markdown");
      return <div>{markdownContent}</div>;
    };
    
    export default MyPage;
    
    tsx
    import { useIntlayer } from "react-intlayer";
    import { Suspense } from "react";
    
    const MyComponent = () => {
      const markdownContent = useIntlayer("my-markdown");
    
      return (
        <Suspense fallback={<div>Loading...</div>}>{markdownContent}</Suspense>
      );
    };
    

    В Vue есть встроенный компонент <Suspense>. Оберните компонент, рендерящий содержимое Markdown, в границу <Suspense>.

    MyComponent.vue
    <script setup>
    import { useIntlayer } from "vue-intlayer";
    
    const { markdownContent } = useIntlayer("my-markdown");
    </script>
    
    <template>
      <Suspense>
        <component :is="markdownContent" />
        <template #fallback>
          <div>Loading...</div>
        </template>
      </Suspense>
    </template>
    

    Svelte не имеет эквивалента API Suspense. Используйте блок {#await} для обработки асинхронного рендеринга содержимого Markdown.

    MyComponent.svelte
    <script lang="ts">
    import { useIntlayer } from "svelte-intlayer";
    
    const content = useIntlayer("my-markdown");
    </script>
    
    {#await $content.markdownContent}
      <div>Loading...</div>
    {:then rendered}
      {@html rendered}
    {/await}
    

    Preact поддерживает API React Suspense через preact/compat.

    MyComponent.tsx
    import { useIntlayer } from "preact-intlayer";
    import { Suspense } from "preact/compat";
    
    const MyComponent = () => {
      const markdownContent = useIntlayer("my-markdown");
    
      return (
        <Suspense fallback={<div>Loading...</div>}>{markdownContent}</Suspense>
      );
    };
    

    В Solid есть собственный компонент <Suspense> из solid-js.

    MyComponent.tsx
    import { useIntlayer } from "solid-intlayer";
    import { Suspense } from "solid-js";
    
    const MyComponent = () => {
      const { markdownContent } = useIntlayer("my-markdown");
    
      return (
        <Suspense fallback={<div>Loading...</div>}>{markdownContent}</Suspense>
      );
    };
    

    Angular не имеет API Suspense. Используйте отложенные представления (@defer) для обработки лениво загружаемого содержимого Markdown (требуется Angular 17+).

    my.component.ts
    import { Component } from "@angular/core";
    import { useIntlayer } from "angular-intlayer";
    
    @Component({
      selector: "app-my",
      template: `
        @defer {
          <div [innerHTML]="content().markdownContent"></div>
        } @loading {
          <div>Loading...</div>
        }
      `,
    })
    export class MyComponent {
      content = useIntlayer("my-markdown");
    }
    

    Рендеринг на стороне сервера (SSR) и гидратация

    По сравнению с другими парсерами Markdown, такими как remark / rehype, Intlayer Markdown не имеет зависимостей и работает как на клиенте, так и на сервере.

    Однако Intlayer оптимизирует синтаксический анализ для фреймворков серверного рендеринга (SSR) (таких как Next.js App Router, React Router, Nuxt, SvelteKit и т. д.).

    Вместо отправки необработанных строк Markdown клиенту и их анализа в браузере (что приводит к снижению производительности), Intlayer позволяет предварительно проанализировать Markdown в абстрактное синтаксическое дерево (AST) на сервере.

    Вы можете использовать функцию parseMarkdown из пакета Intlayer вашего фреймворка на стороне сервера для генерации сериализуемого AST (объекта ParsedMarkdown) и передачи его непосредственно на фронтенд. Все утилиты рендеринга Intlayer (такие как <MarkdownRenderer>, useMarkdownRenderer и т. д.) автоматически принимают этот объект AST и плавно рендерят его.

    Пример в архитектуре Сервер/Клиент

    server.ts
    import { parseMarkdown } from "react-intlayer/markdown";
    
    // 1. На сервере: преобразовать markdown в сериализуемое AST
    export const loader = async () => {
    const markdownString = "## My title \n\nLorem Ipsum";
    const ast = parseMarkdown(markdownString);
    
    // Возвратить AST клиенту в формате JSON
    return Response.json({ content: ast });
    };
    
    client.tsx
    import { useLoaderData } from "react-router";
    import { MarkdownRenderer } from "react-intlayer/markdown";
    
    // 2. На клиенте: отрендерить AST напрямую без повторного анализа
    export default function Page() {
    const { content } = useLoaderData();
    
    // Рендерер принимает либо необработанную строку, либо проанализированное AST
    return <MarkdownRenderer content={content} />;
    }
    
    app/page.tsx
    import { parseMarkdown } from "next-intlayer/markdown";
    import { MarkdownRenderer } from "next-intlayer/markdown";
    
    export default async function Page() {
    // 1. Преобразовать markdown в сериализуемое AST на сервере
    const markdownString = "## My title \n\nLorem Ipsum";
    const ast = parseMarkdown(markdownString);
    
    // 2. Отрендерить AST напрямую
    // В серверном компоненте это работает бесшовно и передает AST
    // напрямую в базовые клиентские компоненты, если это необходимо.
    return <MarkdownRenderer content={ast} />;
    }
    
    pages/index.vue
    <script setup lang="ts">
    import { parseMarkdown } from "vue-intlayer/markdown";
    import { MarkdownRenderer } from "vue-intlayer/markdown";
    
    // 1. Получить и преобразовать markdown в AST на сервере
    const { data: ast } = await useAsyncData('markdown', () => {
    const markdownString = "## My title \n\nLorem Ipsum";
    return parseMarkdown(markdownString);
    });
    </script>
    
    <template>
    <!-- 2. На клиенте: отрендерить AST напрямую без повторного анализа -->
    <MarkdownRenderer :content="ast" />
    </template>
    
    +page.server.ts
    import { parseMarkdown } from "svelte-intlayer/markdown";
    
    // 1. На сервере: преобразовать markdown в сериализуемое AST
    export const load = async () => {
    const markdownString = "## My title \n\nLorem Ipsum";
    const ast = parseMarkdown(markdownString);
    
    // Возвратить AST клиенту
    return { content: ast };
    };
    
    +page.svelte
    <script lang="ts">
    import { MarkdownRenderer } from "svelte-intlayer/markdown";
    export let data;
    </script>
    
    <!-- 2. На клиенте: отрендерить AST напрямую без повторного анализа -->
    <MarkdownRenderer value={data.content} />
    

    Angular SSR обычно разрешает данные на сервере во время первоначальной загрузки и выполняет гидратацию на клиенте. Вы можете использовать резолверы для передачи AST.

    app.resolver.ts
    import { Injectable } from "@angular/core";
    import { Resolve } from "@angular/router";
    import { parseMarkdown, type ParsedMarkdown } from "angular-intlayer/markdown";
    
    @Injectable({ providedIn: "root" })
    export class MarkdownResolver implements Resolve<ParsedMarkdown> {
    resolve(): ParsedMarkdown {
      const markdownString = "## My title \n\nLorem Ipsum";
      // 1. На сервере: преобразовать markdown в сериализуемое AST
      return parseMarkdown(markdownString);
    }
    }
    
    app.component.ts
    import { Component } from "@angular/core";
    import { ActivatedRoute } from "@angular/router";
    import { IntlayerMarkdownService, type ParsedMarkdown } from "angular-intlayer/markdown";
    
    @Component({
    selector: "app-root",
    template: `<div [innerHTML]="renderedMarkdown"></div>`,
    })
    export class AppComponent {
    renderedMarkdown: string = "";
    
    constructor(
      private route: ActivatedRoute,
      private markdownService: IntlayerMarkdownService
    ) {
      // 2. На клиенте: отрендерить AST напрямую без повторного анализа
      this.route.data.subscribe((data) => {
        this.renderedMarkdown = this.markdownService.renderMarkdown(
          data.markdownAst
        ) as string;
      });
    }
    }
    

    Этот подход гарантирует, что логика анализа Markdown полностью выполняется на сервере, что значительно сокращает время выполнения на стороне клиента и повышает скорость первоначальной гидратации.

    Справочник по опциям

    Эти параметры могут быть переданы в MarkdownProvider, MarkdownRenderer, useMarkdownRenderer и renderMarkdown.

    Option Type Default Описание
    forceBlock boolean false Принудительно оборачивает вывод в блочный элемент (например, <div>).
    forceInline boolean false Принудительно оборачивает вывод во встроенный элемент (например, <span>).
    tagfilter boolean true Включает фильтр тегов GitHub для повышения безопасности путем удаления опасных тегов HTML.
    preserveFrontmatter boolean false Если true, начальный мета-блок (frontmatter) в строке Markdown не будет удален.
    components Overrides {} Карта HTML-тегов в пользовательские компоненты (например, { h1: MyHeading }).
    wrapper Component null Пользовательский компонент для обертывания отрендеренного Markdown.
    renderMarkdown Function null Пользовательская функция рендеринга для полной замены компилятора Markdown по умолчанию.