@intlayer/docs 7.0.0 → 7.0.2-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +4 -11
  2. package/dist/cjs/common.cjs +5 -1
  3. package/dist/cjs/common.cjs.map +1 -1
  4. package/dist/esm/common.mjs +5 -1
  5. package/dist/esm/common.mjs.map +1 -1
  6. package/dist/types/common.d.ts.map +1 -1
  7. package/docs/ar/intlayer_with_nextjs_15.md +10 -6
  8. package/docs/ar/intlayer_with_nextjs_16.md +11 -7
  9. package/docs/de/intlayer_with_nextjs_15.md +10 -6
  10. package/docs/de/intlayer_with_nextjs_16.md +11 -7
  11. package/docs/en/CI_CD.md +4 -0
  12. package/docs/en/configuration.md +29 -42
  13. package/docs/en/formatters.md +4 -0
  14. package/docs/en/how_works_intlayer.md +4 -0
  15. package/docs/en/index.md +1 -0
  16. package/docs/en/intlayer_CMS.md +6 -0
  17. package/docs/en/intlayer_cli.md +8 -0
  18. package/docs/en/intlayer_with_nextjs_14.md +14 -6
  19. package/docs/en/intlayer_with_nextjs_15.md +14 -6
  20. package/docs/en/intlayer_with_nextjs_16.md +15 -7
  21. package/docs/en/intlayer_with_nextjs_page_router.md +4 -0
  22. package/docs/en/intlayer_with_nuxt.md +4 -0
  23. package/docs/en/intlayer_with_react_native+expo.md +7 -0
  24. package/docs/en/intlayer_with_react_router_v7.md +4 -0
  25. package/docs/en/intlayer_with_tanstack.md +4 -0
  26. package/docs/en/intlayer_with_vite+preact.md +4 -0
  27. package/docs/en/intlayer_with_vite+react.md +4 -0
  28. package/docs/en/intlayer_with_vite+solid.md +4 -0
  29. package/docs/en/intlayer_with_vite+svelte.md +4 -0
  30. package/docs/en/intlayer_with_vite+vue.md +4 -0
  31. package/docs/en/introduction.md +1 -0
  32. package/docs/en/roadmap.md +6 -0
  33. package/docs/en-GB/intlayer_with_nextjs_14.md +10 -6
  34. package/docs/en-GB/intlayer_with_nextjs_15.md +10 -6
  35. package/docs/en-GB/intlayer_with_nextjs_16.md +11 -7
  36. package/docs/es/intlayer_with_nextjs_14.md +11 -6
  37. package/docs/es/intlayer_with_nextjs_15.md +7 -4
  38. package/docs/es/intlayer_with_nextjs_16.md +11 -7
  39. package/docs/fr/intlayer_with_nextjs_15.md +10 -6
  40. package/docs/fr/intlayer_with_nextjs_16.md +12 -25
  41. package/docs/hi/intlayer_with_nextjs_15.md +10 -6
  42. package/docs/hi/intlayer_with_nextjs_16.md +11 -7
  43. package/docs/id/intlayer_with_nextjs_16.md +11 -7
  44. package/docs/it/intlayer_with_nextjs_15.md +10 -6
  45. package/docs/it/intlayer_with_nextjs_16.md +11 -7
  46. package/docs/ja/intlayer_with_nextjs_14.md +11 -6
  47. package/docs/ja/intlayer_with_nextjs_15.md +10 -6
  48. package/docs/ja/intlayer_with_nextjs_16.md +11 -7
  49. package/docs/ko/intlayer_with_nextjs_14.md +11 -6
  50. package/docs/ko/intlayer_with_nextjs_15.md +10 -6
  51. package/docs/ko/intlayer_with_nextjs_16.md +11 -7
  52. package/docs/pl/intlayer_with_nextjs_16.md +11 -7
  53. package/docs/pt/intlayer_with_nextjs_14.md +10 -7
  54. package/docs/pt/intlayer_with_nextjs_15.md +10 -6
  55. package/docs/pt/intlayer_with_nextjs_16.md +11 -7
  56. package/docs/ru/intlayer_with_nextjs_15.md +7 -4
  57. package/docs/ru/intlayer_with_nextjs_16.md +11 -7
  58. package/docs/tr/intlayer_with_nextjs_15.md +10 -6
  59. package/docs/tr/intlayer_with_nextjs_16.md +11 -7
  60. package/docs/vi/intlayer_with_nextjs_16.md +11 -7
  61. package/docs/zh/intlayer_with_nextjs_14.md +11 -6
  62. package/docs/zh/intlayer_with_nextjs_15.md +7 -4
  63. package/docs/zh/intlayer_with_nextjs_16.md +11 -7
  64. package/package.json +14 -14
  65. package/src/common.ts +7 -1
@@ -27,13 +27,7 @@ This is not a full tutorial. It’s a comparison to help you pick.
27
27
 
28
28
  We focus on **Next.js 13+ App Router** (with **React Server Components**) and evaluate:
29
29
 
30
- 1. **Architecture & content organization**
31
- 2. **TypeScript & safety**
32
- 3. **Missing translation handling**
33
- 4. **Routing & middleware**
34
- 5. **Performance & loading behavior**
35
- 6. **Developer experience (DX), tooling & maintenance**
36
- 7. **SEO & large-project scalability**
30
+ <TOC>
37
31
 
38
32
  > **tl;dr**: All three can localize a Next.js app. If you want **component-scoped content**, **strict TypeScript types**, **build-time missing-key checks**, **tree-shaken dictionaries**, and **first-class App Router + SEO helpers**, **Intlayer** is the most complete, modern choice.
39
33
 
