Ask your question and get a summary of the document by referencing this page and the AI provider of your choice
The content of this page was translated using an AI.
See the last version of the original content in EnglishIf you have an idea for improving this documentation, please feel free to contribute by submitting a pull request on GitHub.
GitHub link to the documentationCopy doc Markdown to clipboard
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.
Table of contents
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>withNextLinkor<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:MarkdownProviderexisted in v7 but now integrates with these new tools). - HTML:
HTMLRenderer,useHTMLRenderer,renderHTML,HTMLProvider.
Examples: Markdown Rendering Tools
1. Using the Component:
Copy the code to the clipboard
import { MarkdownRenderer } from "react-intlayer/markdown";<MarkdownRenderer forceBlock={true} components={{ h1: ({ children }) => <h1 className="text-2xl">{children}</h1> }}> {"# My Title"}</MarkdownRenderer>2. Using the Hook:
Copy the code to the clipboard
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. Using the Utility Function:
Copy the code to the clipboard
import { renderMarkdown } from "react-intlayer/markdown";const html = renderMarkdown("# My Title", { forceBlock: true});Examples: HTML Rendering Tools
1. Using the Component:
Copy the code to the clipboard
import { HTMLRenderer } from "react-intlayer/html";<HTMLRenderer components={{ p: ({ children }) => <p className="mb-4">{children}</p> }}> {"<p>Hello World</p>"}</HTMLRenderer>2. Using the Hook:
Copy the code to the clipboard
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. Using the Utility Function:
Copy the code to the clipboard
import { renderHTML } from "react-intlayer/html";const html = renderHTML("<p>Hello World</p>");For more details, see the HTML Content Documentation and Markdown Documentation.
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, andviteRewriteto provide idiomatic pattern syntax for each router. useRewriteURLHook: 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:
Copy the code to the clipboard
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;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.
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:
Copy the code to the clipboard
import { insert } from "intlayer";export default { key: "my-key", content: { myInsertion: insert("Hi {{name}}"), },};Copy the code to the clipboard
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>);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:
Copy the code to the clipboard
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:
Copy the code to the clipboard
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:
Copy the code to the clipboard
export default { dictionary: { // contentAutoTransformation: false (default) contentAutoTransformation: { markdown: true, html: true, insertion: false, // Disable automatic insertion detection }, },};v7 behaviour (Manual wrapping):
Copy the code to the clipboard
import { md, insert } from "intlayer";export default { key: "my-key", content: { myMarkdown: md("## Hello World"), myInsertion: insert("Hi {{name}}"), },};v8 behaviour (Automatic detection):
Copy the code to the clipboard
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:
Copy the code to the clipboard
{ "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.
Copy the code to the clipboard
import { useIntl } from "next-intlayer";const intl = useIntl();const formattedPrice = new intl.NumberFormat({ style: "currency", currency: "USD",}).format(123.45);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.
Copy the code to the clipboard
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()], ],};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:
Open the table in a modal to view all data content clearly
| 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:
Copy the code to the clipboard
export default { dictionary: { importMode: "dynamic", // Global default }, // ...};Dictionary Example:
Copy the code to the clipboard
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:
Copy the code to the clipboard
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:
dictionariesDirmoduleAugmentationDirunmergedDictionariesDirtypesDirmainDirconfigDircacheDiroutputFilesPatternWithPath
v7 behaviour:
Copy the code to the clipboard
export default { content: { contentDir: ["src"], dictionariesDir: ".intlayer/dictionary", // Mixed with source config },};v8 behaviour:
Copy the code to the clipboard
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:
Copy the code to the clipboard
export default { content: { contentDir: ["src", "@packages/design-system"], // Used for both content and code },};v8 behaviour:
Copy the code to the clipboard
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
liveproperty: Theliveproperty in dictionaries is removed. UseimportMode: 'fetch'instead.- importMode: The
build.importModeproperty in configuration has been deprecated. Usedictionary.importModeinstead. contentDirandcodeDir:contentDiris now specifically for content files. A newcodeDirproperty has been added for code transformation. IfcodeDiris not set, Intlayer will fallback tocontentDirand log a warning.- Schema Validation: To use the new
schemafeature, ensure you havezodinstalled in your project.