@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.
- package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +4 -11
- package/dist/cjs/common.cjs +5 -1
- package/dist/cjs/common.cjs.map +1 -1
- package/dist/esm/common.mjs +5 -1
- package/dist/esm/common.mjs.map +1 -1
- package/dist/types/common.d.ts.map +1 -1
- package/docs/ar/intlayer_with_nextjs_15.md +10 -6
- package/docs/ar/intlayer_with_nextjs_16.md +11 -7
- package/docs/de/intlayer_with_nextjs_15.md +10 -6
- package/docs/de/intlayer_with_nextjs_16.md +11 -7
- package/docs/en/CI_CD.md +4 -0
- package/docs/en/configuration.md +29 -42
- package/docs/en/formatters.md +4 -0
- package/docs/en/how_works_intlayer.md +4 -0
- package/docs/en/index.md +1 -0
- package/docs/en/intlayer_CMS.md +6 -0
- package/docs/en/intlayer_cli.md +8 -0
- package/docs/en/intlayer_with_nextjs_14.md +14 -6
- package/docs/en/intlayer_with_nextjs_15.md +14 -6
- package/docs/en/intlayer_with_nextjs_16.md +15 -7
- package/docs/en/intlayer_with_nextjs_page_router.md +4 -0
- package/docs/en/intlayer_with_nuxt.md +4 -0
- package/docs/en/intlayer_with_react_native+expo.md +7 -0
- package/docs/en/intlayer_with_react_router_v7.md +4 -0
- package/docs/en/intlayer_with_tanstack.md +4 -0
- package/docs/en/intlayer_with_vite+preact.md +4 -0
- package/docs/en/intlayer_with_vite+react.md +4 -0
- package/docs/en/intlayer_with_vite+solid.md +4 -0
- package/docs/en/intlayer_with_vite+svelte.md +4 -0
- package/docs/en/intlayer_with_vite+vue.md +4 -0
- package/docs/en/introduction.md +1 -0
- package/docs/en/roadmap.md +6 -0
- package/docs/en-GB/intlayer_with_nextjs_14.md +10 -6
- package/docs/en-GB/intlayer_with_nextjs_15.md +10 -6
- package/docs/en-GB/intlayer_with_nextjs_16.md +11 -7
- package/docs/es/intlayer_with_nextjs_14.md +11 -6
- package/docs/es/intlayer_with_nextjs_15.md +7 -4
- package/docs/es/intlayer_with_nextjs_16.md +11 -7
- package/docs/fr/intlayer_with_nextjs_15.md +10 -6
- package/docs/fr/intlayer_with_nextjs_16.md +12 -25
- package/docs/hi/intlayer_with_nextjs_15.md +10 -6
- package/docs/hi/intlayer_with_nextjs_16.md +11 -7
- package/docs/id/intlayer_with_nextjs_16.md +11 -7
- package/docs/it/intlayer_with_nextjs_15.md +10 -6
- package/docs/it/intlayer_with_nextjs_16.md +11 -7
- package/docs/ja/intlayer_with_nextjs_14.md +11 -6
- package/docs/ja/intlayer_with_nextjs_15.md +10 -6
- package/docs/ja/intlayer_with_nextjs_16.md +11 -7
- package/docs/ko/intlayer_with_nextjs_14.md +11 -6
- package/docs/ko/intlayer_with_nextjs_15.md +10 -6
- package/docs/ko/intlayer_with_nextjs_16.md +11 -7
- package/docs/pl/intlayer_with_nextjs_16.md +11 -7
- package/docs/pt/intlayer_with_nextjs_14.md +10 -7
- package/docs/pt/intlayer_with_nextjs_15.md +10 -6
- package/docs/pt/intlayer_with_nextjs_16.md +11 -7
- package/docs/ru/intlayer_with_nextjs_15.md +7 -4
- package/docs/ru/intlayer_with_nextjs_16.md +11 -7
- package/docs/tr/intlayer_with_nextjs_15.md +10 -6
- package/docs/tr/intlayer_with_nextjs_16.md +11 -7
- package/docs/vi/intlayer_with_nextjs_16.md +11 -7
- package/docs/zh/intlayer_with_nextjs_14.md +11 -6
- package/docs/zh/intlayer_with_nextjs_15.md +7 -4
- package/docs/zh/intlayer_with_nextjs_16.md +11 -7
- package/package.json +14 -14
- 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
|
-
|
|
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
|
|
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
|
|
package/dist/cjs/common.cjs
CHANGED
|
@@ -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
|
|
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)
|
package/dist/cjs/common.cjs.map
CHANGED
|
@@ -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
|
|
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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"}
|
package/dist/esm/common.mjs
CHANGED
|
@@ -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
|
|
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)
|
package/dist/esm/common.mjs.map
CHANGED
|
@@ -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
|
|
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":";;;;;AAIA,MAAa,gBAAgB,QAAQ;AAErC,MAAa,oBACX;AACF,MAAa,aAAa;AAE1B,MAAa,WAA0C,QACrD,OAAO,KAAK,IAAI;AAElB,MAAa,WAAW,OAGtB,OACA,OAAsB,kBACc;CACpC,MAAM,eAAe,MAAM,QAAQ,IACjC,OAAO,QAAQ,MAAM,CAClB,KAAK,CAAC,KAAK,WAAW,CAAC,KAAK,MAAM,MAAuB,CAAC,CAC1D,IAAI,OAAO,CAAC,KAAK,WAAW,CAAC,KAAK,MAAM,MAAM,CAAC,CACnD;AAED,QADoB,OAAO,YAAY,aAAa;;AAItD,MAAa,UAAU,OAGrB,OACA,QACA,SAAwB,kBACJ;AAGpB,KAAI,CAFe,MAAM,QAGvB,OAAM,IAAI,MAAM,QAAQ,OAAiB,YAAY;CAGvD,MAAM,OAAO,MAAM,MAAM,UAAU;AAEnC,KAAI,CAAC,MAAM;EACT,MAAM,cAAc,MAAM,MAAM,QAAQ;AAExC,MAAI,CAAC,YACH,OAAM,IAAI,MAAM,QAAQ,OAAiB,YAAY;AAGvD,SAAO;;AAGT,QAAO;;AAwBT,MAAa,kBACX,QACA,MACA,SAAwB,kBACP;CACjB,MAAM,WAAW,oBAAoB,KAAK;CAE1C,MAAM,SAAS,SAAS,SAAS,EAAE,EAAE,IAAI,OAAO;CAChD,MAAM,YAAY,SAAS,YAAY,EAAE,EAAE,IAAI,OAAO;CAEtD,MAAM,cAAc,KAAK,KAAK,GAAG,MAAM;CAEvC,MAAM,eAAe,OAAO,MAAM,EAAE;AAEpC,QAAO;EACL,GAAG;EACH;EACA;EACA;EACA,WAAW,GAAG,oBAAoB,eAAe,QAC/C,QACA,IAAI,OAAO,GACZ;EACD,aAAa,gBAAgB,aAAa,OAAO;EACjD,KAAK,gBAAgB,KAAK,YAAY,YAAY,EAAE,OAAO;EAC5D;;AAGH,MAAa,kBAAkB,OAI7B,OACA,QACA,SAAwB,kBACT;AAGf,QAAO,eAAe,QAFT,MAAM,QAAQ,OAAO,QAAQ,OAAO,EAEH,OAAO;;AAGvD,MAAa,wBAAwB,OAGnC,OACA,SAAwB,kBACmB;CAC3C,MAAM,eAAe,MAAM,QAAQ,IACjC,OAAO,QAAQ,MAAM,CAAC,IAAI,OAAO,CAAC,SAAS,CACzC,KACA,MAAM,gBAAgB,OAAO,KAAgB,OAAO,CACrD,CAAC,CACH;AAED,QADoB,OAAO,YAAY,aAAa;;AAItD,MAAa,wBAAwB,OAGnC,OACA,OACA,SAAwB,eACxB,SAAS,UACN;CACH,MAAM,aAAa,MAAM,QAAQ,MAAM,GAAG,QAAQ,CAAC,MAAM;CACzD,MAAM,gBAAgB,MAAM,sBAC1B,OACA,cACD;CAED,IAAIA,oBAAoC,OAAO,OAAO,cAAc,CAAC,QAClE,iBACC,WAAW,OAAO,SAAS,aAAa,OAAO,SAAS,KAAK,CAAC,CACjE;AAED,KAAI,OACF,qBAAoB,kBAAkB,QACnC,iBAAiB,aAAa,MAAM,WAAW,WAAW,OAC5D;AAGH,KAAI,WAAW,cAQb,QAP8B,MAAM,QAAQ,IAC1C,kBAAkB,IAChB,OAAO,iBACL,MAAM,gBAAgB,OAAO,aAAa,QAAQ,OAAO,CAC5D,CACF;AAKH,QAAO;;AAGT,MAAa,gBAAgB,OAG3B,OACA,OACA,SAAwB,eACxB,SAAS,UACN;CACH,MAAM,aAAa,MAAM,QAAQ,MAAM,GAAG,QAAQ,CAAC,MAAM;CACzD,MAAM,gBAAgB,MAAM,sBAC1B,OACA,cACD;CAED,IAAI,oBAAoB,OAAO,OAAO,cAAc,CAAC,QAAQ,iBAC3D,WAAW,OAAO,SAAS,aAAa,OAAO,SAAS,KAAK,CAAC,CAC/D;AAED,KAAI,OACF,qBAAoB,kBAAkB,QACnC,iBAAiB,aAAa,MAAM,WAAW,WAAW,OAC5D;AAUH,QAPiB,MAAM,QAAQ,IAC7B,kBAAkB,IAAI,OAAO,iBAAiB;AAE5C,SADa,MAAM,QAAQ,OAAO,aAAa,QAAQ,OAAO;GAE9D,CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","names":[],"sources":["../../src/common.ts"],"sourcesContent":[],"mappings":";;;cAIa;cAEA,iBAAA;AAFA,cAIA,UAAA,GAJ+B,uBAAA;AAE/B,cAIA,OAJiB,EAAA,CAAA,UAII,MAJJ,CAAA,MAAA,EAAA,GAAA,CAAA,CAAA,CAAA,GAAA,EAI8B,CAJ9B,EAAA,GAAA,CAAA,MAIyC,CAJzC,CAAA,EAAA;AAEjB,cAKA,QALU,EAAA,CAAA,UAMX,MANW,CAAA,KAAA,MAAA,EAAA,EAMW,MANX,CAMkB,aANlB,EAMiC,OANjC,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAQd,CARc,EAAA,IAAA,CAAA,EASf,aATe,EAAA,GAUpB,OAVoB,CAUZ,MAVY,CAAA,MAAA,EAAA,MAAA,CAAA,CAAA;AAEV,cAkBA,OAjBoB,EAAA,CAAA,UAkBrB,MAlBqB,CAAA,MAAA,EAkBN,MAlBM,CAkBC,aAlBD,EAkBgB,OAlBhB,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAoBxB,CApBwB,EAAA,MAAA,EAAA,MAqBjB,CArBiB,EAAA,MAAA,CAAA,EAsBvB,aAtBuB,EAAA,GAuB9B,OAvB8B,CAAA,MAAA,CAAA;AADC,KA8CtB,YAAA,GA9CsB;EAA0B,MAAA,EAAA,MAAA;EAAW,GAAA,EAAA,MAAA;EAAC,WAAA,EAAA,MAAA;EAG3D,SAAA,EAaZ,MAAA;EAZwC,KAAA,EAAA,MAAA;EAAe,KAAA,EAAA,MAAA,EAAA;EAAtB,WAAA,EAAA,MAAA;EAAtB,QAAA,EAAA,MAAA,EAAA;EAEH,SAAA,EAAA,MAAA;EACD,SAAA,EAAA,MAAA;EACG,MAAA,CAAA,EAAA,MAAA;EAAR,YAAA,CAAA,EAAA,MAAA;EAAO,mBAAA,CAAA,EAAA,MAAA;EAUG,OAAA,CAAA,EA0BZ;IAzBiC,OAAA,EAAA,MAAA;IAAe,IAAA,EAAA,MAAA;IAAtB,OAAA,EAAA,MAAA;EAAf,CAAA,EAAA;CAEH;AACO,cA6CH,cA7CG,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAgDN,aAhDM,EAAA,GAiDb,YAjDa;AACN,
|
|
1
|
+
{"version":3,"file":"common.d.ts","names":[],"sources":["../../src/common.ts"],"sourcesContent":[],"mappings":";;;cAIa;cAEA,iBAAA;AAFA,cAIA,UAAA,GAJ+B,uBAAA;AAE/B,cAIA,OAJiB,EAAA,CAAA,UAII,MAJJ,CAAA,MAAA,EAAA,GAAA,CAAA,CAAA,CAAA,GAAA,EAI8B,CAJ9B,EAAA,GAAA,CAAA,MAIyC,CAJzC,CAAA,EAAA;AAEjB,cAKA,QALU,EAAA,CAAA,UAMX,MANW,CAAA,KAAA,MAAA,EAAA,EAMW,MANX,CAMkB,aANlB,EAMiC,OANjC,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAQd,CARc,EAAA,IAAA,CAAA,EASf,aATe,EAAA,GAUpB,OAVoB,CAUZ,MAVY,CAAA,MAAA,EAAA,MAAA,CAAA,CAAA;AAEV,cAkBA,OAjBoB,EAAA,CAAA,UAkBrB,MAlBqB,CAAA,MAAA,EAkBN,MAlBM,CAkBC,aAlBD,EAkBgB,OAlBhB,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAoBxB,CApBwB,EAAA,MAAA,EAAA,MAqBjB,CArBiB,EAAA,MAAA,CAAA,EAsBvB,aAtBuB,EAAA,GAuB9B,OAvB8B,CAAA,MAAA,CAAA;AADC,KA8CtB,YAAA,GA9CsB;EAA0B,MAAA,EAAA,MAAA;EAAW,GAAA,EAAA,MAAA;EAAC,WAAA,EAAA,MAAA;EAG3D,SAAA,EAaZ,MAAA;EAZwC,KAAA,EAAA,MAAA;EAAe,KAAA,EAAA,MAAA,EAAA;EAAtB,WAAA,EAAA,MAAA;EAAtB,QAAA,EAAA,MAAA,EAAA;EAEH,SAAA,EAAA,MAAA;EACD,SAAA,EAAA,MAAA;EACG,MAAA,CAAA,EAAA,MAAA;EAAR,YAAA,CAAA,EAAA,MAAA;EAAO,mBAAA,CAAA,EAAA,MAAA;EAUG,OAAA,CAAA,EA0BZ;IAzBiC,OAAA,EAAA,MAAA;IAAe,IAAA,EAAA,MAAA;IAAtB,OAAA,EAAA,MAAA;EAAf,CAAA,EAAA;CAEH;AACO,cA6CH,cA7CG,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAgDN,aAhDM,EAAA,GAiDb,YAjDa;AACN,cAwEG,eAxEH,EAAA,CAAA,UAyEE,MAzEF,CAAA,MAAA,EAyEiB,MAzEjB,CAyEwB,aAzExB,EAyEuC,OAzEvC,CAAA,MAAA,CAAA,CAAA,CAAA,EAAA,UA0EE,YA1EF,CAAA,CAAA,KAAA,EA4ED,CA5EC,EAAA,MAAA,EAAA,MA6EM,CA7EN,EAAA,MAAA,CAAA,EA8EA,aA9EA,EAAA,GA+EP,OA/EO,CA+EC,CA/ED,CAAA;AACP,cAoFU,qBApFV,EAAA,CAAA,UAqFS,MArFT,CAAA,MAAA,EAqFwB,MArFxB,CAqF+B,aArF/B,EAqF8C,OArF9C,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAuFM,CAvFN,EAAA,MAAA,CAAA,EAwFO,aAxFP,EAAA,GAyFA,OAzFA,CAyFQ,MAzFR,CAAA,MAyFqB,CAzFrB,EAyFwB,YAzFxB,CAAA,CAAA;AAAO,cAoGG,qBApGH,EAAA,CAAA,UAqGE,MArGF,CAAA,MAAA,EAqGiB,MArGjB,CAqGwB,aArGxB,EAqGuC,OArGvC,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAuGD,CAvGC,EAAA,KAAA,EAAA,MAAA,GAAA,MAAA,EAAA,EAAA,MAAA,CAAA,EAyGA,aAzGA,EAAA,MAAA,CAAA,EAAA,OAAA,EAAA,GA0GM,OA1GN,CA0GM,YA1GN,EAAA,CAAA;AAsBE,cAqHC,aArHW,EAAA,CAAA,UAsHZ,MAtHY,CAAA,MAAA,EAsHG,MAtHH,CAsHU,aAtHV,EAsHyB,OAtHzB,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAwHf,CAxHe,EAAA,KAAA,EAAA,MAAA,GAAA,MAAA,EAAA,EAAA,MAAA,CAAA,EA0Hd,aA1Hc,EAAA,MAAA,CAAA,EAAA,OAAA,EAAA,GA2HR,OA3HQ,CAAA,MAAA,EAAA,CAAA"}
|
|
@@ -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:
|
|
780
|
+
canonical: localizedUrl,
|
|
779
781
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
780
782
|
},
|
|
781
783
|
openGraph: {
|
|
782
|
-
url:
|
|
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:
|
|
821
|
+
canonical: localizedUrl,
|
|
819
822
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
820
823
|
},
|
|
821
824
|
openGraph: {
|
|
822
|
-
url:
|
|
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:
|
|
862
|
+
canonical: localizedUrl,
|
|
859
863
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
860
864
|
},
|
|
861
865
|
openGraph: {
|
|
862
|
-
url:
|
|
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-
|
|
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:
|
|
852
|
+
canonical: localizedUrl,
|
|
851
853
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
852
854
|
},
|
|
853
855
|
openGraph: {
|
|
854
|
-
url:
|
|
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:
|
|
893
|
+
canonical: localizedUrl,
|
|
891
894
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
892
895
|
},
|
|
893
896
|
openGraph: {
|
|
894
|
-
url:
|
|
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:
|
|
934
|
+
canonical: localizedUrl,
|
|
931
935
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
932
936
|
},
|
|
933
937
|
openGraph: {
|
|
934
|
-
url:
|
|
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:
|
|
783
|
+
canonical: localizedUrl,
|
|
782
784
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
783
785
|
},
|
|
784
786
|
openGraph: {
|
|
785
|
-
url:
|
|
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:
|
|
824
|
+
canonical: localizedUrl,
|
|
822
825
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
823
826
|
},
|
|
824
827
|
openGraph: {
|
|
825
|
-
url:
|
|
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:
|
|
865
|
+
canonical: localizedUrl,
|
|
862
866
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
863
867
|
},
|
|
864
868
|
openGraph: {
|
|
865
|
-
url:
|
|
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-
|
|
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:
|
|
881
|
+
canonical: localizedUrl,
|
|
880
882
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
881
883
|
},
|
|
882
884
|
openGraph: {
|
|
883
|
-
url:
|
|
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:
|
|
922
|
+
canonical: localizedUrl,
|
|
920
923
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
921
924
|
},
|
|
922
925
|
openGraph: {
|
|
923
|
-
url:
|
|
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:
|
|
963
|
+
canonical: localizedUrl,
|
|
960
964
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
961
965
|
},
|
|
962
966
|
openGraph: {
|
|
963
|
-
url:
|
|
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).
|
package/docs/en/configuration.md
CHANGED
|
@@ -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 |
|
|
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
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
-
|
|
354
|
-
-
|
|
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`
|
package/docs/en/formatters.md
CHANGED
|
@@ -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)**
|
package/docs/en/intlayer_CMS.md
CHANGED
|
@@ -39,6 +39,12 @@ For that, Intlayer introduce the concept of 'distant dictionaries'.
|
|
|
39
39
|
|
|
40
40
|

|
|
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.
|
package/docs/en/intlayer_cli.md
CHANGED
|
@@ -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:
|
|
780
|
+
canonical: localizedUrl,
|
|
775
781
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
776
782
|
},
|
|
777
783
|
openGraph: {
|
|
778
|
-
url:
|
|
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:
|
|
819
|
+
canonical: localizedUrl,
|
|
813
820
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
814
821
|
},
|
|
815
822
|
openGraph: {
|
|
816
|
-
url:
|
|
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:
|
|
858
|
+
canonical: localizedUrl,
|
|
851
859
|
languages: { ...multilingualUrls, "x-default": "/" },
|
|
852
860
|
},
|
|
853
861
|
openGraph: {
|
|
854
|
-
url:
|
|
862
|
+
url: localizedUrl,
|
|
855
863
|
},
|
|
856
864
|
};
|
|
857
865
|
};
|