@@ -1402,14 +1396,13 @@ export const config = {
1402
1396
  Intlayer provides built-in middleware handling through the `next-intlayer` package configuration.
1403
1397
 
1404
1398
  ```ts fileName="src/middleware.ts"
1405
- import { intlayerMiddleware } from 'next-intlayer/middleware';
1399
+ import { intlayerMiddleware } from "next-intlayer/middleware";
1406
1400
 
1407
- export const middleware = intlayerMiddleware()
1401
+ export const middleware = intlayerMiddleware();
1408
1402
 
1409
1403
  // applies this middleware only to files in the app directory
1410
1404
  export const config = {
1411
- matcher:
1412
- "/((?!api|_next|static|.*\\..*).*)",
1405
+ matcher: "/((?!api|_next|static|.*\\..*).*)",
1413
1406
  };
1414
1407
  ```
1415
1408
 
@@ -27,11 +27,15 @@ const getFile = async (files, docKey, locale = defaultLocale) => {
27
27
  };
28
28
  const formatMetadata = (docKey, file, locale = defaultLocale) => {
29
29
  const metadata = (0, __intlayer_core.getMarkdownMetadata)(file);
30
- const relativeUrl = (0, node_path.join)("/", ...metadata.slugs ?? []);
30
+ const slugs = (metadata.slugs ?? []).map(String);
31
+ const keywords = (metadata.keywords ?? []).map(String);
32
+ const relativeUrl = (0, node_path.join)("/", ...slugs);
31
33
  const slicedDocKey = docKey.slice(1);
32
34
  return {
33
35
  ...metadata,
34
36
  docKey,
37
+ slugs,
38
+ keywords,
35
39
  githubUrl: `${GITHUB_URL_PREFIX}${slicedDocKey}`.replace("/en/", `/${locale}/`),
36
40
  relativeUrl: (0, __intlayer_core.getLocalizedUrl)(relativeUrl, locale),
37
41
  url: (0, __intlayer_core.getLocalizedUrl)((0, node_path.join)(URL_PREFIX, relativeUrl), locale)
@@ -1 +1 @@
1
- {"version":3,"file":"common.cjs","names":["Locales","fileMetadataArray: FileMetadata[]"],"sources":["../../src/common.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { getLocalizedUrl, getMarkdownMetadata } from '@intlayer/core';\nimport { Locales, type LocalesValues } from '@intlayer/types';\n\nexport const defaultLocale = Locales.ENGLISH;\n\nexport const GITHUB_URL_PREFIX =\n 'https://github.com/aymericzip/intlayer/blob/main/docs';\nexport const URL_PREFIX = 'https://intlayer.org/';\n\nexport const getKeys = <T extends Record<string, any>>(obj: T): (keyof T)[] =>\n Object.keys(obj) as (keyof T)[];\n\nexport const getFiles = async <\n F extends Record<`./${string}`, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n lang: LocalesValues = defaultLocale as LocalesValues\n): Promise<Record<string, string>> => {\n const filesEntries = await Promise.all(\n Object.entries(files)\n .map(([key, value]) => [key, value[lang as LocalesValues]])\n .map(async ([key, value]) => [key, await value])\n );\n const filesResult = Object.fromEntries(filesEntries);\n return filesResult;\n};\n\nexport const getFile = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n docKey: keyof F,\n locale: LocalesValues = defaultLocale as LocalesValues\n): Promise<string> => {\n const fileRecord = files[docKey];\n\n if (!fileRecord) {\n throw new Error(`File ${docKey as string} not found`);\n }\n\n const file = await files[docKey]?.[locale];\n\n if (!file) {\n const englishFile = await files[docKey][defaultLocale as LocalesValues];\n\n if (!englishFile) {\n throw new Error(`File ${docKey as string} not found`);\n }\n\n return englishFile;\n }\n\n return file;\n};\n\nexport type FileMetadata = {\n docKey: string;\n url: string;\n relativeUrl: string;\n githubUrl: string;\n title: string;\n slugs: string[];\n description: string;\n keywords: string[];\n updatedAt: string;\n createdAt: string;\n author?: string;\n youtubeVideo?: string;\n applicationTemplate?: string;\n history?: {\n version: string;\n date: string;\n changes: string;\n }[];\n};\n\nexport const formatMetadata = (\n docKey: string,\n file: string,\n locale: LocalesValues = defaultLocale as LocalesValues\n): FileMetadata => {\n const metadata = getMarkdownMetadata(file);\n const relativeUrl = join('/', ...(metadata.slugs ?? []));\n\n const slicedDocKey = docKey.slice(1);\n\n return {\n ...metadata,\n docKey,\n githubUrl: `${GITHUB_URL_PREFIX}${slicedDocKey}`.replace(\n '/en/',\n `/${locale}/`\n ),\n relativeUrl: getLocalizedUrl(relativeUrl, locale),\n url: getLocalizedUrl(join(URL_PREFIX, relativeUrl), locale),\n } as FileMetadata;\n};\n\nexport const getFileMetadata = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n R extends FileMetadata,\n>(\n files: F,\n docKey: keyof F,\n locale: LocalesValues = defaultLocale as LocalesValues\n): Promise<R> => {\n const file = await getFile(files, docKey, locale);\n\n return formatMetadata(docKey as string, file, locale) as R;\n};\n\nexport const getFileMetadataRecord = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n locale: LocalesValues = defaultLocale as LocalesValues\n): Promise<Record<keyof F, FileMetadata>> => {\n const filesEntries = await Promise.all(\n Object.entries(files).map(async ([key]) => [\n key,\n await getFileMetadata(files, key as keyof F, locale),\n ])\n );\n const filesResult = Object.fromEntries(filesEntries);\n return filesResult;\n};\n\nexport const getFileMetadataBySlug = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n slugs: string | string[],\n locale: LocalesValues = defaultLocale as LocalesValues,\n strict = false\n) => {\n const slugsArray = Array.isArray(slugs) ? slugs : [slugs];\n const filesMetadata = await getFileMetadataRecord(\n files,\n defaultLocale as LocalesValues\n );\n\n let fileMetadataArray: FileMetadata[] = Object.values(filesMetadata).filter(\n (fileMetadata) =>\n slugsArray.every((slug) => fileMetadata.slugs?.includes(slug))\n );\n\n if (strict) {\n fileMetadataArray = fileMetadataArray.filter(\n (fileMetadata) => fileMetadata.slugs.length === slugsArray.length\n );\n }\n\n if (locale !== defaultLocale) {\n const localizedFileMetadata = await Promise.all(\n fileMetadataArray.map(\n async (fileMetadata) =>\n await getFileMetadata(files, fileMetadata.docKey, locale)\n )\n );\n\n return localizedFileMetadata;\n }\n\n return fileMetadataArray;\n};\n\nexport const getFileBySlug = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n slugs: string | string[],\n locale: LocalesValues = defaultLocale as LocalesValues,\n strict = false\n) => {\n const slugsArray = Array.isArray(slugs) ? slugs : [slugs];\n const filesMetadata = await getFileMetadataRecord(\n files,\n defaultLocale as LocalesValues\n );\n\n let fileMetadataArray = Object.values(filesMetadata).filter((fileMetadata) =>\n slugsArray.every((slug) => fileMetadata.slugs?.includes(slug))\n );\n\n if (strict) {\n fileMetadataArray = fileMetadataArray.filter(\n (fileMetadata) => fileMetadata.slugs.length === slugsArray.length\n );\n }\n\n const fileList = await Promise.all(\n fileMetadataArray.map(async (fileMetadata) => {\n const file = await getFile(files, fileMetadata.docKey, locale);\n return file;\n })\n );\n\n return fileList;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"common.cjs","names":["Locales","fileMetadataArray: FileMetadata[]"],"sources":["../../src/common.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { getLocalizedUrl, getMarkdownMetadata } from '@intlayer/core';\nimport { Locales, type LocalesValues } from '@intlayer/types';\n\nexport const defaultLocale = Locales.ENGLISH;\n\nexport const GITHUB_URL_PREFIX =\n 'https://github.com/aymericzip/intlayer/blob/main/docs';\nexport const URL_PREFIX = 'https://intlayer.org/';\n\nexport const getKeys = <T extends Record<string, any>>(obj: T): (keyof T)[] =>\n Object.keys(obj) as (keyof T)[];\n\nexport const getFiles = async <\n F extends Record<`./${string}`, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n lang: LocalesValues = defaultLocale as LocalesValues\n): Promise<Record<string, string>> => {\n const filesEntries = await Promise.all(\n Object.entries(files)\n .map(([key, value]) => [key, value[lang as LocalesValues]])\n .map(async ([key, value]) => [key, await value])\n );\n const filesResult = Object.fromEntries(filesEntries);\n return filesResult;\n};\n\nexport const getFile = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n docKey: keyof F,\n locale: LocalesValues = defaultLocale as LocalesValues\n): Promise<string> => {\n const fileRecord = files[docKey];\n\n if (!fileRecord) {\n throw new Error(`File ${docKey as string} not found`);\n }\n\n const file = await files[docKey]?.[locale];\n\n if (!file) {\n const englishFile = await files[docKey][defaultLocale as LocalesValues];\n\n if (!englishFile) {\n throw new Error(`File ${docKey as string} not found`);\n }\n\n return englishFile;\n }\n\n return file;\n};\n\nexport type FileMetadata = {\n docKey: string;\n url: string;\n relativeUrl: string;\n githubUrl: string;\n title: string;\n slugs: string[];\n description: string;\n keywords: string[];\n updatedAt: string;\n createdAt: string;\n author?: string;\n youtubeVideo?: string;\n applicationTemplate?: string;\n history?: {\n version: string;\n date: string;\n changes: string;\n }[];\n};\n\nexport const formatMetadata = (\n docKey: string,\n file: string,\n locale: LocalesValues = defaultLocale as LocalesValues\n): FileMetadata => {\n const metadata = getMarkdownMetadata(file);\n\n const slugs = (metadata.slugs ?? []).map(String);\n const keywords = (metadata.keywords ?? []).map(String);\n\n const relativeUrl = join('/', ...slugs);\n\n const slicedDocKey = docKey.slice(1);\n\n return {\n ...metadata,\n docKey,\n slugs,\n keywords,\n githubUrl: `${GITHUB_URL_PREFIX}${slicedDocKey}`.replace(\n '/en/',\n `/${locale}/`\n ),\n relativeUrl: getLocalizedUrl(relativeUrl, locale),\n url: getLocalizedUrl(join(URL_PREFIX, relativeUrl), locale),\n } as FileMetadata;\n};\n\nexport const getFileMetadata = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n R extends FileMetadata,\n>(\n files: F,\n docKey: keyof F,\n locale: LocalesValues = defaultLocale as LocalesValues\n): Promise<R> => {\n const file = await getFile(files, docKey, locale);\n\n return formatMetadata(docKey as string, file, locale) as R;\n};\n\nexport const getFileMetadataRecord = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n locale: LocalesValues = defaultLocale as LocalesValues\n): Promise<Record<keyof F, FileMetadata>> => {\n const filesEntries = await Promise.all(\n Object.entries(files).map(async ([key]) => [\n key,\n await getFileMetadata(files, key as keyof F, locale),\n ])\n );\n const filesResult = Object.fromEntries(filesEntries);\n return filesResult;\n};\n\nexport const getFileMetadataBySlug = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n slugs: string | string[],\n locale: LocalesValues = defaultLocale as LocalesValues,\n strict = false\n) => {\n const slugsArray = Array.isArray(slugs) ? slugs : [slugs];\n const filesMetadata = await getFileMetadataRecord(\n files,\n defaultLocale as LocalesValues\n );\n\n let fileMetadataArray: FileMetadata[] = Object.values(filesMetadata).filter(\n (fileMetadata) =>\n slugsArray.every((slug) => fileMetadata.slugs?.includes(slug))\n );\n\n if (strict) {\n fileMetadataArray = fileMetadataArray.filter(\n (fileMetadata) => fileMetadata.slugs.length === slugsArray.length\n );\n }\n\n if (locale !== defaultLocale) {\n const localizedFileMetadata = await Promise.all(\n fileMetadataArray.map(\n async (fileMetadata) =>\n await getFileMetadata(files, fileMetadata.docKey, locale)\n )\n );\n\n return localizedFileMetadata;\n }\n\n return fileMetadataArray;\n};\n\nexport const getFileBySlug = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n slugs: string | string[],\n locale: LocalesValues = defaultLocale as LocalesValues,\n strict = false\n) => {\n const slugsArray = Array.isArray(slugs) ? slugs : [slugs];\n const filesMetadata = await getFileMetadataRecord(\n files,\n defaultLocale as LocalesValues\n );\n\n let fileMetadataArray = Object.values(filesMetadata).filter((fileMetadata) =>\n slugsArray.every((slug) => fileMetadata.slugs?.includes(slug))\n );\n\n if (strict) {\n fileMetadataArray = fileMetadataArray.filter(\n (fileMetadata) => fileMetadata.slugs.length === slugsArray.length\n );\n }\n\n const fileList = await Promise.all(\n fileMetadataArray.map(async (fileMetadata) => {\n const file = await getFile(files, fileMetadata.docKey, locale);\n return file;\n })\n );\n\n return fileList;\n};\n"],"mappings":"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"}
@@ -23,11 +23,15 @@ const getFile = async (files, docKey, locale = defaultLocale) => {
23
23
  };
