@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 - アプリを翻訳する完全ガイド"
|
|
5
|
+
description: "i18nextはもう不要。2026年に多言語(i18n)SolidStartアプリを構築するためのガイド。サーバーレンダリングされたロケールルーティング、hreflang、サイトマップ、AI支援翻訳。"
|
|
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: "Initial history"
|
|
25
|
+
author: aymericzip
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# Intlayer を使用して SolidStart Web サイトを翻訳する | 国際化 (i18n)
|
|
29
|
+
|
|
30
|
+
<Tabs defaultTab="video">
|
|
31
|
+
<Tab label="動画" value="video">
|
|
32
|
+
|
|
33
|
+
<iframe title="ViteとSolidに最適なi18nソリューション?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="コード" 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="Demo CodeSandbox - 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
|
+
## 目次
|
|
50
|
+
|
|
51
|
+
<TOC/>
|
|
52
|
+
|
|
53
|
+
このガイドでは、**サーバーレンダリング**された SolidStart アプリケーションを扱います。ロケール検出はリクエスト時に行われ、ページは正しい言語でサーバー上にレンダリングされ、検索エンジンが必要とする `<html lang>`、`hreflang`、サイトマップのシグナルはサーバー側で出力されます。
|
|
54
|
+
|
|
55
|
+
## 代替手段ではなく Intlayer を選ぶ理由
|
|
56
|
+
|
|
57
|
+
`@solid-primitives/i18n` や `i18next` などの主要なソリューションと比較して、Intlayer は次のような統合された最適化を備えたソリューションです。
|
|
58
|
+
|
|
59
|
+
<AccordionGroup>
|
|
60
|
+
|
|
61
|
+
<Accordion header="Solid の完全なサポート">
|
|
62
|
+
|
|
63
|
+
Intlayer は、**コンポーネントレベルのコンテンツスコープ**、**リアクティブな翻訳**、および国際化 (i18n) の拡張に必要なすべての機能を提供することで、Solid と完全に連携するように最適化されています。
|
|
64
|
+
|
|
65
|
+
</Accordion>
|
|
66
|
+
|
|
67
|
+
<Accordion header="バンドルサイズ">
|
|
68
|
+
|
|
69
|
+
大量の JSON ファイルをページにロードするのではなく、必要なコンテンツのみをロードします。Intlayer は、**バンドルとページのサイズを最大 50% 削減**するのに役立ちます。
|
|
70
|
+
|
|
71
|
+
</Accordion>
|
|
72
|
+
|
|
73
|
+
<Accordion header="保守性">
|
|
74
|
+
|
|
75
|
+
アプリケーションのコンテンツのスコープを設定すると、大規模なアプリケーションの**メンテナンスが容易になります**。コンテンツコードベース全体を確認するという精神的な負担を負うことなく、単一の機能フォルダを複製または削除できます。さらに、Intlayer は**完全に型指定**されており、コンテンツの正確性を保証します。
|
|
76
|
+
|
|
77
|
+
</Accordion>
|
|
78
|
+
|
|
79
|
+
<Accordion header="AI エージェント">
|
|
80
|
+
|
|
81
|
+
コンテンツを同じ場所に配置すると、大規模言語モデル (LLM) によって**必要なコンテキストが削減**されます。Intlayer には、翻訳の欠落をテストする **CLI**、**[LSP](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/lsp.md)**、**[MCP](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/mcp_server.md)**、**[エージェントスキル](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/agent_skills.md)** などのツールスイートも付属しており、AI エージェントの開発者エクスペリエンス (DX) をさらにスムーズにします。
|
|
82
|
+
|
|
83
|
+
</Accordion>
|
|
84
|
+
|
|
85
|
+
<Accordion header="自動化">
|
|
86
|
+
|
|
87
|
+
AI プロバイダーのコストで、選択した LLM を使用して CI/CD パイプラインで翻訳を自動化します。Intlayer は、コンテンツ抽出を自動化する**コンパイラ**や、**バックグラウンドでの翻訳**を支援する [Web プラットフォーム](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_CMS.md) も提供します。
|
|
88
|
+
|
|
89
|
+
</Accordion>
|
|
90
|
+
|
|
91
|
+
<Accordion header="パフォーマンス">
|
|
92
|
+
|
|
93
|
+
大量の JSON ファイルをコンポーネントに接続すると、パフォーマンスと反応性の問題が発生する可能性があります。Intlayer は、ビルド時のコンテンツ読み込みを最適化します。
|
|
94
|
+
|
|
95
|
+
</Accordion>
|
|
96
|
+
|
|
97
|
+
<Accordion header="開発者以外のメンバーとのスケーリング">
|
|
98
|
+
|
|
99
|
+
単なる i18n ソリューションにとどまらず、Intlayer は**セルフホスト型の[ビジュアルエディタ](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_visual_editor.md)**と**[完全な CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_CMS.md)**を提供し、多言語コンテンツを**リアルタイム**で管理できるようにします。これにより、翻訳者、コピーライター、その他のチームメンバーとのコラボレーションがスムーズになります。コンテンツはローカルおよび/またはリモートに保存できます。
|
|
100
|
+
|
|
101
|
+
</Accordion>
|
|
102
|
+
</AccordionGroup>
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## SolidStart アプリケーションで Intlayer をセットアップするためのステップバイステップガイド
|
|
107
|
+
|
|
108
|
+
<Steps>
|
|
109
|
+
|
|
110
|
+
<Step number={1} title="依存関係のインストール">
|
|
111
|
+
|
|
112
|
+
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
|
+
> `--interactive` フラグはオプションです。AI エージェントの場合は `intlayer-cli init` を使用してください。
|
|
131
|
+
|
|
132
|
+
> このコマンドは環境を検出し、必要なパッケージをインストールします。例:
|
|
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
|
+
設定管理、翻訳、[コンテンツ宣言](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dictionary/content_file.md)、トランスパイル、[CLI コマンド](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/cli/index.md)のための国際化ツールを提供するコアパッケージです。
|
|
153
|
+
|
|
154
|
+
- **solid-intlayer**
|
|
155
|
+
|
|
156
|
+
Intlayer を Solid アプリケーションに統合するパッケージです。Solid の国際化のためのコンテキストプロバイダーとフックを提供します。
|
|
157
|
+
|
|
158
|
+
- **vite-intlayer**
|
|
159
|
+
|
|
160
|
+
Intlayer を [Vite バンドラー](https://vite.dev/guide/why.html#why-bundle-for-production) に統合するための Vite プラグインと、ユーザーの優先ロケールを検出し、Cookie を管理し、URL リダイレクトを処理するロケールルーティングハンドラーが含まれています。
|
|
161
|
+
|
|
162
|
+
> `vite-intlayer` は、単なるビルド時の懸念事項ではなく、サーバー側の懸念事項でもあります。SolidStart の Nitro サーバーが実行するリクエストハンドラーを提供します。`dependencies` に維持するのが安全なデフォルトです。コンパイルされた `.output` ディレクトリをデプロイし、Nitro がハンドラーをインライン化する場合にのみ、`devDependencies` に移動できます。
|
|
163
|
+
|
|
164
|
+
</Step>
|
|
165
|
+
|
|
166
|
+
<Step number={2} title="プロジェクトの設定">
|
|
167
|
+
|
|
168
|
+
アプリケーションの言語を設定するための設定ファイルを作成します:
|
|
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
|
+
// その他のロケール
|
|
180
|
+
],
|
|
181
|
+
defaultLocale: Locales.ENGLISH,
|
|
182
|
+
},
|
|
183
|
+
routing: {
|
|
184
|
+
mode: "prefix-no-default",
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export default config;
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`prefix-no-default` を使用すると、デフォルトのロケールはプレフィックスのない URL から提供されます:
|
|
192
|
+
|
|
193
|
+
```plaintext
|
|
194
|
+
/ /about → 英語 (デフォルトロケール)
|
|
195
|
+
/fr /fr/about → フランス語
|
|
196
|
+
/es /es/about → スペイン語
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
> この設定ファイルを使用して、ローカライズされた URL、ミドルウェアのリダイレクト、Cookie 名、コンテンツ宣言の場所と拡張子の設定、コンソールでの Intlayer ログの無効化などを行うことができます。利用可能なパラメータの完全なリストについては、[設定ドキュメント](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/configuration.md)を参照してください。
|
|
200
|
+
|
|
201
|
+
</Step>
|
|
202
|
+
|
|
203
|
+
<Step number={3} title="Vite 設定への Intlayer の統合">
|
|
204
|
+
|
|
205
|
+
Intlayer プラグインを設定に追加します:
|
|
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
|
+
> `intlayer()` Vite プラグインは、コンテンツ宣言ファイルをビルドし、開発モードで監視し、アプリケーション内に Intlayer 環境変数を定義します。また、パフォーマンスを最適化するエイリアスも提供します。
|
|
219
|
+
|
|
220
|
+
### ロケールルーティングはプラグインに付属しています
|
|
221
|
+
|
|
222
|
+
SolidStart は [Nitro](https://nitro.build) 上で動作し、`intlayer()` はロケールルーティングハンドラーを Nitro のサーバーパイプラインに直接登録します(デフォルトで `true` になっている `routing.enableProxy` オプションを介して)。他に接続するものは何もありません。構築されたサーバー上では、すべてのリクエストがルーターに到達する前に検査されます。
|
|
223
|
+
|
|
224
|
+
- ロケールは URL プレフィックス、次に `INTLAYER_LOCALE` Cookie、次に `Accept-Language` ヘッダーから読み取られます。
|
|
225
|
+
- 解決されたロケールがデフォルトのものではない場合、プレフィックスのない URL は対応するローカライズされた URL にリダイレクトされます (`/` → `/fr`)。
|
|
226
|
+
- 冗長なプレフィックスを持つ URL は、正規の形式にリダイレクトされます (`/en/about` → `/about`)。
|
|
227
|
+
- ロケール Cookie はレスポンスに書き戻されます。
|
|
228
|
+
|
|
229
|
+
</Step>
|
|
230
|
+
|
|
231
|
+
<Step number={4} title="コンテンツの宣言">
|
|
232
|
+
|
|
233
|
+
翻訳を保存するためのコンテンツ宣言を作成および管理します:
|
|
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
|
+
> ⚠️ **SolidStart 固有の注意点**: `src/routes` 配下のすべての `.ts` / `.tsx` ファイルはルートになり、`.content.ts` ファイルにはデフォルトのエクスポートがあるため、ページとして検出されてしまいます。**ページ**のコンテンツ宣言はルートディレクトリの外に配置してください (`src/contents/` が適しています)。**コンポーネント**のコンテンツは、`src/components` がファイルシステムルーターによってスキャンされないため、同じ場所に配置したままで問題ありません。
|
|
298
|
+
|
|
299
|
+
> コンテンツ宣言は、`contentDir` ディレクトリ(デフォルトでは `./src`)に含まれ、コンテンツ宣言ファイルの拡張子(デフォルトでは `.content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml}`)と一致していれば、アプリケーション内のどこにでも定義できます。
|
|
300
|
+
>
|
|
301
|
+
> 詳細については、[コンテンツ宣言のドキュメント](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dictionary/content_file.md)を参照してください。
|
|
302
|
+
|
|
303
|
+
</Step>
|
|
304
|
+
|
|
305
|
+
<Step number={5} title="ローカライズされたルーティングの追加">
|
|
306
|
+
|
|
307
|
+
このステップの目標は、各言語に独自の URL を与えることです。これは検索エンジンがインデックスを作成する対象となります。
|
|
308
|
+
|
|
309
|
+
ページを**オプションの動的セグメント**に移動します。SolidStart のファイルシステムルーターでは、`[[locale]]` は `:locale?` パスパターンにコンパイルされます:
|
|
310
|
+
|
|
311
|
+
```plaintext
|
|
312
|
+
src/routes/
|
|
313
|
+
[[locale]].tsx ← セグメントを検証するレイアウト
|
|
314
|
+
[[locale]]/
|
|
315
|
+
index.tsx → / および /fr および /es
|
|
316
|
+
about.tsx → /about および /fr/about および /es/about
|
|
317
|
+
[...404].tsx → その他のすべてをキャッチ
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
レイアウトファイルの唯一の役割は、セグメントを設定されたロケールに制約することです:
|
|
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` は `:locale?` を 2 つのパターン(セグメントありとセグメントなし)に拡張し、降順の特定性でそれらを試行します。`matchFilters` は、機能する設定と混乱を招く設定の差を生み出すものです:
|
|
338
|
+
|
|
339
|
+
| URL | `matchFilters` なし | `matchFilters` あり |
|
|
340
|
+
| ----------- | -------------------------------------------------- | ---------------------------------------------- |
|
|
341
|
+
| `/fr/about` | フランス語の about ページ | フランス語の about ページ |
|
|
342
|
+
| `/about` | About ページ (静的セグメントが優先) | About ページ |
|
|
343
|
+
| `/unknown` | **ホーム ページ**(`locale=unknown` で静かに表示) | 一致なし → キャッチオール 404 にフォールスルー |
|
|
344
|
+
|
|
345
|
+
> `'prefix-all'` ルーティングモードを使用する場合は `[[locale]]` の代わりに `[locale]` (必須) を推奨し、`'no-prefix'` や `'search-params'` の場合はセグメントを完全に削除します。
|
|
346
|
+
|
|
347
|
+
</Step>
|
|
348
|
+
|
|
349
|
+
<Step number={6} title="アプリケーションへのロケールの提供">
|
|
350
|
+
|
|
351
|
+
URL はロケールの唯一の信頼できる情報源です。ミドルウェアはすでにリクエストをローカライズされたパスにリダイレクトしているため、ルートレイアウトでパスを読み取ることで、サーバーレンダリングとクライアントハイドレーションの一致が保たれ、クライアント側のナビゲーションごとに無料でロケールが更新されます。
|
|
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
|
+
// サーバーは entry-server.tsx で <html> をレンダリングします。クライアント側のロケール間
|
|
369
|
+
// ナビゲーションでは、属性自体を更新する必要があります。
|
|
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` はその `locale` プロパティに反応するため、JSX 内でアクセサー呼び出し `locale()` を渡すだけで十分です。Solid はそれをゲッターにコンパイルし、URL が変更されるとツリー全体が新しい言語で再レンダリングされます。
|
|
397
|
+
|
|
398
|
+
</Step>
|
|
399
|
+
|
|
400
|
+
<Step number={7} title="サーバー上での HTML lang および dir 属性の設定">
|
|
401
|
+
|
|
402
|
+
`<html>` エレメントは `Router` の外部にある `entry-server.tsx` によってレンダリングされます。代わりにリクエスト URL からロケールを読み取ります:
|
|
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
|
+
クローラーは最初のバイトで正しい言語を受け取るようになります:
|
|
439
|
+
|
|
440
|
+
```html
|
|
441
|
+
<html dir="ltr" lang="fr"></html>
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
</Step>
|
|
445
|
+
|
|
446
|
+
<Step number={8} title="ページでの Intlayer の活用">
|
|
447
|
+
|
|
448
|
+
アプリケーション全体でコンテンツ辞書にアクセスします:
|
|
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
|
+
> Solid では、`useIntlayer` はリアクティブなコンテンツ(例: `content`)を返します。そのプロパティに直接アクセスできます。
|
|
471
|
+
|
|
472
|
+
> `alt`、`title`、`href`、`aria-label` などの `string` 属性でコンテンツを使用したい場合は、次のように関数の値を使用できます:
|
|
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
|
+
> `useIntlayer` フックの詳細については、[ドキュメント](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/solid-intlayer/useIntlayer.md)を参照してください。
|
|
481
|
+
|
|
482
|
+
コンテンツノードは単純な翻訳に限定されません。例えば、複数形化されたカウンター:
|
|
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()` はアクティブなロケールの `Intl.PluralRules` を介してカテゴリを選択するため、3 つ以上の複数形を持つ言語でも余分なコードなしで動作します。
|
|
525
|
+
|
|
526
|
+
</Step>
|
|
527
|
+
|
|
528
|
+
<Step number={9} title="ローカライズされた Link コンポーネントの作成">
|
|
529
|
+
|
|
530
|
+
内部 URL に現在の言語のプレフィックスを自動的に付与するカスタム `Link` コンポーネントを作成します:
|
|
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
|
+
一度 `href="/about"` と記述するだけで、アクティブなロケールに応じて `/about`、`/fr/about`、または `/es/about` が生成されるようになります。ページ内のどこでも手動でプレフィックスを付ける必要はありません。
|
|
570
|
+
|
|
571
|
+
</Step>
|
|
572
|
+
|
|
573
|
+
<Step number={10} title="ロケールスイッチャーコンポーネントの作成">
|
|
574
|
+
|
|
575
|
+
スイッチャーを `<select>` ではなく**実際のアンカー**としてレンダリングします。現在のページの各言語が新しいタブで開くことができるクロール可能なリンクになり、JavaScript のみのコントロールでは提供できない利点が得られます。
|
|
576
|
+
|
|
577
|
+
`getPathWithoutLocale` は現在のパスからロケールセグメントを取り除き、`getLocalizedUrl` はターゲットロケール用にそれを再構築するため、何もハードコーディングすることなくリンクがルーティングモードに従います。レンダリングされたロケールを変更するのはナビゲーションであり(`[[locale]]` ルートは URL からそれを導出します)、`setLocale` は選択を `INTLAYER_LOCALE` Cookie に保持するため、後でロケールなしの URL を訪問したときに同じ言語に解決されます。
|
|
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
|
+
// 現在表示されているページの正規(ロケールなし)パス
|
|
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
|
+
// 完全一致のみ。デフォルトロケールのリンクがすべてのページでアクティブとして
|
|
613
|
+
// フラグが立てられないようにするため
|
|
614
|
+
end
|
|
615
|
+
href={getLocalizedUrl(pathWithoutLocale(), localeItem)}
|
|
616
|
+
hreflang={localeItem}
|
|
617
|
+
lang={localeItem}
|
|
618
|
+
onClick={() => setLocale(localeItem)}
|
|
619
|
+
// ブラウザの「戻る」ボタンが前のページに戻ることを保証します
|
|
620
|
+
replace
|
|
621
|
+
>
|
|
622
|
+
{/* 独自のロケールでの言語 - 例: Français */}
|
|
623
|
+
{getLocaleName(localeItem)}
|
|
624
|
+
</A>
|
|
625
|
+
)}
|
|
626
|
+
</For>
|
|
627
|
+
</div>
|
|
628
|
+
</div>
|
|
629
|
+
);
|
|
630
|
+
};
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
> Solid では、`useLocale` からの `locale` は**シグナルアクセサー**です。リアクティブに現在の値を読み取るには、`locale()`(括弧付き)を使用します。
|
|
634
|
+
>
|
|
635
|
+
> `getLocaleName(localeItem)` は各言語を独自の言語で表示します(`English / Français / Español`)。2 番目の引数を渡すと、代わりに現在表示されている言語に名前を翻訳します: `getLocaleName(localeItem, locale())` は英語で `English / French / Spanish`、日本語で `英語 / フランス語 / スペイン語` を返します。
|
|
636
|
+
>
|
|
637
|
+
> `<A>` は現在の URL に一致するリンクにすでに `aria-current="page"` を設定しているため、そこに追加するものはありません。`replace` はレンダリングされた属性からルーターによって読み取られます。履歴エントリをプッシュするのではなく置き換えるため、ブラウザの「戻る」ボタンは前の言語の同じページではなく、切り替え前に訪問したページに戻ります。
|
|
638
|
+
>
|
|
639
|
+
> 各リンクの `dir` と `hreflang` は、右から左への言語名を正しく配置し、支援技術やクローラーに各リンクがどの言語を指しているかを伝えます。
|
|
640
|
+
>
|
|
641
|
+
> `useLocale` フックの詳細については、[ドキュメント](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/solid-intlayer/useLocale.md)を参照してください。
|
|
642
|
+
|
|
643
|
+
</Step>
|
|
644
|
+
|
|
645
|
+
<Step number={11} title="canonical および hreflang リンクの出力" isOptional={true}>
|
|
646
|
+
|
|
647
|
+
`hreflang` アノテーションは、`/about`、`/fr/about`、`/es/about` が異なる言語での同じページであることを検索エンジンに伝えます。`getMultilingualUrls` はルーティングモードに従って、正規(ロケールなし)のパスからそれらを導出するため、何もハードコーディングされません:
|
|
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。 */
|
|
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
|
+
これをドキュメントの head(リクエスト URL が利用可能な場所)にレンダリングします:
|
|
695
|
+
|
|
696
|
+
```tsx fileName="src/entry-server.tsx" codeFormat="typescript"
|
|
697
|
+
import { AlternateLinks } from "~/components/AlternateLinks";
|
|
698
|
+
|
|
699
|
+
// … <head> 内、他の meta タグの隣:
|
|
700
|
+
<AlternateLinks url={url} />;
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
`GET /fr/about` は以下を出力します:
|
|
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
|
+
> **`@solidjs/meta` に関する注意**: 執筆時点では、`@solidjs/meta` の `<Title>` と `<Meta>` はハイドレーション後にクライアントに適用されますが、SolidStart v2 のサーバーレンダリングされた `<head>` には**出力されません**。目が離せない修正がアップストリームで適用されるまでは、クローラーが JavaScript なしで表示する必要があるタグ(`canonical`、`hreflang`、必要に応じて `title` / `description`)を、上記のように `entry-server.tsx` に直接レンダリングしてください。
|
|
714
|
+
|
|
715
|
+
</Step>
|
|
716
|
+
|
|
717
|
+
<Step number={12} title="404 ページの管理" isOptional={true}>
|
|
718
|
+
|
|
719
|
+
`src/routes` のルートにあるスプラットルートは、ロケールセグメントに一致しなかったすべてのパスをキャッチします(`matchFilters` によって拒否された無効なロケールプレフィックスを含む)。ロケールはルートレイアウトを通じて URL から取得されるため、404 ページは訪問者の言語で表示されます:
|
|
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
|
+
| リクエスト | 結果 |
|
|
742
|
+
| ----------------- | ----------------------------------------------- |
|
|
743
|
+
| `/xx` | `404` — `xx` は設定されたロケールではありません |
|
|
744
|
+
| `/nonexistent` | デフォルトロケールでの `404` |
|
|
745
|
+
| `/fr/nonexistent` | フランス語での `404` (`Page introuvable`) |
|
|
746
|
+
|
|
747
|
+
</Step>
|
|
748
|
+
|
|
749
|
+
<Step number={13} title="多言語サイトマップの生成" isOptional={true}>
|
|
750
|
+
|
|
751
|
+
Intlayer のサイトマップジェネレーターは、各パスをロケールごとに 1 つのエントリに拡張し、それらの間に `xhtml:link` の代替を接続するため、ルートは正規のロケールなしパスをリストするだけで済みます。
|
|
752
|
+
|
|
753
|
+
> フラットな URL のみを出力する基本的なジェネレーターとは異なり、Intlayer は各ページのローカライズされたバリアント間に双方向リンクを接続します。これにより、検索エンジンがローカライズされた URL を関連付け、適切なユーザーに適切な URL を提供するのに役立ちます。
|
|
754
|
+
|
|
755
|
+
SolidStart は、HTTP メソッドをエクスポートするファイルを API ルートに変換し、パスから `.ts` 拡張子を削除します。そのため、`src/routes/sitemap.xml.ts` は `/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="output of 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
|
+
> API ルートはオプションのパラメータをサポートしていないため、このファイルは `src/routes` のルート、`[[locale]]` セグメントの外側に保持してください。サイトマップにはすでにすべてのロケールが含まれています。
|
|
797
|
+
|
|
798
|
+
`getMultilingualUrls` を使用して同じ方法で `robots.txt` を構築し、`Disallow` エントリが機密パスのローカライズされた表記すべてをカバーするようにすることができます:
|
|
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="サーバー関数でのロケールの取得" isOptional={true}>
|
|
825
|
+
|
|
826
|
+
サーバー関数または API ルートの内部から現在のロケールにアクセスしたい場合があります。
|
|
827
|
+
|
|
828
|
+
このようなプレフィックスベースの設定では、**URL が決定権を持ちます**: `getLocaleFromPath` はリクエスト URL からプレフィックスを読み取ります。`getLocale` はロケールプレフィックスを持たないリクエストのフォールバックです。`INTLAYER_LOCALE` Cookie を調べ、次に `x-intlayer-locale` ヘッダーを調べ、`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
|
+
// リクエストから Cookie を取得(デフォルト: 'INTLAYER_LOCALE')
|
|
844
|
+
getCookie: (name) =>
|
|
845
|
+
getCookie(name, request?.headers.get("cookie") ?? ""),
|
|
846
|
+
// リクエストからヘッダーを取得(デフォルト: 'x-intlayer-locale')、
|
|
847
|
+
// Accept-Language の交渉にフォールバック
|
|
848
|
+
getHeader: (name) => request?.headers.get(name) ?? undefined,
|
|
849
|
+
}));
|
|
850
|
+
|
|
851
|
+
// 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
|
+
> ここで `getLocale` だけに頼らないでください。ロケール Cookie は訪問者が積極的に言語を切り替えたときにのみ書き込まれるため、`/fr/...` への初回訪問はデフォルトロケールに解決されてしまいます。
|
|
865
|
+
|
|
866
|
+
</Step>
|
|
867
|
+
|
|
868
|
+
<Step number={15} title="コンポーネントのコンテンツの抽出" isOptional={true}>
|
|
869
|
+
|
|
870
|
+
既存のコードベースがある場合、何千ものファイルを変換するには時間がかかることがあります。
|
|
871
|
+
|
|
872
|
+
このプロセスを簡素化するために、Intlayer はコンポーネントを変換してコンテンツを抽出するための [コンパイラ](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/compiler.md) / [エクストラクター](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/cli/extract.md) を提案しています。
|
|
873
|
+
|
|
874
|
+
設定するには、`intlayer.config.ts` ファイルに `compiler` セクションを追加します:
|
|
875
|
+
|
|
876
|
+
```typescript fileName="intlayer.config.ts" codeFormat={["typescript", "esm", "commonjs"]}
|
|
877
|
+
import { type IntlayerConfig } from "intlayer";
|
|
878
|
+
|
|
879
|
+
const config: IntlayerConfig = {
|
|
880
|
+
// ... 設定の残りの部分
|
|
881
|
+
compiler: {
|
|
882
|
+
/**
|
|
883
|
+
* コンパイラを有効にするかどうかを示します。
|
|
884
|
+
*/
|
|
885
|
+
enabled: true,
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* 出力ファイルパスを定義します
|
|
889
|
+
*/
|
|
890
|
+
output: ({ fileName, extension }) => `./${fileName}${extension}`,
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* 変換後にコンポーネントを保存するかどうかを示します。
|
|
894
|
+
*
|
|
895
|
+
* - `true` の場合、コンパイラはディスク上のコンポーネントファイルを書き換えます。これにより変換は永久的なものとなり、コンパイラは次のプロセスでの変換をスキップします。これにより、コンパイラはアプリを変換した後、削除できます。
|
|
896
|
+
*
|
|
897
|
+
* - `false` の場合、コンパイラはビルド出力のコードにのみ `useIntlayer()` 関数呼び出しを注入し、ベースコードベースを元のまま維持します。変換はメモリ内でのみ行われます。
|
|
898
|
+
*/
|
|
899
|
+
saveComponents: false,
|
|
900
|
+
|
|
901
|
+
/**
|
|
902
|
+
* 辞書キーのプレフィックス
|
|
903
|
+
*/
|
|
904
|
+
dictionaryKeyPrefix: "",
|
|
905
|
+
},
|
|
906
|
+
};
|
|
907
|
+
|
|
908
|
+
export default config;
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
<Tabs>
|
|
912
|
+
<Tab value='Extract コマンド'>
|
|
913
|
+
|
|
914
|
+
エクストラクターを実行してコンポーネントを変換し、コンテンツを抽出します
|
|
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
|
+
> その後、ステップ 5 で説明した理由により、生成されたページのコンテンツファイルを `src/routes` の外に移動してください。
|
|
933
|
+
|
|
934
|
+
</Tab>
|
|
935
|
+
<Tab value='Babel コンパイラ'>
|
|
936
|
+
|
|
937
|
+
> v9 以降、`intlayerCompiler` は `intlayer` プラグインに含まれています。そのため、手動で追加する必要はありません。
|
|
938
|
+
|
|
939
|
+
`vite.config.ts` を更新して `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(), // コンパイラプラグインを追加
|
|
953
|
+
],
|
|
954
|
+
});
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
```bash packageManager="npm"
|
|
958
|
+
npm run build # または npm run dev
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
```bash packageManager="pnpm"
|
|
962
|
+
pnpm run build # または pnpm run dev
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
```bash packageManager="yarn"
|
|
966
|
+
yarn build # または yarn dev
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
```bash packageManager="bun"
|
|
970
|
+
bun run build # または bun run dev
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
</Tab>
|
|
974
|
+
</Tabs>
|
|
975
|
+
|
|
976
|
+
</Step>
|
|
977
|
+
|
|
978
|
+
<Step number={16} title="TypeScript の設定">
|
|
979
|
+
|
|
980
|
+
Intlayer はモジュール拡張機能を使用して TypeScript のメリットを活かし、コードベースをより堅牢にします。
|
|
981
|
+
|
|
982
|
+
TypeScript の設定に自動生成された型が含まれていることを確認します:
|
|
983
|
+
|
|
984
|
+
```json5 fileName="tsconfig.json"
|
|
985
|
+
{
|
|
986
|
+
compilerOptions: {
|
|
987
|
+
// ... 既存の設定
|
|
988
|
+
},
|
|
989
|
+
include: [
|
|
990
|
+
"src",
|
|
991
|
+
"*.ts",
|
|
992
|
+
".intlayer/**/*.ts", // 自動生成された型を含める
|
|
993
|
+
],
|
|
994
|
+
}
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
辞書キーとコンテンツパスがコンパイル時にチェックされるようになります:
|
|
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
|
+
## 設定の検証
|
|
1011
|
+
|
|
1012
|
+
ビルドしてサーバーを起動し、以下のリクエストが期待通りに動作することを確認します:
|
|
1013
|
+
|
|
1014
|
+
```bash
|
|
1015
|
+
npm run build
|
|
1016
|
+
node .output/server/index.mjs
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
| リクエスト | 期待されるレスポンス |
|
|
1020
|
+
| ------------------------------------------ | -------------------------------------- |
|
|
1021
|
+
| `GET /` | `200` — 英語 |
|
|
1022
|
+
| `GET /` (`Accept-Language: fr` 付き) | `302` → `/fr` |
|
|
1023
|
+
| `GET /` (`INTLAYER_LOCALE=es` Cookie 付き) | `302` → `/es` |
|
|
1024
|
+
| `GET /fr` | `200` — フランス語, `<html lang="fr">` |
|
|
1025
|
+
| `GET /fr/about` | `200` — フランス語の about ページ |
|
|
1026
|
+
| `GET /en/about` | `302` → `/about` (正規リダイレクト) |
|
|
1027
|
+
| `GET /xx` | `404` |
|
|
1028
|
+
| `GET /fr/nonexistent` | `404` (フランス語) |
|
|
1029
|
+
| `GET /sitemap.xml` | `200` — 多言語 XML サイトマップ |
|
|
1030
|
+
|
|
1031
|
+
ページをレンダリングする行は `vite dev` 下でもまったく同じように動作します。3 つのリダイレクト行は、自分でハンドラーをミドルウェアとして登録しない限り、構築されたサーバーにのみ適用されます(ステップ 3 を参照)。
|
|
1032
|
+
|
|
1033
|
+
> デブサーバーは Bun (`bun --bun vite dev`) ではなく Node (`vite dev`) で実行してください。SolidStart の SSR は現在、Bun ランタイム下で `Expected a Response object, but received 'NodeResponse'` で失敗します。これは Intlayer とは無関係で(プレーンなテンプレートでも再現します)、`vite build` ではなく開発サーバーにのみ影響します。
|
|
1034
|
+
|
|
1035
|
+
---
|
|
1036
|
+
|
|
1037
|
+
## Git の設定
|
|
1038
|
+
|
|
1039
|
+
Intlayer によって生成されたファイルを無視することをお勧めします。これにより、それらを Git リポジトリにコミットすることを回避できます。
|
|
1040
|
+
|
|
1041
|
+
これを行うには、`.gitignore` ファイルに次の手順を追加します:
|
|
1042
|
+
|
|
1043
|
+
```plaintext fileName=".gitignore"
|
|
1044
|
+
# Intlayer によって生成されたファイルを無視
|
|
1045
|
+
.intlayer
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
---
|
|
1049
|
+
|
|
1050
|
+
## VS Code 拡張機能
|
|
1051
|
+
|
|
1052
|
+
Intlayer での開発体験を向上させるために、公式の **Intlayer VS Code 拡張機能** をインストールできます。
|
|
1053
|
+
|
|
1054
|
+
[VS Code Marketplace からインストール](https://marketplace.visualstudio.com/items?itemName=intlayer.intlayer-vs-code-extension)
|
|
1055
|
+
|
|
1056
|
+
この拡張機能は以下を提供します:
|
|
1057
|
+
|
|
1058
|
+
- 翻訳キーの **自動補完**。
|
|
1059
|
+
- 欠落している翻訳の **リアルタイムエラー検出**。
|
|
1060
|
+
- 翻訳されたコンテンツの **インラインプレビュー**。
|
|
1061
|
+
- 翻訳を簡単に作成および更新するための **クイックアクション**。
|
|
1062
|
+
|
|
1063
|
+
---
|
|
1064
|
+
|
|
1065
|
+
## さらに進む
|
|
1066
|
+
|
|
1067
|
+
さらに進むには、[ビジュアルエディタ](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_visual_editor.md)を実装するか、[CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_CMS.md)を使用してコンテンツを外部化できます。
|
|
1068
|
+
|
|
1069
|
+
---
|
|
1070
|
+
|
|
1071
|
+
## ドキュメントの参照
|
|
1072
|
+
|
|
1073
|
+
- [Intlayer ドキュメント](https://intlayer.org)
|
|
1074
|
+
- [SolidStart ドキュメント](https://start.solidjs.com)
|
|
1075
|
+
- [useIntlayer フック](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/solid-intlayer/useIntlayer.md)
|
|
1076
|
+
- [useLocale フック](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/solid-intlayer/useLocale.md)
|
|
1077
|
+
- [コンテンツ宣言](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dictionary/content_file.md)
|
|
1078
|
+
- [設定](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/configuration.md)
|