@intlayer/docs 9.1.3 → 9.2.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/ar/rag_powered_documentation_assistant.md +7 -0
- package/blog/de/rag_powered_documentation_assistant.md +6 -0
- package/blog/en-GB/rag_powered_documentation_assistant.md +6 -0
- package/blog/es/rag_powered_documentation_assistant.md +7 -0
- package/blog/fr/i18n_meaning.md +7 -1
- package/blog/fr/list_i18n_technologies/frameworks/angular.md +5 -1
- package/blog/fr/rag_powered_documentation_assistant.md +6 -0
- package/blog/hi/next-i18next_vs_next-intl_vs_intlayer.md +119 -42
- package/blog/hi/rag_powered_documentation_assistant.md +7 -0
- package/blog/id/rag_powered_documentation_assistant.md +6 -0
- package/blog/it/rag_powered_documentation_assistant.md +6 -0
- package/blog/ja/rag_powered_documentation_assistant.md +7 -0
- package/blog/ko/list_i18n_technologies/frameworks/react.md +7 -7
- package/blog/ko/rag_powered_documentation_assistant.md +6 -0
- package/blog/pl/rag_powered_documentation_assistant.md +6 -0
- package/blog/pt/rag_powered_documentation_assistant.md +6 -0
- package/blog/ru/rag_powered_documentation_assistant.md +7 -0
- package/blog/tr/intlayer_with_react-intl.md +3 -1
- package/blog/tr/next-i18next_vs_next-intl_vs_intlayer.md +175 -42
- package/blog/tr/rag_powered_documentation_assistant.md +6 -0
- package/blog/uk/rag_powered_documentation_assistant.md +6 -0
- package/blog/vi/rag_powered_documentation_assistant.md +6 -0
- package/blog/zh/intlayer_with_i18next.md +87 -28
- package/blog/zh/intlayer_with_next-i18next.md +86 -29
- package/blog/zh/intlayer_with_next-intl.md +88 -28
- package/blog/zh/intlayer_with_react-i18next.md +87 -28
- package/blog/zh/intlayer_with_react-intl.md +88 -27
- package/blog/zh/intlayer_with_vue-i18n.md +117 -8
- package/blog/zh/rag_powered_documentation_assistant.md +6 -0
- package/dist/cjs/generated/blog.entry.cjs +27 -27
- package/dist/cjs/generated/blog.entry.cjs.map +1 -1
- package/dist/cjs/generated/docs.entry.cjs +234 -214
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/cjs/generated/frequentQuestions.entry.cjs +17 -17
- package/dist/cjs/generated/frequentQuestions.entry.cjs.map +1 -1
- package/dist/cjs/generated/legal.entry.cjs +2 -2
- package/dist/cjs/generated/legal.entry.cjs.map +1 -1
- package/dist/esm/generated/blog.entry.mjs +27 -27
- package/dist/esm/generated/blog.entry.mjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +234 -214
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/esm/generated/frequentQuestions.entry.mjs +17 -17
- package/dist/esm/generated/frequentQuestions.entry.mjs.map +1 -1
- package/dist/esm/generated/legal.entry.mjs +2 -2
- package/dist/esm/generated/legal.entry.mjs.map +1 -1
- package/dist/types/generated/docs.entry.d.ts +1 -0
- package/dist/types/generated/docs.entry.d.ts.map +1 -1
- package/docs/ar/analytics.md +222 -0
- package/docs/ar/autoFill.md +28 -9
- package/docs/ar/configuration.md +25 -8
- package/docs/ar/dictionary/file.md +3 -1
- package/docs/ar/dictionary/nesting.md +47 -30
- package/docs/ar/formatters.md +148 -193
- package/docs/ar/intlayer_CMS.md +152 -0
- package/docs/ar/intlayer_with_angular_21.md +9 -9
- package/docs/ar/intlayer_with_nextjs_14.md +1 -28
- package/docs/ar/intlayer_with_nextjs_15.md +1 -33
- package/docs/ar/intlayer_with_react_router_v7_fs_routes.md +40 -83
- package/docs/ar/intlayer_with_solid_start.md +1078 -0
- package/docs/ar/intlayer_with_vite+vue.md +1 -3
- package/docs/ar/packages/intlayer/getLocalizedUrl.md +26 -24
- package/docs/ar/packages/intlayer/getMultilingualUrls.md +4 -18
- package/docs/ar/packages/react-intlayer/useDictionary.md +4 -21
- package/docs/ar/packages/react-intlayer/useIntlayer.md +2 -2
- package/docs/ar/packages/vite-intlayer/exports.md +15 -0
- package/docs/ar/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/ar/packages/vite-intlayer/intlayerPrune.md +70 -3
- package/docs/ar/releases/v9.md +0 -37
- package/docs/ar/self_hosting.md +46 -49
- package/docs/bn/configuration.md +25 -8
- package/docs/bn/intlayer_with_angular_21.md +9 -9
- package/docs/cs/configuration.md +25 -8
- package/docs/cs/intlayer_with_angular_21.md +9 -9
- package/docs/de/analytics.md +222 -0
- package/docs/de/autoFill.md +28 -9
- package/docs/de/configuration.md +25 -8
- package/docs/de/dictionary/file.md +3 -1
- package/docs/de/dictionary/nesting.md +47 -31
- package/docs/de/formatters.md +208 -334
- package/docs/de/intlayer_CMS.md +66 -15
- package/docs/de/intlayer_with_angular_21.md +9 -9
- package/docs/de/intlayer_with_nestjs.md +11 -7
- package/docs/de/intlayer_with_nextjs_14.md +1 -28
- package/docs/de/intlayer_with_nextjs_15.md +1 -33
- package/docs/de/intlayer_with_solid_start.md +1078 -0
- package/docs/de/intlayer_with_vite+vue.md +1 -3
- package/docs/de/packages/intlayer/getLocalizedUrl.md +33 -25
- package/docs/de/packages/intlayer/getMultilingualUrls.md +4 -18
- package/docs/de/packages/react-intlayer/useDictionary.md +2 -5
- package/docs/de/packages/vite-intlayer/exports.md +15 -0
- package/docs/de/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/de/packages/vite-intlayer/intlayerPrune.md +77 -4
- package/docs/de/releases/v9.md +0 -15
- package/docs/de/self_hosting.md +46 -50
- package/docs/en/cli/doc-review.md +13 -2
- package/docs/en/configuration.md +24 -15
- package/docs/en/intlayer_with_angular_21.md +9 -9
- package/docs/en/intlayer_with_solid_start.md +1091 -0
- package/docs/en/intlayer_with_vite+solid.md +12 -0
- package/docs/en-GB/analytics.md +222 -0
- package/docs/en-GB/autoFill.md +26 -7
- package/docs/en-GB/configuration.md +25 -8
- package/docs/en-GB/dictionary/file.md +2 -0
- package/docs/en-GB/dictionary/nesting.md +64 -205
- package/docs/en-GB/formatters.md +146 -181
- package/docs/en-GB/intlayer_CMS.md +152 -0
- package/docs/en-GB/intlayer_with_angular_21.md +9 -9
- package/docs/en-GB/intlayer_with_nestjs.md +6 -2
- package/docs/en-GB/intlayer_with_nextjs_14.md +0 -27
- package/docs/en-GB/intlayer_with_nextjs_15.md +1 -33
- package/docs/en-GB/intlayer_with_react_router_v7_fs_routes.md +40 -82
- package/docs/en-GB/intlayer_with_solid_start.md +1078 -0
- package/docs/en-GB/intlayer_with_vite+vue.md +1 -3
- package/docs/en-GB/packages/intlayer/getLocalizedUrl.md +30 -22
- package/docs/en-GB/packages/intlayer/getMultilingualUrls.md +16 -48
- package/docs/en-GB/packages/vite-intlayer/exports.md +15 -0
- package/docs/en-GB/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/en-GB/packages/vite-intlayer/intlayerPrune.md +77 -4
- package/docs/en-GB/self_hosting.md +60 -49
- package/docs/es/analytics.md +222 -0
- package/docs/es/autoFill.md +28 -9
- package/docs/es/configuration.md +24 -7
- package/docs/es/dictionary/file.md +3 -1
- package/docs/es/dictionary/nesting.md +47 -30
- package/docs/es/formatters.md +114 -168
- package/docs/es/intlayer_CMS.md +35 -10
- package/docs/es/intlayer_with_angular_21.md +9 -9
- package/docs/es/intlayer_with_nextjs_14.md +1 -28
- package/docs/es/intlayer_with_nextjs_15.md +1 -33
- package/docs/es/intlayer_with_solid_start.md +1078 -0
- package/docs/es/packages/intlayer/getLocalizedUrl.md +31 -23
- package/docs/es/packages/intlayer/getMultilingualUrls.md +4 -18
- package/docs/es/packages/vite-intlayer/exports.md +15 -0
- package/docs/es/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/es/packages/vite-intlayer/intlayerPrune.md +69 -2
- package/docs/es/releases/v9.md +0 -15
- package/docs/es/self_hosting.md +46 -49
- package/docs/fr/analytics.md +222 -0
- package/docs/fr/autoFill.md +27 -8
- package/docs/fr/configuration.md +25 -8
- package/docs/fr/dictionary/file.md +2 -0
- package/docs/fr/dictionary/nesting.md +37 -184
- package/docs/fr/formatters.md +95 -236
- package/docs/fr/intlayer_CMS.md +66 -15
- package/docs/fr/intlayer_with_angular_21.md +9 -9
- package/docs/fr/intlayer_with_nextjs_14.md +1 -28
- package/docs/fr/intlayer_with_nextjs_15.md +1 -33
- package/docs/fr/intlayer_with_solid_start.md +1078 -0
- package/docs/fr/packages/intlayer/getLocalizedUrl.md +37 -27
- package/docs/fr/packages/intlayer/getMultilingualUrls.md +18 -20
- package/docs/fr/packages/vite-intlayer/exports.md +15 -0
- package/docs/fr/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/fr/packages/vite-intlayer/intlayerPrune.md +77 -4
- package/docs/fr/releases/v9.md +0 -15
- package/docs/fr/self_hosting.md +46 -49
- package/docs/hi/analytics.md +222 -0
- package/docs/hi/autoFill.md +28 -9
- package/docs/hi/configuration.md +25 -8
- package/docs/hi/dictionary/file.md +3 -1
- package/docs/hi/dictionary/nesting.md +47 -30
- package/docs/hi/formatters.md +233 -334
- package/docs/hi/how_works_intlayer.md +3 -1
- package/docs/hi/intlayer_CMS.md +152 -0
- package/docs/hi/intlayer_with_angular_21.md +9 -9
- package/docs/hi/intlayer_with_nestjs.md +11 -7
- package/docs/hi/intlayer_with_nextjs_14.md +1 -28
- package/docs/hi/intlayer_with_nextjs_15.md +1 -33
- package/docs/hi/intlayer_with_react_router_v7_fs_routes.md +40 -83
- package/docs/hi/intlayer_with_solid_start.md +1077 -0
- package/docs/hi/intlayer_with_vite+preact.md +56 -49
- package/docs/hi/intlayer_with_vite+react.md +48 -41
- package/docs/hi/intlayer_with_vite+solid.md +32 -41
- package/docs/hi/intlayer_with_vite+vue.md +49 -44
- package/docs/hi/packages/intlayer/getLocalizedUrl.md +26 -24
- package/docs/hi/packages/intlayer/getMultilingualUrls.md +4 -18
- package/docs/hi/packages/next-intlayer/t.md +33 -1
- package/docs/hi/packages/react-intlayer/useDictionary.md +4 -21
- package/docs/hi/packages/vite-intlayer/exports.md +15 -0
- package/docs/hi/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/hi/packages/vite-intlayer/intlayerPrune.md +78 -5
- package/docs/hi/plugins/sync-json.md +9 -9
- package/docs/hi/releases/v9.md +0 -15
- package/docs/hi/self_hosting.md +38 -51
- package/docs/id/analytics.md +223 -0
- package/docs/id/configuration.md +25 -8
- package/docs/id/dictionary/nesting.md +37 -184
- package/docs/id/formatters.md +208 -305
- package/docs/id/intlayer_CMS.md +164 -0
- package/docs/id/intlayer_with_angular_21.md +9 -9
- package/docs/id/intlayer_with_nextjs_14.md +1 -26
- package/docs/id/intlayer_with_react_router_v7_fs_routes.md +70 -63
- package/docs/id/intlayer_with_solid_start.md +1078 -0
- package/docs/id/packages/intlayer/getMultilingualUrls.md +4 -18
- package/docs/id/packages/react-intlayer/useIntlayer.md +2 -2
- package/docs/id/packages/vite-intlayer/exports.md +15 -0
- package/docs/id/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/id/packages/vite-intlayer/intlayerPrune.md +78 -5
- package/docs/id/releases/v9.md +12 -0
- package/docs/id/self_hosting.md +61 -50
- package/docs/it/analytics.md +222 -0
- package/docs/it/autoFill.md +27 -8
- package/docs/it/configuration.md +25 -8
- package/docs/it/dictionary/file.md +3 -1
- package/docs/it/dictionary/nesting.md +47 -30
- package/docs/it/formatters.md +114 -168
- package/docs/it/intlayer_CMS.md +66 -15
- package/docs/it/intlayer_with_angular_21.md +9 -9
- package/docs/it/intlayer_with_nestjs.md +11 -7
- package/docs/it/intlayer_with_nextjs_14.md +1 -28
- package/docs/it/intlayer_with_nextjs_15.md +1 -33
- package/docs/it/intlayer_with_solid_start.md +1078 -0
- package/docs/it/intlayer_with_vite+vue.md +1 -3
- package/docs/it/packages/intlayer/getLocalizedUrl.md +34 -26
- package/docs/it/packages/intlayer/getMultilingualUrls.md +4 -18
- package/docs/it/packages/react-intlayer/useDictionary.md +4 -21
- package/docs/it/packages/vite-intlayer/exports.md +15 -0
- package/docs/it/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/it/packages/vite-intlayer/intlayerPrune.md +77 -4
- package/docs/it/releases/v9.md +0 -15
- package/docs/it/self_hosting.md +60 -49
- package/docs/ja/analytics.md +222 -0
- package/docs/ja/autoFill.md +28 -9
- package/docs/ja/configuration.md +25 -8
- package/docs/ja/dictionary/content_file.md +15 -7
- package/docs/ja/dictionary/file.md +3 -1
- package/docs/ja/dictionary/nesting.md +47 -30
- package/docs/ja/formatters.md +133 -187
- package/docs/ja/intlayer_visual_editor.md +3 -1
- package/docs/ja/intlayer_with_angular_21.md +6 -6
- package/docs/ja/intlayer_with_nestjs.md +2 -12
- package/docs/ja/intlayer_with_nextjs_14.md +1 -28
- package/docs/ja/intlayer_with_nextjs_15.md +1 -33
- package/docs/ja/intlayer_with_react_router_v7.md +456 -20
- package/docs/ja/intlayer_with_solid_start.md +1078 -0
- package/docs/ja/intlayer_with_vite+preact.md +73 -41
- package/docs/ja/intlayer_with_vite+vue.md +1 -3
- package/docs/ja/mcp_server.md +3 -9
- package/docs/ja/packages/intlayer/getLocalizedUrl.md +26 -24
- package/docs/ja/packages/intlayer/getMultilingualUrls.md +3 -17
- package/docs/ja/packages/vite-intlayer/exports.md +15 -0
- package/docs/ja/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/ja/packages/vite-intlayer/intlayerPrune.md +79 -6
- package/docs/ja/releases/v9.md +12 -0
- package/docs/ja/self_hosting.md +46 -50
- package/docs/ko/analytics.md +222 -0
- package/docs/ko/autoFill.md +28 -9
- package/docs/ko/configuration.md +25 -8
- package/docs/ko/dictionary/file.md +3 -1
- package/docs/ko/dictionary/nesting.md +47 -30
- package/docs/ko/formatters.md +133 -187
- package/docs/ko/intlayer_with_angular_21.md +9 -9
- package/docs/ko/intlayer_with_lynx+react.md +133 -39
- package/docs/ko/intlayer_with_nextjs_14.md +1 -28
- package/docs/ko/intlayer_with_nextjs_15.md +1 -33
- package/docs/ko/intlayer_with_react_router_v7_fs_routes.md +40 -188
- package/docs/ko/intlayer_with_solid_start.md +1078 -0
- package/docs/ko/intlayer_with_vite+preact.md +57 -23
- package/docs/ko/intlayer_with_vite+vue.md +1 -3
- package/docs/ko/packages/intlayer/getLocalizedUrl.md +26 -24
- package/docs/ko/packages/intlayer/getMultilingualUrls.md +4 -18
- package/docs/ko/packages/vite-intlayer/exports.md +15 -0
- package/docs/ko/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/ko/packages/vite-intlayer/intlayerPrune.md +79 -6
- package/docs/ko/releases/v9.md +12 -0
- package/docs/ko/self_hosting.md +60 -49
- package/docs/nl/configuration.md +25 -8
- package/docs/nl/intlayer_with_angular_21.md +9 -9
- package/docs/pl/analytics.md +220 -0
- package/docs/pl/configuration.md +25 -8
- package/docs/pl/dictionary/nesting.md +47 -30
- package/docs/pl/formatters.md +208 -305
- package/docs/pl/intlayer_CMS.md +152 -0
- package/docs/pl/intlayer_with_angular_21.md +9 -9
- package/docs/pl/intlayer_with_nextjs_14.md +1 -26
- package/docs/pl/intlayer_with_solid_start.md +1078 -0
- package/docs/pl/packages/intlayer/getMultilingualUrls.md +4 -18
- package/docs/pl/packages/react-intlayer/useDictionary.md +2 -19
- package/docs/pl/packages/vite-intlayer/exports.md +15 -0
- package/docs/pl/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/pl/packages/vite-intlayer/intlayerPrune.md +77 -4
- package/docs/pl/releases/v9.md +0 -15
- package/docs/pl/self_hosting.md +60 -49
- package/docs/pt/analytics.md +222 -0
- package/docs/pt/configuration.md +25 -8
- package/docs/pt/dictionary/file.md +3 -1
- package/docs/pt/dictionary/nesting.md +47 -30
- package/docs/pt/formatters.md +112 -168
- package/docs/pt/intlayer_CMS.md +66 -15
- package/docs/pt/intlayer_with_angular_21.md +9 -9
- package/docs/pt/intlayer_with_astro_lit.md +26 -1
- package/docs/pt/intlayer_with_nextjs_14.md +1 -28
- package/docs/pt/intlayer_with_nextjs_15.md +1 -33
- package/docs/pt/intlayer_with_solid_start.md +1078 -0
- package/docs/pt/intlayer_with_vite+vue.md +1 -3
- package/docs/pt/packages/intlayer/getLocalizedUrl.md +34 -26
- package/docs/pt/packages/intlayer/getMultilingualUrls.md +4 -18
- package/docs/pt/packages/vite-intlayer/exports.md +15 -0
- package/docs/pt/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/pt/packages/vite-intlayer/intlayerPrune.md +78 -6
- package/docs/pt/releases/v9.md +0 -15
- package/docs/pt/self_hosting.md +60 -49
- package/docs/ru/analytics.md +222 -0
- package/docs/ru/autoFill.md +27 -8
- package/docs/ru/configuration.md +25 -8
- package/docs/ru/dictionary/file.md +3 -1
- package/docs/ru/dictionary/nesting.md +64 -205
- package/docs/ru/formatters.md +108 -128
- package/docs/ru/intlayer_with_angular_21.md +9 -9
- package/docs/ru/intlayer_with_nextjs_14.md +1 -28
- package/docs/ru/intlayer_with_nextjs_15.md +1 -33
- package/docs/ru/intlayer_with_solid_start.md +1078 -0
- package/docs/ru/intlayer_with_vite+vue.md +1 -3
- package/docs/ru/packages/intlayer/getLocalizedUrl.md +34 -26
- package/docs/ru/packages/intlayer/getMultilingualUrls.md +4 -18
- package/docs/ru/packages/react-intlayer/useDictionary.md +4 -21
- package/docs/ru/packages/vite-intlayer/exports.md +15 -0
- package/docs/ru/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/ru/packages/vite-intlayer/intlayerPrune.md +77 -4
- package/docs/ru/releases/v9.md +0 -15
- package/docs/ru/self_hosting.md +60 -49
- package/docs/tr/analytics.md +222 -0
- package/docs/tr/autoFill.md +28 -9
- package/docs/tr/configuration.md +25 -8
- package/docs/tr/dictionary/file.md +2 -0
- package/docs/tr/dictionary/nesting.md +47 -30
- package/docs/tr/formatters.md +144 -190
- package/docs/tr/intlayer_CMS.md +152 -0
- package/docs/tr/intlayer_with_angular_21.md +9 -9
- package/docs/tr/intlayer_with_nestjs.md +2 -12
- package/docs/tr/intlayer_with_nextjs_15.md +1 -33
- package/docs/tr/intlayer_with_solid_start.md +1078 -0
- package/docs/tr/intlayer_with_vite+vue.md +1 -3
- package/docs/tr/packages/intlayer/getMultilingualUrls.md +4 -18
- package/docs/tr/packages/vite-intlayer/exports.md +15 -0
- package/docs/tr/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/tr/packages/vite-intlayer/intlayerPrune.md +77 -4
- package/docs/tr/self_hosting.md +47 -50
- package/docs/uk/analytics.md +222 -0
- package/docs/uk/configuration.md +25 -8
- package/docs/uk/dictionary/nesting.md +47 -30
- package/docs/uk/formatters.md +128 -185
- package/docs/uk/intlayer_CMS.md +152 -0
- package/docs/uk/intlayer_with_angular_21.md +9 -9
- package/docs/uk/intlayer_with_nextjs_14.md +1 -26
- package/docs/uk/intlayer_with_solid_start.md +1078 -0
- package/docs/uk/packages/react-intlayer/useDictionary.md +2 -19
- package/docs/uk/packages/vite-intlayer/exports.md +15 -0
- package/docs/uk/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/uk/packages/vite-intlayer/intlayerPrune.md +77 -4
- package/docs/uk/releases/v9.md +0 -15
- package/docs/uk/self_hosting.md +60 -50
- package/docs/ur/configuration.md +25 -8
- package/docs/ur/intlayer_with_angular_21.md +9 -9
- package/docs/vi/analytics.md +222 -0
- package/docs/vi/configuration.md +24 -8
- package/docs/vi/dictionary/nesting.md +37 -184
- package/docs/vi/formatters.md +208 -309
- package/docs/vi/intlayer_CMS.md +164 -0
- package/docs/vi/intlayer_with_angular_21.md +9 -9
- package/docs/vi/intlayer_with_nextjs_14.md +0 -25
- package/docs/vi/intlayer_with_react_router_v7_fs_routes.md +70 -63
- package/docs/vi/intlayer_with_solid_start.md +1078 -0
- package/docs/vi/packages/intlayer/getMultilingualUrls.md +4 -18
- package/docs/vi/packages/react-intlayer/useIntlayer.md +2 -2
- package/docs/vi/packages/vite-intlayer/exports.md +15 -0
- package/docs/vi/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/vi/packages/vite-intlayer/intlayerPrune.md +77 -4
- package/docs/vi/plugins/sync-json.md +6 -6
- package/docs/vi/releases/v9.md +12 -0
- package/docs/vi/self_hosting.md +61 -50
- package/docs/zh/CI_CD.md +4 -0
- package/docs/zh/analytics.md +222 -0
- package/docs/zh/autoFill.md +28 -9
- package/docs/zh/configuration.md +24 -8
- package/docs/zh/dictionary/file.md +2 -0
- package/docs/zh/dictionary/nesting.md +47 -30
- package/docs/zh/formatters.md +140 -188
- package/docs/zh/intlayer_CMS.md +164 -0
- package/docs/zh/intlayer_with_analog.md +193 -3
- package/docs/zh/intlayer_with_angular_19.md +272 -3
- package/docs/zh/intlayer_with_angular_21.md +7 -7
- package/docs/zh/intlayer_with_create_react_app.md +348 -26
- package/docs/zh/intlayer_with_lynx+react.md +263 -4
- package/docs/zh/intlayer_with_nextjs_14.md +1 -28
- package/docs/zh/intlayer_with_nextjs_15.md +1 -33
- package/docs/zh/intlayer_with_nextjs_no_locale_path.md +558 -1
- package/docs/zh/intlayer_with_nuxt.md +182 -7
- package/docs/zh/intlayer_with_react_router_v7.md +183 -25
- package/docs/zh/intlayer_with_react_router_v7_fs_routes.md +306 -42
- package/docs/zh/intlayer_with_solid_start.md +1077 -0
- package/docs/zh/intlayer_with_storybook.md +260 -3
- package/docs/zh/intlayer_with_svelte_kit.md +428 -48
- package/docs/zh/intlayer_with_tanstack+solid.md +713 -13
- package/docs/zh/intlayer_with_tanstack.md +731 -20
- package/docs/zh/intlayer_with_vanilla.md +314 -4
- package/docs/zh/intlayer_with_vite+lit.md +465 -4
- package/docs/zh/intlayer_with_vite+preact.md +422 -116
- package/docs/zh/intlayer_with_vite+react.md +324 -45
- package/docs/zh/intlayer_with_vite+react_compiler.md +228 -13
- package/docs/zh/intlayer_with_vite+solid.md +462 -32
- package/docs/zh/intlayer_with_vite+vanilla.md +497 -4
- package/docs/zh/mcp_server.md +3 -9
- package/docs/zh/packages/intlayer/getLocalizedUrl.md +26 -24
- package/docs/zh/packages/intlayer/getMultilingualUrls.md +4 -18
- package/docs/zh/packages/vite-intlayer/exports.md +29 -0
- package/docs/zh/packages/vite-intlayer/intlayer.md +121 -6
- package/docs/zh/packages/vite-intlayer/intlayerPrune.md +79 -6
- package/docs/zh/releases/v9.md +12 -0
- package/docs/zh/self_hosting.md +60 -50
- package/docs/zh-TW/intlayer_with_angular_21.md +7 -7
- package/package.json +6 -6
- package/src/generated/blog.entry.ts +27 -27
- package/src/generated/docs.entry.ts +234 -214
- package/src/generated/frequentQuestions.entry.ts +17 -17
- package/src/generated/legal.entry.ts +2 -2
|
@@ -0,0 +1,1078 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2025-08-06
|
|
3
|
+
updatedAt: 2026-08-06
|
|
4
|
+
title: "Solid Start i18n - Guide complet pour traduire votre application"
|
|
5
|
+
description: "Fini i18next. Le guide 2026 pour créer une application SolidStart multilingue (i18n). Routage de locale rendu côté serveur, hreflang, sitemap et traduction assistée par IA."
|
|
6
|
+
keywords:
|
|
7
|
+
- Internationalization
|
|
8
|
+
- Documentation
|
|
9
|
+
- Intlayer
|
|
10
|
+
- SolidStart
|
|
11
|
+
- Solid
|
|
12
|
+
- i18n
|
|
13
|
+
- TypeScript
|
|
14
|
+
- Locale Routing
|
|
15
|
+
- Sitemap
|
|
16
|
+
slugs:
|
|
17
|
+
- doc
|
|
18
|
+
- environment
|
|
19
|
+
- solid-start
|
|
20
|
+
applicationTemplate: https://github.com/aymericzip/intlayer-solid-start-template
|
|
21
|
+
history:
|
|
22
|
+
- version: 9.1.3
|
|
23
|
+
date: 2025-08-06
|
|
24
|
+
changes: "Historique initial"
|
|
25
|
+
author: aymericzip
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# Traduire votre site SolidStart avec Intlayer | Internationalisation (i18n)
|
|
29
|
+
|
|
30
|
+
<Tabs defaultTab="video">
|
|
31
|
+
<Tab label="Vidéo" value="video">
|
|
32
|
+
|
|
33
|
+
<iframe title="La meilleure solution i18n pour Vite et Solid ? Découvrez Intlayer" class="m-auto aspect-16/9 w-full overflow-hidden rounded-lg border-0" allow="autoplay; gyroscope;" loading="lazy" width="1080" height="auto" src="https://www.youtube.com/embed/dS9L7uJeak4?si=VaKmrYMmXjo3xpk2"/>
|
|
34
|
+
|
|
35
|
+
</Tab>
|
|
36
|
+
<Tab label="Code" value="code">
|
|
37
|
+
|
|
38
|
+
<iframe
|
|
39
|
+
src="https://ide.intlayer.org/aymericzip/intlayer-solid-start-template?file=intlayer.config.ts"
|
|
40
|
+
className="m-auto overflow-hidden rounded-lg border-0 max-md:size-full max-md:h-[700px] md:aspect-16/9 md:w-full"
|
|
41
|
+
title="Démo CodeSandbox - Comment internationaliser votre application avec Intlayer"
|
|
42
|
+
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
|
|
43
|
+
loading="lazy"
|
|
44
|
+
/>
|
|
45
|
+
|
|
46
|
+
</Tab>
|
|
47
|
+
</Tabs>
|
|
48
|
+
|
|
49
|
+
## Table des matières
|
|
50
|
+
|
|
51
|
+
<TOC/>
|
|
52
|
+
|
|
53
|
+
Ce guide couvre une application SolidStart **rendue côté serveur** : la détection de la locale se fait lors de la requête, les pages sont rendues sur le serveur dans la bonne langue, et les signaux `<html lang>`, `hreflang` et sitemap dont les moteurs de recherche ont besoin sont émis côté serveur.
|
|
54
|
+
|
|
55
|
+
## Pourquoi Intlayer plutôt que des alternatives ?
|
|
56
|
+
|
|
57
|
+
Par rapport aux principales solutions comme `@solid-primitives/i18n` ou `i18next`, Intlayer est une solution qui intègre des optimisations comme :
|
|
58
|
+
|
|
59
|
+
<AccordionGroup>
|
|
60
|
+
|
|
61
|
+
<Accordion header="Couverture complète de Solid">
|
|
62
|
+
|
|
63
|
+
Intlayer est optimisé pour fonctionner parfaitement avec Solid en offrant un **ciblage du contenu au niveau des composants**, des **traductions réactives**, et toutes les fonctionnalités nécessaires pour faire évoluer l'internationalisation (i18n).
|
|
64
|
+
|
|
65
|
+
</Accordion>
|
|
66
|
+
|
|
67
|
+
<Accordion header="Taille du bundle">
|
|
68
|
+
|
|
69
|
+
Au lieu de charger de volumineux fichiers JSON dans vos pages, chargez uniquement le contenu nécessaire. Intlayer aide à **réduire la taille de votre bundle et de vos pages jusqu'à 50 %**.
|
|
70
|
+
|
|
71
|
+
</Accordion>
|
|
72
|
+
|
|
73
|
+
<Accordion header="Maintenabilité">
|
|
74
|
+
|
|
75
|
+
Cibler le contenu de votre application **facilite la maintenance** pour les applications à grande échelle. Vous pouvez dupliquer ou supprimer un dossier de fonctionnalité individuel sans la charge mentale de vérifier l'ensemble de votre base de code de contenu. De plus, Intlayer est **entièrement typé** pour garantir l'exactitude de votre contenu.
|
|
76
|
+
|
|
77
|
+
</Accordion>
|
|
78
|
+
|
|
79
|
+
<Accordion header="Agent IA">
|
|
80
|
+
|
|
81
|
+
Colocaliser le contenu **réduit le contexte nécessaire** pour les grands modèles de langage (LLM). Intlayer est également livré avec une suite d'outils, tels qu'un **CLI** pour tester les traductions manquantes, le **[LSP](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/lsp.md)**, le **[MCP](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/mcp_server.md)**, et des **[compétences d'agent](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/agent_skills.md)**, pour rendre l'expérience développeur (DX) encore plus fluide pour les agents IA.
|
|
82
|
+
|
|
83
|
+
</Accordion>
|
|
84
|
+
|
|
85
|
+
<Accordion header="Automation">
|
|
86
|
+
|
|
87
|
+
Utilisez l'automatisation pour traduire dans votre pipeline CI/CD en utilisant le LLM de votre choix au coût de votre fournisseur d'IA. Intlayer propose également un **compilateur** pour automatiser l'extraction de contenu, ainsi qu'une [plateforme web](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/intlayer_CMS.md) pour vous aider à **traduire en arrière-plan**.
|
|
88
|
+
|
|
89
|
+
</Accordion>
|
|
90
|
+
|
|
91
|
+
<Accordion header="Performance">
|
|
92
|
+
|
|
93
|
+
Connecter de volumineux fichiers JSON à des composants peut entraîner des problèmes de performance et de réactivité. Intlayer optimise le chargement de votre contenu au moment du build.
|
|
94
|
+
|
|
95
|
+
</Accordion>
|
|
96
|
+
|
|
97
|
+
<Accordion header="Évolution avec les non-développeurs">
|
|
98
|
+
|
|
99
|
+
Bien plus qu'une simple solution i18n, Intlayer fournit un **[éditeur visuel](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/intlayer_visual_editor.md) auto-hébergé** et un **[CMS complet](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/intlayer_CMS.md)** pour vous aider à gérer votre contenu multilingue en **temps réel**, rendant la collaboration avec les traducteurs, rédacteurs et autres membres de l'équipe fluide. Le contenu peut être stocké localement et/ou à distance.
|
|
100
|
+
|
|
101
|
+
</Accordion>
|
|
102
|
+
</AccordionGroup>
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Guide étape par étape pour configurer Intlayer dans une application SolidStart
|
|
107
|
+
|
|
108
|
+
<Steps>
|
|
109
|
+
|
|
110
|
+
<Step number={1} title="Installer les dépendances">
|
|
111
|
+
|
|
112
|
+
Installez les paquets nécessaires en utilisant npm :
|
|
113
|
+
|
|
114
|
+
```bash packageManager="npm"
|
|
115
|
+
npx intlayer init --interactive
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```bash packageManager="pnpm"
|
|
119
|
+
pnpm dlx intlayer@canary init --interactive
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
```bash packageManager="yarn"
|
|
123
|
+
yarn dlx intlayer@canary init --interactive
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
```bash packageManager="bun"
|
|
127
|
+
bunx intlayer@canary init --interactive
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
> Le drapeau `--interactive` est optionnel. Utilisez `intlayer-cli init` si vous êtes un agent IA.
|
|
131
|
+
|
|
132
|
+
> Cette commande détectera votre environnement et installera les paquets requis. Par exemple :
|
|
133
|
+
|
|
134
|
+
```bash packageManager="npm"
|
|
135
|
+
npm install intlayer solid-intlayer vite-intlayer
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```bash packageManager="pnpm"
|
|
139
|
+
pnpm add intlayer solid-intlayer vite-intlayer
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```bash packageManager="yarn"
|
|
143
|
+
yarn add intlayer solid-intlayer vite-intlayer
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
```bash packageManager="bun"
|
|
147
|
+
bun add intlayer solid-intlayer vite-intlayer
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- **intlayer**
|
|
151
|
+
|
|
152
|
+
Le paquet principal qui fournit des outils d'internationalisation pour la gestion de la configuration, la traduction, la [déclaration de contenu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/dictionary/content_file.md), la transpilation et les [commandes CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/cli/index.md).
|
|
153
|
+
|
|
154
|
+
- **solid-intlayer**
|
|
155
|
+
|
|
156
|
+
Le paquet qui intègre Intlayer avec l'application Solid. Il fournit des fournisseurs de contexte et des hooks pour l'internationalisation Solid.
|
|
157
|
+
|
|
158
|
+
- **vite-intlayer**
|
|
159
|
+
|
|
160
|
+
Inclut le plugin Vite pour intégrer Intlayer avec le [bundler Vite](https://vite.dev/guide/why.html#why-bundle-for-production), ainsi que le gestionnaire de routage de locale qui détecte la locale préférée de l'utilisateur, gère les cookies et s'occupe de la redirection d'URL.
|
|
161
|
+
|
|
162
|
+
> `vite-intlayer` est ici une préoccupation côté serveur, et pas seulement au moment du build : il fournit le gestionnaire de requête exécuté par le serveur Nitro de SolidStart. Le conserver dans `dependencies` est l'option sécurisée par défaut — vous ne pouvez le déplacer dans `devDependencies` que si vous déployez le répertoire `.output` construit, dans lequel Nitro intègre le gestionnaire.
|
|
163
|
+
|
|
164
|
+
</Step>
|
|
165
|
+
|
|
166
|
+
<Step number={2} title="Configuration de votre projet">
|
|
167
|
+
|
|
168
|
+
Créez un fichier de configuration pour configurer les langues de votre application :
|
|
169
|
+
|
|
170
|
+
```typescript fileName="intlayer.config.ts" codeFormat={["typescript", "esm", "commonjs"]}
|
|
171
|
+
import { type IntlayerConfig, Locales } from "intlayer";
|
|
172
|
+
|
|
173
|
+
const config: IntlayerConfig = {
|
|
174
|
+
internationalization: {
|
|
175
|
+
locales: [
|
|
176
|
+
Locales.ENGLISH,
|
|
177
|
+
Locales.FRENCH,
|
|
178
|
+
Locales.SPANISH,
|
|
179
|
+
// Vos autres locales
|
|
180
|
+
],
|
|
181
|
+
defaultLocale: Locales.ENGLISH,
|
|
182
|
+
},
|
|
183
|
+
routing: {
|
|
184
|
+
mode: "prefix-no-default",
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export default config;
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Avec `prefix-no-default`, la locale par défaut est servie depuis des URL sans préfixe :
|
|
192
|
+
|
|
193
|
+
```plaintext
|
|
194
|
+
/ /about → Anglais (locale par défaut)
|
|
195
|
+
/fr /fr/about → Français
|
|
196
|
+
/es /es/about → Espagnol
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
> Grâce à ce fichier de configuration, vous pouvez configurer les URL localisées, la redirection middleware, les noms de cookies, l'emplacement et l'extension de vos déclarations de contenu, désactiver les logs Intlayer dans la console, et plus encore. Pour une liste complète des paramètres disponibles, reportez-vous à la [documentation de configuration](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/configuration.md).
|
|
200
|
+
|
|
201
|
+
</Step>
|
|
202
|
+
|
|
203
|
+
<Step number={3} title="Intégrer Intlayer dans votre configuration Vite">
|
|
204
|
+
|
|
205
|
+
Ajoutez le plugin Intlayer à votre configuration :
|
|
206
|
+
|
|
207
|
+
```typescript fileName="vite.config.ts" codeFormat={["typescript", "esm", "commonjs"]}
|
|
208
|
+
import { solidStart } from "@solidjs/start/config";
|
|
209
|
+
import { nitro } from "nitro/vite";
|
|
210
|
+
import { defineConfig } from "vite";
|
|
211
|
+
import { intlayer } from "vite-intlayer";
|
|
212
|
+
|
|
213
|
+
export default defineConfig({
|
|
214
|
+
plugins: [solidStart(), nitro(), intlayer()],
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
> Le plugin Vite `intlayer()` construit vos fichiers de déclaration de contenu, les surveille en mode développement et définit les variables d'environnement Intlayer dans l'application. Il fournit également des alias qui optimisent les performances.
|
|
219
|
+
|
|
220
|
+
### Le routage de locale est inclus avec le plugin
|
|
221
|
+
|
|
222
|
+
SolidStart fonctionne sur [Nitro](https://nitro.build), et `intlayer()` enregistre son gestionnaire de routage de locale directement dans le pipeline serveur de Nitro (via l'option `routing.enableProxy`, à `true` par défaut). Rien d'autre à câbler : sur un serveur construit, chaque requête est inspectée avant d'atteindre le routeur, et
|
|
223
|
+
|
|
224
|
+
- la locale est lue depuis le préfixe de l'URL, puis le cookie `INTLAYER_LOCALE`, puis l'en-tête `Accept-Language` ;
|
|
225
|
+
- une URL non préfixée est redirigée vers sa contrepartie localisée lorsque la locale résolue n'est pas celle par défaut (`/` → `/fr`) ;
|
|
226
|
+
- une URL préfixée de manière redundante est redirigée vers sa forme canonique (`/en/about` → `/about`) ;
|
|
227
|
+
- le cookie de locale est réécrit sur la réponse.
|
|
228
|
+
|
|
229
|
+
</Step>
|
|
230
|
+
|
|
231
|
+
<Step number={4} title="Déclarer votre contenu">
|
|
232
|
+
|
|
233
|
+
Créez et gérez vos déclarations de contenu pour stocker les traductions :
|
|
234
|
+
|
|
235
|
+
```tsx fileName="src/contents/home.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
236
|
+
import { type Dictionary, t } from "intlayer";
|
|
237
|
+
|
|
238
|
+
const homeContent = {
|
|
239
|
+
key: "home-page",
|
|
240
|
+
content: {
|
|
241
|
+
title: t({
|
|
242
|
+
en: "Hello world!",
|
|
243
|
+
fr: "Bonjour le monde !",
|
|
244
|
+
es: "¡Hola mundo!",
|
|
245
|
+
}),
|
|
246
|
+
metaTitle: "SolidStart + Intlayer",
|
|
247
|
+
metaDescription: t({
|
|
248
|
+
en: "A SolidStart application internationalized with Intlayer.",
|
|
249
|
+
fr: "Une application SolidStart internationalisée avec Intlayer.",
|
|
250
|
+
es: "Una aplicación SolidStart internacionalizada con Intlayer.",
|
|
251
|
+
}),
|
|
252
|
+
documentation: t({
|
|
253
|
+
en: "Visit start.solidjs.com to learn how to build SolidStart apps.",
|
|
254
|
+
fr: "Visitez start.solidjs.com pour apprendre à créer des applications SolidStart.",
|
|
255
|
+
es: "Visita start.solidjs.com para aprender a crear aplicaciones SolidStart.",
|
|
256
|
+
}),
|
|
257
|
+
},
|
|
258
|
+
} satisfies Dictionary;
|
|
259
|
+
|
|
260
|
+
export default homeContent;
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
```json fileName="src/contents/home.content.json" contentDeclarationFormat="json"
|
|
264
|
+
{
|
|
265
|
+
"$schema": "https://intlayer.org/schema.json",
|
|
266
|
+
"key": "home-page",
|
|
267
|
+
"content": {
|
|
268
|
+
"title": {
|
|
269
|
+
"nodeType": "translation",
|
|
270
|
+
"translation": {
|
|
271
|
+
"en": "Hello world!",
|
|
272
|
+
"fr": "Bonjour le monde !",
|
|
273
|
+
"es": "¡Hola mundo!"
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
"metaTitle": "SolidStart + Intlayer",
|
|
277
|
+
"metaDescription": {
|
|
278
|
+
"nodeType": "translation",
|
|
279
|
+
"translation": {
|
|
280
|
+
"en": "A SolidStart application internationalized with Intlayer.",
|
|
281
|
+
"fr": "Une application SolidStart internationalisée avec Intlayer.",
|
|
282
|
+
"es": "Una aplicación SolidStart internacionalizada con Intlayer."
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
"documentation": {
|
|
286
|
+
"nodeType": "translation",
|
|
287
|
+
"translation": {
|
|
288
|
+
"en": "Visit start.solidjs.com to learn how to build SolidStart apps.",
|
|
289
|
+
"fr": "Visitez start.solidjs.com pour apprendre à créer des applications SolidStart.",
|
|
290
|
+
"es": "Visita start.solidjs.com para aprender a crear aplicaciones SolidStart."
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
> ⚠️ **Piège spécifique à SolidStart** : chaque fichier `.ts` / `.tsx` sous `src/routes` devient une route, et un fichier `.content.ts` a un export par défaut, donc il serait considéré comme une page. Conservez les déclarations de contenu de vos **pages** en dehors du répertoire des routes (`src/contents/` fonctionne très bien). Le contenu des **composants** peut rester colocalisé, car `src/components` n'est pas scanné par le routeur basé sur le système de fichiers.
|
|
298
|
+
|
|
299
|
+
> Vos déclarations de contenu peuvent être définies n'importe où dans votre application dès lors qu'elles sont incluses dans le répertoire `contentDir` (par défaut, `./src`), et correspondent à l'extension de fichier de déclaration de contenu (par défaut, `.content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml}`).
|
|
300
|
+
>
|
|
301
|
+
> Pour plus de détails, reportez-vous à la [documentation de déclaration de contenu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/dictionary/content_file.md).
|
|
302
|
+
|
|
303
|
+
</Step>
|
|
304
|
+
|
|
305
|
+
<Step number={5} title="Ajouter le routage localisé">
|
|
306
|
+
|
|
307
|
+
L'objectif de cette étape est de donner à chaque langue sa propre URL, ce que les moteurs de recherche indexent.
|
|
308
|
+
|
|
309
|
+
Déplacez vos pages sous un **segment dynamique optionnel**. Dans le routeur basé sur le système de fichiers de SolidStart, `[[locale]]` se compile selon le motif de chemin `:locale?` :
|
|
310
|
+
|
|
311
|
+
```plaintext
|
|
312
|
+
src/routes/
|
|
313
|
+
[[locale]].tsx ← layout qui valide le segment
|
|
314
|
+
[[locale]]/
|
|
315
|
+
index.tsx → / et /fr et /es
|
|
316
|
+
about.tsx → /about et /fr/about et /es/about
|
|
317
|
+
[...404].tsx → catch-all pour tout le reste
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Le seul rôle du fichier de layout est de restreindre le segment à une locale configurée :
|
|
321
|
+
|
|
322
|
+
```tsx fileName="src/routes/[[locale]].tsx" codeFormat="typescript"
|
|
323
|
+
import type { RouteSectionProps } from "@solidjs/router";
|
|
324
|
+
import { locales } from "intlayer";
|
|
325
|
+
|
|
326
|
+
export const route = {
|
|
327
|
+
matchFilters: {
|
|
328
|
+
locale: locales,
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
export default function LocaleLayout(props: RouteSectionProps) {
|
|
333
|
+
return <>{props.children}</>;
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
`@solidjs/router` développe `:locale?` en deux motifs — un avec le segment et un sans — et les tente par ordre de spécificité décroissante. `matchFilters` est ce qui fait la différence entre une configuration fonctionnelle et une configuration confuse :
|
|
338
|
+
|
|
339
|
+
| URL | Sans `matchFilters` | Avec `matchFilters` |
|
|
340
|
+
| ----------- | ---------------------------------------------------------- | ------------------------------------------- |
|
|
341
|
+
| `/fr/about` | Page à propos en français | Page à propos en français |
|
|
342
|
+
| `/about` | Page à propos (le segment statique gagne) | Page à propos |
|
|
343
|
+
| `/unknown` | **Page d'accueil**, silencieusement, avec `locale=unknown` | Pas de correspondance → passe au 404 global |
|
|
344
|
+
|
|
345
|
+
> Préférez `[locale]` (obligatoire) à `[[locale]]` si vous utilisez le mode de routage `'prefix-all'`, et supprimez complètement le segment pour `'no-prefix'` ou `'search-params'`.
|
|
346
|
+
|
|
347
|
+
</Step>
|
|
348
|
+
|
|
349
|
+
<Step number={6} title="Fournir la locale à votre application">
|
|
350
|
+
|
|
351
|
+
L'URL est la source unique de vérité pour la locale : le middleware a déjà redirigé la requête vers son chemin localisé, donc lire le chemin dans le layout racine maintient le rendu serveur et l'hydratation client en accord, et permet à chaque navigation côté client de mettre à jour la locale gratuitement.
|
|
352
|
+
|
|
353
|
+
```tsx fileName="src/app.tsx" codeFormat="typescript"
|
|
354
|
+
import { MetaProvider } from "@solidjs/meta";
|
|
355
|
+
import { Router, useLocation } from "@solidjs/router";
|
|
356
|
+
import { FileRoutes } from "@solidjs/start/router";
|
|
357
|
+
import { defaultLocale, getHTMLTextDir, getLocaleFromPath } from "intlayer";
|
|
358
|
+
import { IntlayerProvider } from "solid-intlayer";
|
|
359
|
+
import { createEffect, type ParentProps, Suspense } from "solid-js";
|
|
360
|
+
import { isServer } from "solid-js/web";
|
|
361
|
+
import { Nav } from "~/components/Nav";
|
|
362
|
+
import "./app.css";
|
|
363
|
+
|
|
364
|
+
const RootLayout = (props: ParentProps) => {
|
|
365
|
+
const location = useLocation();
|
|
366
|
+
const locale = () => getLocaleFromPath(location.pathname) ?? defaultLocale;
|
|
367
|
+
|
|
368
|
+
// Le serveur rend <html> dans entry-server.tsx ; les navigations côté client
|
|
369
|
+
// entre les locales doivent mettre à jour les attributs elles-mêmes.
|
|
370
|
+
createEffect(() => {
|
|
371
|
+
if (isServer) return;
|
|
372
|
+
|
|
373
|
+
document.documentElement.lang = locale();
|
|
374
|
+
document.documentElement.dir = getHTMLTextDir(locale());
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
return (
|
|
378
|
+
<MetaProvider>
|
|
379
|
+
<IntlayerProvider locale={locale()}>
|
|
380
|
+
<Nav />
|
|
381
|
+
<Suspense>{props.children}</Suspense>
|
|
382
|
+
</IntlayerProvider>
|
|
383
|
+
</MetaProvider>
|
|
384
|
+
);
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
export default function App() {
|
|
388
|
+
return (
|
|
389
|
+
<Router root={RootLayout}>
|
|
390
|
+
<FileRoutes />
|
|
391
|
+
</Router>
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
> `IntlayerProvider` réagit à sa prop `locale`, donc passer l'appel d'accesseur `locale()` dans le JSX est suffisant — Solid le compile en un getter, et l'ensemble de l'arbre se ré-affiche dans la nouvelle langue lorsque l'URL change.
|
|
397
|
+
|
|
398
|
+
</Step>
|
|
399
|
+
|
|
400
|
+
<Step number={7} title="Définir les attributs HTML lang et dir sur le serveur">
|
|
401
|
+
|
|
402
|
+
L'élément `<html>` est rendu par `entry-server.tsx`, en dehors du `Router`. Lisez plutôt la locale depuis l'URL de la requête :
|
|
403
|
+
|
|
404
|
+
```tsx fileName="src/entry-server.tsx" codeFormat="typescript"
|
|
405
|
+
// @refresh reload
|
|
406
|
+
import { createHandler, StartServer } from "@solidjs/start/server";
|
|
407
|
+
import { defaultLocale, getHTMLTextDir, getLocaleFromPath } from "intlayer";
|
|
408
|
+
import { getRequestEvent } from "solid-js/web";
|
|
409
|
+
|
|
410
|
+
export default createHandler(() => (
|
|
411
|
+
<StartServer
|
|
412
|
+
document={({ assets, children, scripts }) => {
|
|
413
|
+
const url = getRequestEvent()?.request.url ?? "/";
|
|
414
|
+
const locale = getLocaleFromPath(url) ?? defaultLocale;
|
|
415
|
+
|
|
416
|
+
return (
|
|
417
|
+
<html dir={getHTMLTextDir(locale)} lang={locale}>
|
|
418
|
+
<head>
|
|
419
|
+
<meta charset="utf-8" />
|
|
420
|
+
<meta
|
|
421
|
+
name="viewport"
|
|
422
|
+
content="width=device-width, initial-scale=1"
|
|
423
|
+
/>
|
|
424
|
+
<link rel="icon" href="/favicon.ico" />
|
|
425
|
+
{assets}
|
|
426
|
+
</head>
|
|
427
|
+
<body>
|
|
428
|
+
<div id="app">{children}</div>
|
|
429
|
+
{scripts}
|
|
430
|
+
</body>
|
|
431
|
+
</html>
|
|
432
|
+
);
|
|
433
|
+
}}
|
|
434
|
+
/>
|
|
435
|
+
));
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
Les robots d'indexation reçoivent désormais la bonne langue dès le premier octet :
|
|
439
|
+
|
|
440
|
+
```html
|
|
441
|
+
<html dir="ltr" lang="fr"></html>
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
</Step>
|
|
445
|
+
|
|
446
|
+
<Step number={8} title="Utiliser Intlayer dans vos pages">
|
|
447
|
+
|
|
448
|
+
Accédez à vos dictionnaires de contenu dans l'ensemble de votre application :
|
|
449
|
+
|
|
450
|
+
```tsx fileName="src/routes/[[locale]]/index.tsx" codeFormat="typescript"
|
|
451
|
+
import { Meta, Title } from "@solidjs/meta";
|
|
452
|
+
import { useIntlayer } from "solid-intlayer";
|
|
453
|
+
import Counter from "~/components/Counter";
|
|
454
|
+
|
|
455
|
+
export default function Home() {
|
|
456
|
+
const content = useIntlayer("home-page");
|
|
457
|
+
|
|
458
|
+
return (
|
|
459
|
+
<main>
|
|
460
|
+
<Title>{content.metaTitle.value}</Title>
|
|
461
|
+
<Meta content={content.metaDescription.value} name="description" />
|
|
462
|
+
<h1>{content.title}</h1>
|
|
463
|
+
<Counter />
|
|
464
|
+
<p>{content.documentation}</p>
|
|
465
|
+
</main>
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
> Dans Solid, `useIntlayer` renvoie du contenu réactif (ex. `content`). Vous pouvez accéder directement à ses propriétés.
|
|
471
|
+
|
|
472
|
+
> Si vous souhaitez utiliser votre contenu dans un attribut `string`, tel que `alt`, `title`, `href`, `aria-label`, etc., vous pouvez utiliser la valeur de la fonction, comme :
|
|
473
|
+
>
|
|
474
|
+
> ```html
|
|
475
|
+
> <img src="{content.image.src.value}" alt="{content.image.value}" />
|
|
476
|
+
> <img src="{content.image.src.toString()}" alt="{content.image.toString()}" />
|
|
477
|
+
> <img src="{String(content.image.src)}" alt="{String(content.image)}" />
|
|
478
|
+
> ```
|
|
479
|
+
|
|
480
|
+
> Pour en savoir plus sur le hook `useIntlayer`, reportez-vous à la [documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/packages/solid-intlayer/useIntlayer.md).
|
|
481
|
+
|
|
482
|
+
Les nœuds de contenu ne se limitent pas à de simples traductions. Un compteur pluralisé, par exemple :
|
|
483
|
+
|
|
484
|
+
```typescript fileName="src/components/Counter.content.ts" codeFormat="typescript"
|
|
485
|
+
import { type Dictionary, plural, t } from "intlayer";
|
|
486
|
+
|
|
487
|
+
const counterContent = {
|
|
488
|
+
key: "counter",
|
|
489
|
+
content: {
|
|
490
|
+
clicks: plural({
|
|
491
|
+
one: t({
|
|
492
|
+
en: "{{count}} click",
|
|
493
|
+
fr: "{{count}} clic",
|
|
494
|
+
es: "{{count}} clic",
|
|
495
|
+
}),
|
|
496
|
+
other: t({
|
|
497
|
+
en: "{{count}} clicks",
|
|
498
|
+
fr: "{{count}} clics",
|
|
499
|
+
es: "{{count}} clics",
|
|
500
|
+
}),
|
|
501
|
+
}),
|
|
502
|
+
},
|
|
503
|
+
} satisfies Dictionary;
|
|
504
|
+
|
|
505
|
+
export default counterContent;
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
```tsx fileName="src/components/Counter.tsx" codeFormat="typescript"
|
|
509
|
+
import { useIntlayer } from "solid-intlayer";
|
|
510
|
+
import { createSignal } from "solid-js";
|
|
511
|
+
|
|
512
|
+
export default function Counter() {
|
|
513
|
+
const [count, setCount] = createSignal(0);
|
|
514
|
+
const content = useIntlayer("counter");
|
|
515
|
+
|
|
516
|
+
return (
|
|
517
|
+
<button onClick={() => setCount(count() + 1)} type="button">
|
|
518
|
+
{content.clicks(count())}
|
|
519
|
+
</button>
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
`plural()` sélectionne la catégorie via `Intl.PluralRules` pour la locale active, ainsi les langues ayant plus de deux formes pluriel fonctionnent sans aucun code supplémentaire.
|
|
525
|
+
|
|
526
|
+
</Step>
|
|
527
|
+
|
|
528
|
+
<Step number={9} title="Créer un composant Link localisé">
|
|
529
|
+
|
|
530
|
+
Créez un composant `Link` personnalisé qui préfixe automatiquement les URL internes avec la langue actuelle :
|
|
531
|
+
|
|
532
|
+
```tsx fileName="src/components/LocalizedLink.tsx" codeFormat="typescript"
|
|
533
|
+
import { A, type AnchorProps } from "@solidjs/router";
|
|
534
|
+
import { getLocalizedUrl } from "intlayer";
|
|
535
|
+
import { useLocale } from "solid-intlayer";
|
|
536
|
+
import type { ParentComponent } from "solid-js";
|
|
537
|
+
|
|
538
|
+
export const LocalizedLink: ParentComponent<AnchorProps> = (props) => {
|
|
539
|
+
const { locale } = useLocale();
|
|
540
|
+
|
|
541
|
+
const isExternal = () => /^[a-z][a-z0-9+.-]*:/i.test(props.href);
|
|
542
|
+
|
|
543
|
+
const localizedHref = () =>
|
|
544
|
+
isExternal() ? props.href : getLocalizedUrl(props.href, locale());
|
|
545
|
+
|
|
546
|
+
return <A {...props} href={localizedHref()} />;
|
|
547
|
+
};
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
```tsx fileName="src/components/Nav.tsx" codeFormat="typescript"
|
|
551
|
+
import { useIntlayer } from "solid-intlayer";
|
|
552
|
+
import type { Component } from "solid-js";
|
|
553
|
+
import { LocaleSwitcher } from "./LocaleSwitcher";
|
|
554
|
+
import { LocalizedLink } from "./LocalizedLink";
|
|
555
|
+
|
|
556
|
+
export const Nav: Component = () => {
|
|
557
|
+
const content = useIntlayer("nav");
|
|
558
|
+
|
|
559
|
+
return (
|
|
560
|
+
<nav>
|
|
561
|
+
<LocalizedLink href="/">{content.home}</LocalizedLink>
|
|
562
|
+
<LocalizedLink href="/about">{content.about}</LocalizedLink>
|
|
563
|
+
<LocaleSwitcher />
|
|
564
|
+
</nav>
|
|
565
|
+
);
|
|
566
|
+
};
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
Écrire `href="/about"` une seule fois produit désormais `/about`, `/fr/about` ou `/es/about` selon la locale active — aucun préfixage manuel n'est nécessaire dans vos pages.
|
|
570
|
+
|
|
571
|
+
</Step>
|
|
572
|
+
|
|
573
|
+
<Step number={10} title="Créer un composant de changement de locale">
|
|
574
|
+
|
|
575
|
+
Rendez le sélecteur sous forme de **vrais ancres** plutôt qu'un `<select>` : chaque langue de la page actuelle devient un lien explorable pouvant être ouvert dans un nouvel onglet, ce qu'un contrôle uniquement basé sur JavaScript ne peut pas offrir.
|
|
576
|
+
|
|
577
|
+
`getPathWithoutLocale` supprime le segment de locale du chemin actuel, et `getLocalizedUrl` le reconstruit pour la locale cible, afin que les liens suivent votre mode de routage sans rien coder en dur. La navigation est ce qui modifie la locale rendue — la route `[[locale]]` la déduit de l'URL — tandis que `setLocale` persiste le choix dans le cookie `INTLAYER_LOCALE` afin qu'une visite ultérieure sur une URL sans locale soit résolue dans la même langue.
|
|
578
|
+
|
|
579
|
+
```tsx fileName="src/components/LocaleSwitcher.tsx" codeFormat={["typescript", "esm"]}
|
|
580
|
+
import { A, useLocation } from "@solidjs/router";
|
|
581
|
+
import {
|
|
582
|
+
getHTMLTextDir,
|
|
583
|
+
getLocaleName,
|
|
584
|
+
getLocalizedUrl,
|
|
585
|
+
getPathWithoutLocale,
|
|
586
|
+
} from "intlayer";
|
|
587
|
+
import { useIntlayer, useLocale } from "solid-intlayer";
|
|
588
|
+
import { type Component, For } from "solid-js";
|
|
589
|
+
|
|
590
|
+
export const LocaleSwitcher: Component = () => {
|
|
591
|
+
const content = useIntlayer("locale-switcher");
|
|
592
|
+
const location = useLocation();
|
|
593
|
+
const { locale, setLocale, availableLocales } = useLocale();
|
|
594
|
+
|
|
595
|
+
// Chemin canonique (sans locale) de la page actuellement affichée
|
|
596
|
+
const pathWithoutLocale = () => getPathWithoutLocale(location.pathname);
|
|
597
|
+
|
|
598
|
+
return (
|
|
599
|
+
<div>
|
|
600
|
+
<button
|
|
601
|
+
aria-label={content.label.value}
|
|
602
|
+
popoverTarget="localePopover"
|
|
603
|
+
type="button"
|
|
604
|
+
>
|
|
605
|
+
{getLocaleName(locale())}
|
|
606
|
+
</button>
|
|
607
|
+
<div id="localePopover" popover="auto">
|
|
608
|
+
<For each={availableLocales}>
|
|
609
|
+
{(localeItem) => (
|
|
610
|
+
<A
|
|
611
|
+
dir={getHTMLTextDir(localeItem)}
|
|
612
|
+
// Correspondance exacte uniquement, afin que le lien de la locale par défaut ne soit pas marqué
|
|
613
|
+
// actif sur chaque page
|
|
614
|
+
end
|
|
615
|
+
href={getLocalizedUrl(pathWithoutLocale(), localeItem)}
|
|
616
|
+
hreflang={localeItem}
|
|
617
|
+
lang={localeItem}
|
|
618
|
+
onClick={() => setLocale(localeItem)}
|
|
619
|
+
// S'assure que le bouton "retour" du navigateur revienne à la page précédente
|
|
620
|
+
replace
|
|
621
|
+
>
|
|
622
|
+
{/* Langue dans sa propre locale - ex. Français */}
|
|
623
|
+
{getLocaleName(localeItem)}
|
|
624
|
+
</A>
|
|
625
|
+
)}
|
|
626
|
+
</For>
|
|
627
|
+
</div>
|
|
628
|
+
</div>
|
|
629
|
+
);
|
|
630
|
+
};
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
> Dans Solid, `locale` provenant de `useLocale` est un **accesseur de signal**. Utilisez `locale()` (avec parenthèses) pour lire sa valeur actuelle de manière réactive.
|
|
634
|
+
>
|
|
635
|
+
> `getLocaleName(localeItem)` rend chaque langue dans sa propre langue — `English / Français / Español`. Passez un second argument pour traduire les noms dans la langue actuellement affichée à la place : `getLocaleName(localeItem, locale())` donne `English / French / Spanish` en anglais, `anglais / français / espagnol` en français.
|
|
636
|
+
>
|
|
637
|
+
> `<A>` définit déjà `aria-current="page"` sur le lien correspondant à l'URL actuelle, il n'y a donc rien à ajouter pour cela. `replace` est lu depuis l'attribut rendu par le routeur : il remplace l'entrée d'historique au lieu d'en ajouter une, ainsi le bouton "retour" du navigateur revient à la page visitée avant le changement plutôt qu'à la même page dans la langue précédente.
|
|
638
|
+
>
|
|
639
|
+
> `dir` et `hreflang` sur chaque lien permettent de conserver les noms de langues de droite à gauche correctement orientés et d'indiquer aux technologies d'assistance et aux robots d'indexation la langue vers laquelle pointe chaque lien.
|
|
640
|
+
>
|
|
641
|
+
> Pour en savoir plus sur le hook `useLocale`, reportez-vous à la [documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/packages/solid-intlayer/useLocale.md).
|
|
642
|
+
|
|
643
|
+
</Step>
|
|
644
|
+
|
|
645
|
+
<Step number={11} title="Émettre les liens canoniques et hreflang" isOptional={true}>
|
|
646
|
+
|
|
647
|
+
Les annotations `hreflang` indiquent aux moteurs de recherche que `/about`, `/fr/about` et `/es/about` représentent la même page dans des langues différentes. `getMultilingualUrls` les déduit du chemin canonique (sans locale), en suivant votre mode de routage, afin que rien ne soit codé en dur :
|
|
648
|
+
|
|
649
|
+
```tsx fileName="src/components/AlternateLinks.tsx" codeFormat="typescript"
|
|
650
|
+
import {
|
|
651
|
+
defaultLocale,
|
|
652
|
+
getMultilingualUrls,
|
|
653
|
+
getPathWithoutLocale,
|
|
654
|
+
} from "intlayer";
|
|
655
|
+
import { type Component, For } from "solid-js";
|
|
656
|
+
|
|
657
|
+
export type AlternateLinksProps = {
|
|
658
|
+
/** URL absolue de la page en cours de rendu. */
|
|
659
|
+
url: string;
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
export const AlternateLinks: Component<AlternateLinksProps> = (props) => {
|
|
663
|
+
const multilingualUrls = () => {
|
|
664
|
+
const { origin, pathname } = new URL(props.url);
|
|
665
|
+
|
|
666
|
+
return Object.entries(
|
|
667
|
+
getMultilingualUrls(`${origin}${getPathWithoutLocale(pathname)}`)
|
|
668
|
+
);
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
const canonicalUrl = () =>
|
|
672
|
+
new URL(props.url).origin + new URL(props.url).pathname;
|
|
673
|
+
|
|
674
|
+
return (
|
|
675
|
+
<>
|
|
676
|
+
<link href={canonicalUrl()} rel="canonical" />
|
|
677
|
+
<For each={multilingualUrls()}>
|
|
678
|
+
{([locale, localizedUrl]) => (
|
|
679
|
+
<link href={localizedUrl} hreflang={locale} rel="alternate" />
|
|
680
|
+
)}
|
|
681
|
+
</For>
|
|
682
|
+
<link
|
|
683
|
+
href={
|
|
684
|
+
multilingualUrls().find(([locale]) => locale === defaultLocale)?.[1]
|
|
685
|
+
}
|
|
686
|
+
hreflang="x-default"
|
|
687
|
+
rel="alternate"
|
|
688
|
+
/>
|
|
689
|
+
</>
|
|
690
|
+
);
|
|
691
|
+
};
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
Rendez-le dans l'en-tête du document, où l'URL de la requête est disponible :
|
|
695
|
+
|
|
696
|
+
```tsx fileName="src/entry-server.tsx" codeFormat="typescript"
|
|
697
|
+
import { AlternateLinks } from "~/components/AlternateLinks";
|
|
698
|
+
|
|
699
|
+
// … à l'intérieur de <head>, à côté des autres balises meta :
|
|
700
|
+
<AlternateLinks url={url} />;
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
`GET /fr/about` sert alors :
|
|
704
|
+
|
|
705
|
+
```html
|
|
706
|
+
<link href="https://example.com/fr/about" rel="canonical" />
|
|
707
|
+
<link href="https://example.com/about" hreflang="en" rel="alternate" />
|
|
708
|
+
<link href="https://example.com/fr/about" hreflang="fr" rel="alternate" />
|
|
709
|
+
<link href="https://example.com/es/about" hreflang="es" rel="alternate" />
|
|
710
|
+
<link href="https://example.com/about" hreflang="x-default" rel="alternate" />
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
> **Note sur `@solidjs/meta`** : au moment d'écrire ces lignes, `<Title>` et `<Meta>` de `@solidjs/meta` sont appliqués sur le client après l'hydratation mais ne sont **pas** émis dans le `<head>` rendu côté serveur dans SolidStart v2. En attendant que cela soit corrigé en amont, rendez les balises que les robots doivent voir sans JavaScript — `canonical`, `hreflang`, et si nécessaire `title` / `description` — directement dans `entry-server.tsx`, comme montré ci-dessus.
|
|
714
|
+
|
|
715
|
+
</Step>
|
|
716
|
+
|
|
717
|
+
<Step number={12} title="Gérer les pages non trouvées" isOptional={true}>
|
|
718
|
+
|
|
719
|
+
Une route splat à la racine de `src/routes` intercepte tous les chemins que le segment de locale n'a pas fait correspondre — y compris les préfixes de locale invalides rejetés par `matchFilters`. Parce que la locale provient toujours de l'URL à travers le layout racine, la page 404 est affichée dans la langue du visiteur :
|
|
720
|
+
|
|
721
|
+
```tsx fileName="src/routes/[...404].tsx" codeFormat="typescript"
|
|
722
|
+
import { Title } from "@solidjs/meta";
|
|
723
|
+
import { HttpStatusCode } from "@solidjs/start";
|
|
724
|
+
import { useIntlayer } from "solid-intlayer";
|
|
725
|
+
import { LocalizedLink } from "~/components/LocalizedLink";
|
|
726
|
+
|
|
727
|
+
export default function NotFound() {
|
|
728
|
+
const content = useIntlayer("not-found-page");
|
|
729
|
+
|
|
730
|
+
return (
|
|
731
|
+
<main>
|
|
732
|
+
<Title>{content.metaTitle.value}</Title>
|
|
733
|
+
<HttpStatusCode code={404} />
|
|
734
|
+
<h1>{content.title}</h1>
|
|
735
|
+
<LocalizedLink href="/">{content.backHome}</LocalizedLink>
|
|
736
|
+
</main>
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
| Requête | Résultat |
|
|
742
|
+
| ----------------- | -------------------------------------------- |
|
|
743
|
+
| `/xx` | `404` — `xx` n'est pas une locale configurée |
|
|
744
|
+
| `/nonexistent` | `404` dans la locale par défaut |
|
|
745
|
+
| `/fr/nonexistent` | `404` en français (`Page introuvable`) |
|
|
746
|
+
|
|
747
|
+
</Step>
|
|
748
|
+
|
|
749
|
+
<Step number={13} title="Générer un sitemap multilingue" isOptional={true}>
|
|
750
|
+
|
|
751
|
+
Le générateurs de sitemap d'Intlayer étend chaque chemin en une entrée par locale et câble les alternatives `xhtml:link` entre elles, de sorte que la route n'a qu'à lister les chemins canoniques sans locale.
|
|
752
|
+
|
|
753
|
+
> Contrairement aux générateurs de base qui n'émettent que des URL plates, Intlayer câble des liens bidirectionnels entre chaque variante localisée de chaque page, ce qui aide les moteurs de recherche à relier les URL localisées et à servir la bonne au bon public.
|
|
754
|
+
|
|
755
|
+
SolidStart transforme un fichier exportant une méthode HTTP en route d'API, et supprime l'extension `.ts` du chemin — ainsi `src/routes/sitemap.xml.ts` est servi sur `/sitemap.xml` :
|
|
756
|
+
|
|
757
|
+
```typescript fileName="src/routes/sitemap.xml.ts" codeFormat={["typescript", "esm", "commonjs"]}
|
|
758
|
+
import type { APIEvent } from "@solidjs/start/server";
|
|
759
|
+
import { generateSitemap } from "intlayer";
|
|
760
|
+
|
|
761
|
+
const SITE_URL = process.env.SITE_URL ?? "http://localhost:3000";
|
|
762
|
+
|
|
763
|
+
export const GET = (_event: APIEvent) => {
|
|
764
|
+
const sitemap = generateSitemap(
|
|
765
|
+
[
|
|
766
|
+
{ path: "/", changefreq: "daily", priority: 1.0 },
|
|
767
|
+
{ path: "/about", changefreq: "monthly", priority: 0.8 },
|
|
768
|
+
],
|
|
769
|
+
{ siteUrl: SITE_URL }
|
|
770
|
+
);
|
|
771
|
+
|
|
772
|
+
return new Response(sitemap, {
|
|
773
|
+
headers: { "Content-Type": "application/xml" },
|
|
774
|
+
});
|
|
775
|
+
};
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
```xml fileName="sortie de GET /sitemap.xml"
|
|
779
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
780
|
+
<urlset
|
|
781
|
+
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
782
|
+
xmlns:xhtml="http://www.w3.org/1999/xhtml"
|
|
783
|
+
>
|
|
784
|
+
<url>
|
|
785
|
+
<loc>https://example.com/about</loc>
|
|
786
|
+
<changefreq>monthly</changefreq>
|
|
787
|
+
<priority>0.8</priority>
|
|
788
|
+
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/about"/>
|
|
789
|
+
<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/about"/>
|
|
790
|
+
<xhtml:link rel="alternate" hreflang="es" href="https://example.com/es/about"/>
|
|
791
|
+
<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/about"/>
|
|
792
|
+
</url>
|
|
793
|
+
</urlset>
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
> Les routes d'API ne prennent pas en charge les paramètres optionnels, conservez donc ce fichier à la racine de `src/routes`, en dehors du segment `[[locale]]`. Le sitemap contient déjà chaque locale.
|
|
797
|
+
|
|
798
|
+
Vous pouvez construire un `robots.txt` de la même manière avec `getMultilingualUrls`, de sorte que les entrées `Disallow` couvraient chaque orthographe localisée d'un chemin sensible :
|
|
799
|
+
|
|
800
|
+
```typescript fileName="src/routes/robots.txt.ts" codeFormat={["typescript", "esm", "commonjs"]}
|
|
801
|
+
import { getMultilingualUrls } from "intlayer";
|
|
802
|
+
|
|
803
|
+
const SITE_URL = process.env.SITE_URL ?? "http://localhost:3000";
|
|
804
|
+
|
|
805
|
+
const disallowedPaths = ["/admin", "/private"].flatMap((path) =>
|
|
806
|
+
Object.values(getMultilingualUrls(path))
|
|
807
|
+
);
|
|
808
|
+
|
|
809
|
+
export const GET = () =>
|
|
810
|
+
new Response(
|
|
811
|
+
[
|
|
812
|
+
"User-agent: *",
|
|
813
|
+
"Allow: /",
|
|
814
|
+
...disallowedPaths.map((path) => `Disallow: ${path}`),
|
|
815
|
+
"",
|
|
816
|
+
`Sitemap: ${SITE_URL}/sitemap.xml`,
|
|
817
|
+
].join("\n"),
|
|
818
|
+
{ headers: { "Content-Type": "text/plain" } }
|
|
819
|
+
);
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
</Step>
|
|
823
|
+
|
|
824
|
+
<Step number={14} title="Récupérer la locale dans vos fonctions serveur" isOptional={true}>
|
|
825
|
+
|
|
826
|
+
Vous souhaiterez peut-être accéder à la locale actuelle depuis une fonction serveur ou une route d'API.
|
|
827
|
+
|
|
828
|
+
Dans une configuration basée sur des préfixes comme celle-ci, **l'URL fait foi** : `getLocaleFromPath` lit le préfixe depuis l'URL de la requête. `getLocale` est la solution de repli pour les requêtes qui ne portent pas de préfixe de locale — elle inspecte le cookie `INTLAYER_LOCALE`, puis l'en-tête `x-intlayer-locale`, puis négocie `Accept-Language`.
|
|
829
|
+
|
|
830
|
+
```tsx fileName="src/routes/[[locale]]/index.tsx" codeFormat="typescript"
|
|
831
|
+
import { createAsync } from "@solidjs/router";
|
|
832
|
+
import { getCookie, getIntlayer, getLocale, getLocaleFromPath } from "intlayer";
|
|
833
|
+
import { getRequestEvent } from "solid-js/web";
|
|
834
|
+
|
|
835
|
+
const loadLocalizedData = async () => {
|
|
836
|
+
"use server";
|
|
837
|
+
|
|
838
|
+
const request = getRequestEvent()?.request;
|
|
839
|
+
|
|
840
|
+
const locale =
|
|
841
|
+
getLocaleFromPath(request?.url) ??
|
|
842
|
+
(await getLocale({
|
|
843
|
+
// Récupérer le cookie depuis la requête (par défaut : 'INTLAYER_LOCALE')
|
|
844
|
+
getCookie: (name) =>
|
|
845
|
+
getCookie(name, request?.headers.get("cookie") ?? ""),
|
|
846
|
+
// Récupérer l'en-tête depuis la requête (par défaut : 'x-intlayer-locale'),
|
|
847
|
+
// avec repli sur la négociation Accept-Language
|
|
848
|
+
getHeader: (name) => request?.headers.get(name) ?? undefined,
|
|
849
|
+
}));
|
|
850
|
+
|
|
851
|
+
// Récupérer du contenu en dehors d'un composant en utilisant getIntlayer()
|
|
852
|
+
const content = getIntlayer("home-page", locale);
|
|
853
|
+
|
|
854
|
+
return { locale, title: String(content.title) };
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
export default function Page() {
|
|
858
|
+
const data = createAsync(() => loadLocalizedData());
|
|
859
|
+
|
|
860
|
+
return <p>{data()?.title}</p>;
|
|
861
|
+
}
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
> Ne vous fiez pas uniquement à `getLocale` ici : le cookie de locale n'est écrit qu'une fois qu'un visiteur change activement de langue, donc une première visite sur `/fr/...` serait résolue avec la locale par défaut.
|
|
865
|
+
|
|
866
|
+
</Step>
|
|
867
|
+
|
|
868
|
+
<Step number={15} title="Extraire le contenu de vos composants" isOptional={true}>
|
|
869
|
+
|
|
870
|
+
Si vous avez une base de code existante, transformer des milliers de fichiers peut prendre du temps.
|
|
871
|
+
|
|
872
|
+
Pour faciliter ce processus, Intlayer propose un [compilateur](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/compiler.md) / [extracteur](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/cli/extract.md) pour transformer vos composants et en extraire le contenu.
|
|
873
|
+
|
|
874
|
+
Pour le configurer, vous pouvez ajouter une section `compiler` dans votre fichier `intlayer.config.ts` :
|
|
875
|
+
|
|
876
|
+
```typescript fileName="intlayer.config.ts" codeFormat={["typescript", "esm", "commonjs"]}
|
|
877
|
+
import { type IntlayerConfig } from "intlayer";
|
|
878
|
+
|
|
879
|
+
const config: IntlayerConfig = {
|
|
880
|
+
// ... Reste de votre configuration
|
|
881
|
+
compiler: {
|
|
882
|
+
/**
|
|
883
|
+
* Indique si le compilateur doit être activé.
|
|
884
|
+
*/
|
|
885
|
+
enabled: true,
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Définit le chemin des fichiers de sortie
|
|
889
|
+
*/
|
|
890
|
+
output: ({ fileName, extension }) => `./${fileName}${extension}`,
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* Indique si les composants doivent être enregistrés après avoir été transformés.
|
|
894
|
+
*
|
|
895
|
+
* - Si `true`, le compilateur réécrira le fichier du composant sur le disque. La transformation sera donc permanente et le compilateur ignorera la transformation lors du processus suivant. De cette façon, le compilateur peut transformer l'application, puis être retiré.
|
|
896
|
+
*
|
|
897
|
+
* - Si `false`, le compilateur injectera l'appel de fonction `useIntlayer()` dans le code dans le résultat du build uniquement, et gardera la base de code intacte. La transformation sera effectuée uniquement en mémoire.
|
|
898
|
+
*/
|
|
899
|
+
saveComponents: false,
|
|
900
|
+
|
|
901
|
+
/**
|
|
902
|
+
* Préfixe de clé de dictionnaire
|
|
903
|
+
*/
|
|
904
|
+
dictionaryKeyPrefix: "",
|
|
905
|
+
},
|
|
906
|
+
};
|
|
907
|
+
|
|
908
|
+
export default config;
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
<Tabs>
|
|
912
|
+
<Tab value="Commande d'extraction">
|
|
913
|
+
|
|
914
|
+
Exécutez l'extracteur pour transformer vos composants et extraire le contenu
|
|
915
|
+
|
|
916
|
+
```bash packageManager="npm"
|
|
917
|
+
npx intlayer extract
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
```bash packageManager="pnpm"
|
|
921
|
+
pnpm intlayer extract
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
```bash packageManager="yarn"
|
|
925
|
+
yarn intlayer extract
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
```bash packageManager="bun"
|
|
929
|
+
bun x intlayer extract
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
> Déplacez ensuite les fichiers de contenu générés de vos pages hors de `src/routes`, pour la raison expliquée à l'étape 5.
|
|
933
|
+
|
|
934
|
+
</Tab>
|
|
935
|
+
<Tab value="Compilateur Babel">
|
|
936
|
+
|
|
937
|
+
> Depuis la v9, le `intlayerCompiler` est inclus dans le plugin `intlayer`. Vous n'avez donc pas besoin de l'ajouter manuellement.
|
|
938
|
+
|
|
939
|
+
Mettez à jour votre `vite.config.ts` pour inclure le plugin `intlayerCompiler` :
|
|
940
|
+
|
|
941
|
+
```ts fileName="vite.config.ts"
|
|
942
|
+
import { solidStart } from "@solidjs/start/config";
|
|
943
|
+
import { nitro } from "nitro/vite";
|
|
944
|
+
import { defineConfig } from "vite";
|
|
945
|
+
import { intlayer, intlayerCompiler } from "vite-intlayer";
|
|
946
|
+
|
|
947
|
+
export default defineConfig({
|
|
948
|
+
plugins: [
|
|
949
|
+
solidStart({ middleware: "src/middleware.ts" }),
|
|
950
|
+
nitro(),
|
|
951
|
+
intlayer(),
|
|
952
|
+
intlayerCompiler(), // Ajoute le plugin de compilateur
|
|
953
|
+
],
|
|
954
|
+
});
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
```bash packageManager="npm"
|
|
958
|
+
npm run build # Ou npm run dev
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
```bash packageManager="pnpm"
|
|
962
|
+
pnpm run build # Ou pnpm run dev
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
```bash packageManager="yarn"
|
|
966
|
+
yarn build # Ou yarn dev
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
```bash packageManager="bun"
|
|
970
|
+
bun run build # Ou bun run dev
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
</Tab>
|
|
974
|
+
</Tabs>
|
|
975
|
+
|
|
976
|
+
</Step>
|
|
977
|
+
|
|
978
|
+
<Step number={16} title="Configurer TypeScript">
|
|
979
|
+
|
|
980
|
+
Intlayer utilise l'augmentation de module pour bénéficier des avantages de TypeScript et rendre votre base de code plus solide.
|
|
981
|
+
|
|
982
|
+
Assurez-vous que votre configuration TypeScript inclut les types générés automatiquement :
|
|
983
|
+
|
|
984
|
+
```json5 fileName="tsconfig.json"
|
|
985
|
+
{
|
|
986
|
+
compilerOptions: {
|
|
987
|
+
// ... vos configurations existantes
|
|
988
|
+
},
|
|
989
|
+
include: [
|
|
990
|
+
"src",
|
|
991
|
+
"*.ts",
|
|
992
|
+
".intlayer/**/*.ts", // Inclure les types générés automatiquement
|
|
993
|
+
],
|
|
994
|
+
}
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
Les clés de dictionnaire et les chemins de contenu sont désormais vérifiés au moment de la compilation :
|
|
998
|
+
|
|
999
|
+
```tsx
|
|
1000
|
+
useIntlayer("home-page"); // ✅
|
|
1001
|
+
useIntlayer("hom-page"); // ❌ Argument of type '"hom-page"' is not assignable to parameter of type 'keyof __DictionaryRegistry'
|
|
1002
|
+
```
|
|
1003
|
+
|
|
1004
|
+
</Step>
|
|
1005
|
+
|
|
1006
|
+
</Steps>
|
|
1007
|
+
|
|
1008
|
+
---
|
|
1009
|
+
|
|
1010
|
+
## Vérification de votre configuration
|
|
1011
|
+
|
|
1012
|
+
Construisez et démarrez le serveur, puis vérifiez que ces requêtes se comportent comme prévu :
|
|
1013
|
+
|
|
1014
|
+
```bash
|
|
1015
|
+
npm run build
|
|
1016
|
+
node .output/server/index.mjs
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
| Requête | Réponse attendue |
|
|
1020
|
+
| ---------------------------------------- | ---------------------------------------- |
|
|
1021
|
+
| `GET /` | `200` — Anglais |
|
|
1022
|
+
| `GET /` avec `Accept-Language: fr` | `302` → `/fr` |
|
|
1023
|
+
| `GET /` avec cookie `INTLAYER_LOCALE=es` | `302` → `/es` |
|
|
1024
|
+
| `GET /fr` | `200` — Français, `<html lang="fr">` |
|
|
1025
|
+
| `GET /fr/about` | `200` — Page à propos en français |
|
|
1026
|
+
| `GET /en/about` | `302` → `/about` (redirection canonique) |
|
|
1027
|
+
| `GET /xx` | `404` |
|
|
1028
|
+
| `GET /fr/nonexistent` | `404` en français |
|
|
1029
|
+
| `GET /sitemap.xml` | `200` — Sitemap XML multilingue |
|
|
1030
|
+
|
|
1031
|
+
Les lignes qui rendent une page se comportent à l'identique sous `vite dev`. Les trois lignes de redirection s'appliquent uniquement à un serveur construit, sauf si vous enregistrez vous-même le gestionnaire comme middleware — voir l'étape 3.
|
|
1032
|
+
|
|
1033
|
+
> Exécutez le serveur dev sur Node (`vite dev`) plutôt que sur Bun (`bun --bun vite dev`) : le SSR de SolidStart échoue actuellement sous le runtime Bun avec `Expected a Response object, but received 'NodeResponse'`. Ceci n'a aucun lien avec Intlayer — cela se reproduit sur le modèle de base — et n'affecte que le serveur dev, pas `vite build`.
|
|
1034
|
+
|
|
1035
|
+
---
|
|
1036
|
+
|
|
1037
|
+
## Configuration Git
|
|
1038
|
+
|
|
1039
|
+
Il est recommandé d'ignorer les fichiers générés par Intlayer. Cela vous permet d'éviter de les commiter dans votre dépôt Git.
|
|
1040
|
+
|
|
1041
|
+
Pour ce faire, vous pouvez ajouter les instructions suivantes à votre fichier `.gitignore` :
|
|
1042
|
+
|
|
1043
|
+
```plaintext fileName=".gitignore"
|
|
1044
|
+
# Ignorer les fichiers générés par Intlayer
|
|
1045
|
+
.intlayer
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
---
|
|
1049
|
+
|
|
1050
|
+
## Extension VS Code
|
|
1051
|
+
|
|
1052
|
+
Pour améliorer votre expérience de développement avec Intlayer, vous pouvez installer l'**extension VS Code officielle Intlayer**.
|
|
1053
|
+
|
|
1054
|
+
[Installer depuis le VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=intlayer.intlayer-vs-code-extension)
|
|
1055
|
+
|
|
1056
|
+
Cette extension fournit :
|
|
1057
|
+
|
|
1058
|
+
- **L'autocomplétion** pour les clés de traduction.
|
|
1059
|
+
- **La détection d'erreurs en temps réel** pour les traductions manquantes.
|
|
1060
|
+
- **Aperçus en ligne** du contenu traduit.
|
|
1061
|
+
- **Actions rapides** pour créer et mettre à jour facilement les traductions.
|
|
1062
|
+
|
|
1063
|
+
---
|
|
1064
|
+
|
|
1065
|
+
## Pour aller plus loin
|
|
1066
|
+
|
|
1067
|
+
Pour aller plus loin, vous pouvez implémenter l'[éditeur visuel](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/intlayer_visual_editor.md) ou externaliser votre contenu à l'aide du [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/intlayer_CMS.md).
|
|
1068
|
+
|
|
1069
|
+
---
|
|
1070
|
+
|
|
1071
|
+
## Références de documentation
|
|
1072
|
+
|
|
1073
|
+
- [Documentation Intlayer](https://intlayer.org)
|
|
1074
|
+
- [Documentation SolidStart](https://start.solidjs.com)
|
|
1075
|
+
- [Hook useIntlayer](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/packages/solid-intlayer/useIntlayer.md)
|
|
1076
|
+
- [Hook useLocale](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/packages/solid-intlayer/useLocale.md)
|
|
1077
|
+
- [Déclaration de contenu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/dictionary/content_file.md)
|
|
1078
|
+
- [Configuration](https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/configuration.md)
|