24
24
  const formatMetadata = (docKey, file, locale = defaultLocale) => {
25
25
  const metadata = getMarkdownMetadata(file);
26
- const relativeUrl = join("/", ...metadata.slugs ?? []);
26
+ const slugs = (metadata.slugs ?? []).map(String);
27
+ const keywords = (metadata.keywords ?? []).map(String);
28
+ const relativeUrl = join("/", ...slugs);
27
29
  const slicedDocKey = docKey.slice(1);
28
30
  return {
29
31
  ...metadata,
30
32
  docKey,
33
+ slugs,
34
+ keywords,
31
35
  githubUrl: `${GITHUB_URL_PREFIX}${slicedDocKey}`.replace("/en/", `/${locale}/`),
32
36
  relativeUrl: getLocalizedUrl(relativeUrl, locale),
33
37
  url: getLocalizedUrl(join(URL_PREFIX, relativeUrl), locale)
@@ -1 +1 @@
1
- {"version":3,"file":"common.mjs","names":["fileMetadataArray: FileMetadata[]"],"sources":["../../src/common.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { getLocalizedUrl, getMarkdownMetadata } from '@intlayer/core';\nimport { Locales, type LocalesValues } from '@intlayer/types';\n\nexport const defaultLocale = Locales.ENGLISH;\n\nexport const GITHUB_URL_PREFIX =\n 'https://github.com/aymericzip/intlayer/blob/main/docs';\nexport const URL_PREFIX = 'https://intlayer.org/';\n\nexport const getKeys = <T extends Record<string, any>>(obj: T): (keyof T)[] =>\n Object.keys(obj) as (keyof T)[];\n\nexport const getFiles = async <\n F extends Record<`./${string}`, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n lang: LocalesValues = defaultLocale as LocalesValues\n): Promise<Record<string, string>> => {\n const filesEntries = await Promise.all(\n Object.entries(files)\n .map(([key, value]) => [key, value[lang as LocalesValues]])\n .map(async ([key, value]) => [key, await value])\n );\n const filesResult = Object.fromEntries(filesEntries);\n return filesResult;\n};\n\nexport const getFile = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n docKey: keyof F,\n locale: LocalesValues = defaultLocale as LocalesValues\n): Promise<string> => {\n const fileRecord = files[docKey];\n\n if (!fileRecord) {\n throw new Error(`File ${docKey as string} not found`);\n }\n\n const file = await files[docKey]?.[locale];\n\n if (!file) {\n const englishFile = await files[docKey][defaultLocale as LocalesValues];\n\n if (!englishFile) {\n throw new Error(`File ${docKey as string} not found`);\n }\n\n return englishFile;\n }\n\n return file;\n};\n\nexport type FileMetadata = {\n docKey: string;\n url: string;\n relativeUrl: string;\n githubUrl: string;\n title: string;\n slugs: string[];\n description: string;\n keywords: string[];\n updatedAt: string;\n createdAt: string;\n author?: string;\n youtubeVideo?: string;\n applicationTemplate?: string;\n history?: {\n version: string;\n date: string;\n changes: string;\n }[];\n};\n\nexport const formatMetadata = (\n docKey: string,\n file: string,\n locale: LocalesValues = defaultLocale as LocalesValues\n): FileMetadata => {\n const metadata = getMarkdownMetadata(file);\n const relativeUrl = join('/', ...(metadata.slugs ?? []));\n\n const slicedDocKey = docKey.slice(1);\n\n return {\n ...metadata,\n docKey,\n githubUrl: `${GITHUB_URL_PREFIX}${slicedDocKey}`.replace(\n '/en/',\n `/${locale}/`\n ),\n relativeUrl: getLocalizedUrl(relativeUrl, locale),\n url: getLocalizedUrl(join(URL_PREFIX, relativeUrl), locale),\n } as FileMetadata;\n};\n\nexport const getFileMetadata = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n R extends FileMetadata,\n>(\n files: F,\n docKey: keyof F,\n locale: LocalesValues = defaultLocale as LocalesValues\n): Promise<R> => {\n const file = await getFile(files, docKey, locale);\n\n return formatMetadata(docKey as string, file, locale) as R;\n};\n\nexport const getFileMetadataRecord = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n locale: LocalesValues = defaultLocale as LocalesValues\n): Promise<Record<keyof F, FileMetadata>> => {\n const filesEntries = await Promise.all(\n Object.entries(files).map(async ([key]) => [\n key,\n await getFileMetadata(files, key as keyof F, locale),\n ])\n );\n const filesResult = Object.fromEntries(filesEntries);\n return filesResult;\n};\n\nexport const getFileMetadataBySlug = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n slugs: string | string[],\n locale: LocalesValues = defaultLocale as LocalesValues,\n strict = false\n) => {\n const slugsArray = Array.isArray(slugs) ? slugs : [slugs];\n const filesMetadata = await getFileMetadataRecord(\n files,\n defaultLocale as LocalesValues\n );\n\n let fileMetadataArray: FileMetadata[] = Object.values(filesMetadata).filter(\n (fileMetadata) =>\n slugsArray.every((slug) => fileMetadata.slugs?.includes(slug))\n );\n\n if (strict) {\n fileMetadataArray = fileMetadataArray.filter(\n (fileMetadata) => fileMetadata.slugs.length === slugsArray.length\n );\n }\n\n if (locale !== defaultLocale) {\n const localizedFileMetadata = await Promise.all(\n fileMetadataArray.map(\n async (fileMetadata) =>\n await getFileMetadata(files, fileMetadata.docKey, locale)\n )\n );\n\n return localizedFileMetadata;\n }\n\n return fileMetadataArray;\n};\n\nexport const getFileBySlug = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n slugs: string | string[],\n locale: LocalesValues = defaultLocale as LocalesValues,\n strict = false\n) => {\n const slugsArray = Array.isArray(slugs) ? slugs : [slugs];\n const filesMetadata = await getFileMetadataRecord(\n files,\n defaultLocale as LocalesValues\n );\n\n let fileMetadataArray = Object.values(filesMetadata).filter((fileMetadata) =>\n slugsArray.every((slug) => fileMetadata.slugs?.includes(slug))\n );\n\n if (strict) {\n fileMetadataArray = fileMetadataArray.filter(\n (fileMetadata) => fileMetadata.slugs.length === slugsArray.length\n );\n }\n\n const fileList = await Promise.all(\n fileMetadataArray.map(async (fileMetadata) => {\n const file = await getFile(files, fileMetadata.docKey, locale);\n return file;\n })\n );\n\n return fileList;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"common.mjs","names":["fileMetadataArray: FileMetadata[]"],"sources":["../../src/common.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { getLocalizedUrl, getMarkdownMetadata } from '@intlayer/core';\nimport { Locales, type LocalesValues } from '@intlayer/types';\n\nexport const defaultLocale = Locales.ENGLISH;\n\nexport const GITHUB_URL_PREFIX =\n 'https://github.com/aymericzip/intlayer/blob/main/docs';\nexport const URL_PREFIX = 'https://intlayer.org/';\n\nexport const getKeys = <T extends Record<string, any>>(obj: T): (keyof T)[] =>\n Object.keys(obj) as (keyof T)[];\n\nexport const getFiles = async <\n F extends Record<`./${string}`, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n lang: LocalesValues = defaultLocale as LocalesValues\n): Promise<Record<string, string>> => {\n const filesEntries = await Promise.all(\n Object.entries(files)\n .map(([key, value]) => [key, value[lang as LocalesValues]])\n .map(async ([key, value]) => [key, await value])\n );\n const filesResult = Object.fromEntries(filesEntries);\n return filesResult;\n};\n\nexport const getFile = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n docKey: keyof F,\n locale: LocalesValues = defaultLocale as LocalesValues\n): Promise<string> => {\n const fileRecord = files[docKey];\n\n if (!fileRecord) {\n throw new Error(`File ${docKey as string} not found`);\n }\n\n const file = await files[docKey]?.[locale];\n\n if (!file) {\n const englishFile = await files[docKey][defaultLocale as LocalesValues];\n\n if (!englishFile) {\n throw new Error(`File ${docKey as string} not found`);\n }\n\n return englishFile;\n }\n\n return file;\n};\n\nexport type FileMetadata = {\n docKey: string;\n url: string;\n relativeUrl: string;\n githubUrl: string;\n title: string;\n slugs: string[];\n description: string;\n keywords: string[];\n updatedAt: string;\n createdAt: string;\n author?: string;\n youtubeVideo?: string;\n applicationTemplate?: string;\n history?: {\n version: string;\n date: string;\n changes: string;\n }[];\n};\n\nexport const formatMetadata = (\n docKey: string,\n file: string,\n locale: LocalesValues = defaultLocale as LocalesValues\n): FileMetadata => {\n const metadata = getMarkdownMetadata(file);\n\n const slugs = (metadata.slugs ?? []).map(String);\n const keywords = (metadata.keywords ?? []).map(String);\n\n const relativeUrl = join('/', ...slugs);\n\n const slicedDocKey = docKey.slice(1);\n\n return {\n ...metadata,\n docKey,\n slugs,\n keywords,\n githubUrl: `${GITHUB_URL_PREFIX}${slicedDocKey}`.replace(\n '/en/',\n `/${locale}/`\n ),\n relativeUrl: getLocalizedUrl(relativeUrl, locale),\n url: getLocalizedUrl(join(URL_PREFIX, relativeUrl), locale),\n } as FileMetadata;\n};\n\nexport const getFileMetadata = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n R extends FileMetadata,\n>(\n files: F,\n docKey: keyof F,\n locale: LocalesValues = defaultLocale as LocalesValues\n): Promise<R> => {\n const file = await getFile(files, docKey, locale);\n\n return formatMetadata(docKey as string, file, locale) as R;\n};\n\nexport const getFileMetadataRecord = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n locale: LocalesValues = defaultLocale as LocalesValues\n): Promise<Record<keyof F, FileMetadata>> => {\n const filesEntries = await Promise.all(\n Object.entries(files).map(async ([key]) => [\n key,\n await getFileMetadata(files, key as keyof F, locale),\n ])\n );\n const filesResult = Object.fromEntries(filesEntries);\n return filesResult;\n};\n\nexport const getFileMetadataBySlug = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n slugs: string | string[],\n locale: LocalesValues = defaultLocale as LocalesValues,\n strict = false\n) => {\n const slugsArray = Array.isArray(slugs) ? slugs : [slugs];\n const filesMetadata = await getFileMetadataRecord(\n files,\n defaultLocale as LocalesValues\n );\n\n let fileMetadataArray: FileMetadata[] = Object.values(filesMetadata).filter(\n (fileMetadata) =>\n slugsArray.every((slug) => fileMetadata.slugs?.includes(slug))\n );\n\n if (strict) {\n fileMetadataArray = fileMetadataArray.filter(\n (fileMetadata) => fileMetadata.slugs.length === slugsArray.length\n );\n }\n\n if (locale !== defaultLocale) {\n const localizedFileMetadata = await Promise.all(\n fileMetadataArray.map(\n async (fileMetadata) =>\n await getFileMetadata(files, fileMetadata.docKey, locale)\n )\n );\n\n return localizedFileMetadata;\n }\n\n return fileMetadataArray;\n};\n\nexport const getFileBySlug = async <\n F extends Record<string, Record<LocalesValues, Promise<string>>>,\n>(\n files: F,\n slugs: string | string[],\n locale: LocalesValues = defaultLocale as LocalesValues,\n strict = false\n) => {\n const slugsArray = Array.isArray(slugs) ? slugs : [slugs];\n const filesMetadata = await getFileMetadataRecord(\n files,\n defaultLocale as LocalesValues\n );\n\n let fileMetadataArray = Object.values(filesMetadata).filter((fileMetadata) =>\n slugsArray.every((slug) => fileMetadata.slugs?.includes(slug))\n );\n\n if (strict) {\n fileMetadataArray = fileMetadataArray.filter(\n (fileMetadata) => fileMetadata.slugs.length === slugsArray.length\n );\n }\n\n const fileList = await Promise.all(\n fileMetadataArray.map(async (fileMetadata) => {\n const file = await getFile(files, fileMetadata.docKey, locale);\n return file;\n })\n );\n\n return fileList;\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","names":[],"sources":["../../src/common.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"common.d.ts","names":[],"sources":["../../src/common.ts"],"sourcesContent":[],"mappings":"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"}
@@ -771,15 +771,17 @@ export const generateMetadata = async ({
771
771
  * ```
772
772
  */
773
773
  const multilingualUrls = getMultilingualUrls("/");
774
+ const localizedUrl =
775
+ multilingualUrls[locale as keyof typeof multilingualUrls];
774
776
 
775
777
  return {
776
778
  ...metadata,
777
779
  alternates: {
778
- canonical: multilingualUrls[locale as keyof typeof multilingualUrls],
780
+ canonical: localizedUrl,
779
781
  languages: { ...multilingualUrls, "x-default": "/" },
780
782
  },
781
783
  openGraph: {
782
- url: multilingualUrls[locale],
784
+ url: localizedUrl,
783
785
  },
784
786
  };
785
787
  };
@@ -811,15 +813,16 @@ export const generateMetadata = async ({ params }) => {
811
813
  * ```
812
814
  */
813
815
  const multilingualUrls = getMultilingualUrls("/");
816
+ const localizedUrl = multilingualUrls[locale];
814
817
 
815
818
  return {
816
819
  ...metadata,
817
820
  alternates: {
818
- canonical: multilingualUrls[locale],
821
+ canonical: localizedUrl,
819
822
  languages: { ...multilingualUrls, "x-default": "/" },
820
823
  },
821
824
  openGraph: {
822
- url: multilingualUrls[locale],
825
+ url: localizedUrl,
823
826
  },
824
827
  };
825
828
  };
@@ -851,15 +854,16 @@ const generateMetadata = async ({ params }) => {
851
854
  * ```
852
855
  */
853
856
  const multilingualUrls = getMultilingualUrls("/");
857
+ const localizedUrl = multilingualUrls[locale];
854
858
 
855
859
  return {
856
860
  ...metadata,
857
861
  alternates: {
858
- canonical: multilingualUrls[locale],
862
+ canonical: localizedUrl,
859
863
  languages: { ...multilingualUrls, "x-default": "/" },
860
864
  },
861
865
  openGraph: {
862
- url: multilingualUrls[locale],
866
+ url: localizedUrl,
863
867
  },
864
868
  };
865
869
  };
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  createdAt: 2025-10-25
3
- updatedAt: 2025-10-25
3
+ updatedAt: 2025-10-26
4
4
  title: كيفية ترجمة تطبيق Next.js 16 الخاص بك – دليل i18n لعام 2025
5
5
  description: اكتشف كيفية جعل موقع Next.js 16 الخاص بك متعدد اللغات. اتبع الوثائق لتدويل (i18n) وترجمته.
6
6
  keywords:
@@ -843,15 +843,17 @@ export const generateMetadata = async ({
843
843
  * ```
844
844
  */
845
845
  const multilingualUrls = getMultilingualUrls("/");
846
+ const localizedUrl =
847
+ multilingualUrls[locale as keyof typeof multilingualUrls];
846
848
 
847
849
  return {
848
850
  ...metadata,
849
851
  alternates: {
850
- canonical: multilingualUrls[locale as keyof typeof multilingualUrls],
852
+ canonical: localizedUrl,
851
853
  languages: { ...multilingualUrls, "x-default": "/" },
852
854
  },
853
855
  openGraph: {
854
- url: multilingualUrls[locale],
856
+ url: localizedUrl,
855
857
  },
856
858
  };
857
859
  };
@@ -883,15 +885,16 @@ export const generateMetadata = async ({ params }) => {
883
885
  * ```
884
886
  */
885
887
  const multilingualUrls = getMultilingualUrls("/");
888
+ const localizedUrl = multilingualUrls[locale];
886
889
 
887
890
  return {
888
891
  ...metadata,
889
892
  alternates: {
890
- canonical: multilingualUrls[locale],
893
+ canonical: localizedUrl,
891
894
  languages: { ...multilingualUrls, "x-default": "/" },
892
895
  },
893
896
  openGraph: {
894
- url: multilingualUrls[locale],
897
+ url: localizedUrl,
895
898
  },
896
899
  };
897
900
  };
@@ -923,15 +926,16 @@ const generateMetadata = async ({ params }) => {
923
926
  * ```
924
927
  */
925
928
  const multilingualUrls = getMultilingualUrls("/");
929
+ const localizedUrl = multilingualUrls[locale];
926
930
 
927
931
  return {
928
932
  ...metadata,
929
933
  alternates: {
930
- canonical: multilingualUrls[locale],
934
+ canonical: localizedUrl,
931
935
  languages: { ...multilingualUrls, "x-default": "/" },
932
936
  },
933
937
  openGraph: {
934
- url: multilingualUrls[locale],
938
+ url: localizedUrl,
935
939
  },
936
940
  };
937
941
  };
@@ -774,15 +774,17 @@ export const generateMetadata = async ({
774
774
  * ```
775
775
  */
776
776
  const multilingualUrls = getMultilingualUrls("/");
777
+ const localizedUrl =
778
+ multilingualUrls[locale as keyof typeof multilingualUrls];
777
779
 
778
780
  return {
779
781
  ...metadata,
780
782
  alternates: {
781
- canonical: multilingualUrls[locale as keyof typeof multilingualUrls],
783
+ canonical: localizedUrl,
782
784
  languages: { ...multilingualUrls, "x-default": "/" },
783
785
  },
784
786
  openGraph: {
785
- url: multilingualUrls[locale],
787
+ url: localizedUrl,
786
788
  },
787
789
  };
788
790
  };
@@ -814,15 +816,16 @@ export const generateMetadata = async ({ params }) => {
814
816
  * ```
815
817
  */
816
818
  const multilingualUrls = getMultilingualUrls("/");
819
+ const localizedUrl = multilingualUrls[locale];
817
820
 
818
821
  return {
819
822
  ...metadata,
820
823
  alternates: {
821
- canonical: multilingualUrls[locale],
824
+ canonical: localizedUrl,
822
825
  languages: { ...multilingualUrls, "x-default": "/" },
823
826
  },
824
827
  openGraph: {
825
- url: multilingualUrls[locale],
828
+ url: localizedUrl,
826
829
  },
827
830
  };
828
831
  };
@@ -854,15 +857,16 @@ const generateMetadata = async ({ params }) => {
854
857
  * ```
855
858
  */
856
859
  const multilingualUrls = getMultilingualUrls("/");
860
+ const localizedUrl = multilingualUrls[locale];
857
861
 
858
862
  return {
859
863
  ...metadata,
860
864
  alternates: {
861
- canonical: multilingualUrls[locale],
865
+ canonical: localizedUrl,
862
866
  languages: { ...multilingualUrls, "x-default": "/" },
863
867
  },
864
868
  openGraph: {
865
- url: multilingualUrls[locale],
869
+ url: localizedUrl,
866
870
  },
867
871
  };
868
872
  };
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  createdAt: 2025-10-25
3
- updatedAt: 2025-10-25
3
+ updatedAt: 2025-10-26
4
4
  title: Wie Sie Ihre Next.js 16 App übersetzen – i18n Leitfaden 2025
5
5
  description: Entdecken Sie, wie Sie Ihre Next.js 16 Website mehrsprachig machen. Folgen Sie der Dokumentation, um sie zu internationalisieren (i18n) und zu übersetzen.
6
6
  keywords:
@@ -872,15 +872,17 @@ export const generateMetadata = async ({
872
872
  * ```
873
873
  */
874
874
  const multilingualUrls = getMultilingualUrls("/");
875
+ const localizedUrl =
876
+ multilingualUrls[locale as keyof typeof multilingualUrls];
875
877
 
876
878
  return {
877
879
  ...metadata,
878
880
  alternates: {
879
- canonical: multilingualUrls[locale as keyof typeof multilingualUrls],
881
+ canonical: localizedUrl,
880
882
  languages: { ...multilingualUrls, "x-default": "/" },
881
883
  },
882
884
  openGraph: {
883
- url: multilingualUrls[locale],
885
+ url: localizedUrl,
884
886
  },
885
887
  };
886
888
  };
@@ -912,15 +914,16 @@ export const generateMetadata = async ({ params }) => {
912
914
  * ```
913
915
  */
914
916
  const multilingualUrls = getMultilingualUrls("/");
917
+ const localizedUrl = multilingualUrls[locale];
915
918
 
916
919
  return {
917
920
  ...metadata,
918
921
  alternates: {
919
- canonical: multilingualUrls[locale],
922
+ canonical: localizedUrl,
920
923
  languages: { ...multilingualUrls, "x-default": "/" },
921
924
  },
922
925
  openGraph: {
923
- url: multilingualUrls[locale],
926
+ url: localizedUrl,
924
927
  },
925
928
  };
926
929
  };
@@ -952,15 +955,16 @@ const generateMetadata = async ({ params }) => {
952
955
  * ```
953
956
  */
954
957
  const multilingualUrls = getMultilingualUrls("/");
958
+ const localizedUrl = multilingualUrls[locale];
955
959
 
956
960
  return {
957
961
  ...metadata,
958
962
  alternates: {
959
- canonical: multilingualUrls[locale],
963
+ canonical: localizedUrl,
960
964
  languages: { ...multilingualUrls, "x-default": "/" },
961
965
  },
962
966
  openGraph: {
963
- url: multilingualUrls[locale],
967
+ url: localizedUrl,
964
968
  },
965
969
  };
966
970
  };
package/docs/en/CI_CD.md CHANGED
@@ -25,6 +25,10 @@ history:
25
25
 
26
26
  Intlayer allows the automatic generation of translations for your content declaration files. There are multiple ways to achieve this depending on your workflow.
27
27
 
28
+ ## Table of Contents
29
+
30
+ <TOC>
31
+
28
32
  ## Using the CMS
29
33
 
30
34
  With Intlayer, you can adopt a workflow where only a single locale is declared locally, while all translations are managed remotely through the CMS. This allows content and translations to be completely detached from the codebase, offering more flexibility for content editors and enabling Live Sync (no need to rebuild the application to apply changes).
@@ -57,6 +57,12 @@ Intlayer configuration files allow customization of various aspects of the plugi
57
57
 
58
58
  ---
59
59
 
60
+ ## Table of Contents
61
+
62
+ <TOC>
63
+
64
+ ---
65
+
60
66
  ## Configuration File Support
61
67
 
62
68
  Intlayer accepts JSON, JS, MJS, and TS configuration file formats:
@@ -316,51 +322,32 @@ Settings that control routing behavior, including URL structure, locale storage,
316
322
  - _Note_: This setting does not impact cookie or locale storage management.
317
323
 
318
324
  - **storage**:
319
- - _Type_: `false | 'cookie' | 'localStorage' | 'sessionStorage' | CookiesAttributes | LocaleStorageAttributes | Array`
325
+ - _Type_: `false | 'cookie' | 'localStorage' | 'sessionStorage' | 'header' | CookiesAttributes | StorageAttributes | Array`
320
326
  - _Default_: `'localStorage'`
321
327
  - _Description_: Configuration for storing the locale in the client.
322
- - _Examples_:
323
-
324
- ```typescript
325
- // Disable storage
326
- storage: false
327
-
328
- // Simple storage types
329
- storage: 'cookie'
330
- storage: 'localStorage'
331
- storage: 'sessionStorage'
332
328
 
333
- // Cookie with custom attributes
334
- storage: {
335
- type: 'cookie',
336
- name: 'custom-locale',
337
- domain: '.example.com',
338
- secure: true,
339
- sameSite: 'strict'
340
- }
341
-
342
- // localStorage with custom key
343
- storage: {
344
- type: 'localStorage',
345
- name: 'custom-locale'
346
- }
347
-
348
- // Multiple storage types
349
- storage: ['cookie', 'localStorage']
350
- ```
351
-
352
- - _Note_:
353
- - If `false`, the locale will not be stored by the middleware
354
- - Check GDPR compliance for cookies. See https://gdpr.eu/cookies/
355
- - Recommendation: Configure both localStorage and cookies for GDPR compliance
356
- - Disable cookie storage by default on the useLocale hook until user consent
357
-
358
- - **headerName**:
359
- - _Type_: `string`
360
- - _Default_: `'x-intlayer-locale'`
361
- - _Description_: The name of the HTTP header used to determine the locale.
362
- - _Example_: `'x-custom-locale'`
363
- - _Note_: This is useful for API-based locale determination.
329
+ - **cookie**:
330
+ - _Description_: Stores data in cookies, small pieces of data stored on the client's browser, accessible on both client and server side.
331
+ - _Note_: For GDPR compliant storage, ensure proper user consent before usage.
332
+ - _Note_: Cookies parameters are customizable if set as CookiesAttributes (`{ type: 'cookie', name: 'custom-locale', secure: true, httpOnly: false }`).
333
+
334
+ - **localStorage**:
335
+ - _Description_: Stores data in the browser without expiration dates, allowing for data persistence across sessions, accessible only on the client side.
336
+ - _Note_: Ideal for storing long-term data but mindful of the privacy and security implications due to non-expiring nature unless explicitly cleared.
337
+ - _Note_: Locale storage is only accessible on the client side, the intlayer proxy will not be able to access it.
338
+ - _Note_: Locale storage parameters are customizable if set as StorageAttributes (`{ type: 'localStorage', name: 'custom-locale' }`).
339
+
340
+ - **sessionStorage**:
341
+ - _Description_: Stores data for the duration of a page session, meaning it gets cleared once the tab or window is closed, accessible only on the client side.
342
+ - _Note_: Suitable for temporary data storage for each session.
343
+ - _Note_: Locale storage is only accessible on the client side, the intlayer proxy will not be able to access it.
344
+ - _Note_: Locale storage parameters are customizable if set as StorageAttributes (`{ type: 'sessionStorage', name: 'custom-locale' }`).
345
+
346
+ - **header**:
347
+ - _Description_: Utilizes HTTP headers to store or transmit locale data, suitable for server-side language determination.
348
+ - _Note_: Useful in API calls for maintaining consistent language settings across requests.
349
+ - _Note_: Header is only accessible on the server side, the client side will not be able to access it.
350
+ - _Note_: Header name is customizable if set as StorageAttributes (`{ type: 'header', name: 'custom-locale' }`).
364
351
 
365
352
  - **basePath**:
366
353
  - _Type_: `string`
@@ -44,6 +44,10 @@ history:
44
44
 
45
45
  # Intlayer Formatters
46
46
 
47
+ ## Table of Contents
48
+
49
+ <TOC>
50
+
47
51
  ## Overview
48
52
 
49
53
  Intlayer provides a set of lightweight helpers built on top of the native `Intl` APIs, plus a cached `Intl` wrapper to avoid repeatedly constructing heavy formatters. These utilities are fully locale-aware and can be used from the main `intlayer` package.
@@ -21,6 +21,10 @@ history:
21
21
 
22
22
  # How Intlayer Works
23
23
 
24
+ ## Table of Contents
25
+
26
+ <TOC>
27
+
24
28
  ## Overview
25
29
 
26
30
  The main idea behind Intlayer is to adopt a per-component content management. So the idea behind Intlayer is to allow you to declare your content anywhere in your codebase, as in the same directory as your component.
package/docs/en/index.md CHANGED
@@ -91,6 +91,7 @@ Organize your multilingual content close to your code to keep everything consist
91
91
 
92
92
  We’ve built Intlayer with flexibility in mind, offering seamless integration across popular frameworks and build tools:
93
93
 
94
+ - **[Intlayer with Next.js 16](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_with_nextjs_16.md)**
94
95
  - **[Intlayer with Next.js 15](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_with_nextjs_15.md)**
95
96
  - **[Intlayer with Next.js 14 (App Router)](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_with_nextjs_14.md)**
96
97
  - **[Intlayer with Next.js Page Router](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_with_nextjs_page_router.md)**
@@ -39,6 +39,12 @@ For that, Intlayer introduce the concept of 'distant dictionaries'.
39
39
 
40
40
  ![Intlayer CMS Interface](https://github.com/aymericzip/intlayer/blob/main/docs/assets/CMS.png)
41
41
 
42
+ ## Table of Contents
43
+
44
+ <TOC>
45
+
46
+ ---
47
+
42
48
  ## Understanding distant dictionaries
43
49
 
44
50
  Intlayer make a difference between 'local' and 'remote' dictionaries.
@@ -48,6 +48,14 @@ history:
48
48
 
49
49
  # Intlayer CLI
50
50
 
51
+ ---
52
+
53
+ ## Table of Contents
54
+
55
+ <TOC>
56
+
57
+ ---
58
+
51
59
  ## Install Package
52
60
 
53
61
  Install the necessary packages using npm:
@@ -38,6 +38,10 @@ history:
38
38
 
39
39
  See [Application Template](https://github.com/aymericzip/intlayer-next-14-template) on GitHub.
40
40
 
41
+ ## Table of Contents
42
+
43
+ <TOC>
44
+
41
45
  ## What is Intlayer?
42
46
 
43
47
  **Intlayer** is an innovative, open-source internationalization (i18n) library designed to simplify multilingual support in modern web applications. Intlayer seamlessly integrates with the latest **Next.js 14** framework, including its powerful **App Router**. It is optimized to work with **Server Components** for efficient rendering and is fully compatible with [**Turbopack**](https://nextjs.org/docs/architecture/turbopack) (from Next.js >= 15).
@@ -767,15 +771,17 @@ export const generateMetadata = ({
767
771
  * ```
768
772
  */
769
773
  const multilingualUrls = getMultilingualUrls("/");
774
+ const localizedUrl =
775
+ multilingualUrls[locale as keyof typeof multilingualUrls];
770
776
 
771
777
  return {
772
778
  ...metadata,
773
779
  alternates: {
774
- canonical: multilingualUrls[locale as keyof typeof multilingualUrls],
780
+ canonical: localizedUrl,
775
781
  languages: { ...multilingualUrls, "x-default": "/" },
776
782
  },
777
783
  openGraph: {
778
- url: multilingualUrls[locale],
784
+ url: localizedUrl,
779
785
  },
780
786
  };
781
787
  };
@@ -805,15 +811,16 @@ export const generateMetadata = ({ params: { locale } }) => {
805
811
  * ```
806
812
  */
807
813
  const multilingualUrls = getMultilingualUrls("/");
814
+ const localizedUrl = multilingualUrls[locale];
808
815
 
809
816
  return {
810
817
  ...metadata,
811
818
  alternates: {
812
- canonical: multilingualUrls[locale],
819
+ canonical: localizedUrl,
813
820
  languages: { ...multilingualUrls, "x-default": "/" },
814
821
  },
815
822
  openGraph: {
816
- url: multilingualUrls[locale],
823
+ url: localizedUrl,
817
824
  },
818
825
  };
819
826
  };
@@ -843,15 +850,16 @@ const generateMetadata = ({ params: { locale } }) => {
843
850
  * ```
844
851
  */
845
852
  const multilingualUrls = getMultilingualUrls("/");
853
+ const localizedUrl = multilingualUrls[locale];
846
854
 
847
855
  return {
848
856
  ...metadata,
849
857
  alternates: {
850
- canonical: multilingualUrls[locale],
858
+ canonical: localizedUrl,
851
859
  languages: { ...multilingualUrls, "x-default": "/" },
852
860
  },
853
861
  openGraph: {
854
- url: multilingualUrls[locale],
862
+ url: localizedUrl,
855
863
  },
856
864
  };
857
865
  };