@intlayer/docs 9.1.3 → 9.3.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/index.md +1 -1
- package/blog/ar/rag_powered_documentation_assistant.md +7 -0
- package/blog/de/index.md +1 -1
- package/blog/de/rag_powered_documentation_assistant.md +6 -0
- package/blog/en/index.md +1 -1
- package/blog/en-GB/index.md +1 -1
- package/blog/en-GB/rag_powered_documentation_assistant.md +6 -0
- package/blog/es/index.md +1 -1
- package/blog/es/rag_powered_documentation_assistant.md +7 -0
- package/blog/fr/i18n_meaning.md +7 -1
- package/blog/fr/index.md +1 -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/index.md +1 -1
- 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/index.md +1 -1
- package/blog/id/rag_powered_documentation_assistant.md +6 -0
- package/blog/it/index.md +1 -1
- package/blog/it/rag_powered_documentation_assistant.md +6 -0
- package/blog/ja/index.md +1 -1
- package/blog/ja/rag_powered_documentation_assistant.md +7 -0
- package/blog/ko/index.md +1 -1
- package/blog/ko/list_i18n_technologies/frameworks/react.md +7 -7
- package/blog/ko/rag_powered_documentation_assistant.md +6 -0
- package/blog/pl/index.md +1 -1
- package/blog/pl/rag_powered_documentation_assistant.md +6 -0
- package/blog/pt/index.md +1 -1
- package/blog/pt/rag_powered_documentation_assistant.md +6 -0
- package/blog/ru/index.md +1 -1
- 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/index.md +1 -1
- package/blog/uk/rag_powered_documentation_assistant.md +6 -0
- package/blog/vi/index.md +1 -1
- package/blog/vi/rag_powered_documentation_assistant.md +6 -0
- package/blog/zh/index.md +1 -1
- 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/common.cjs +24 -1
- package/dist/cjs/common.cjs.map +1 -1
- package/dist/cjs/generated/blog.entry.cjs +58 -31
- package/dist/cjs/generated/blog.entry.cjs.map +1 -1
- package/dist/cjs/generated/docs.entry.cjs +265 -218
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/cjs/generated/frequentQuestions.entry.cjs +48 -21
- package/dist/cjs/generated/frequentQuestions.entry.cjs.map +1 -1
- package/dist/cjs/generated/legal.entry.cjs +33 -6
- package/dist/cjs/generated/legal.entry.cjs.map +1 -1
- package/dist/esm/common.mjs +24 -1
- package/dist/esm/common.mjs.map +1 -1
- package/dist/esm/generated/blog.entry.mjs +58 -31
- package/dist/esm/generated/blog.entry.mjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +265 -218
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/esm/generated/frequentQuestions.entry.mjs +48 -21
- package/dist/esm/generated/frequentQuestions.entry.mjs.map +1 -1
- package/dist/esm/generated/legal.entry.mjs +33 -6
- package/dist/esm/generated/legal.entry.mjs.map +1 -1
- package/dist/types/common.d.ts.map +1 -1
- package/dist/types/generated/blog.entry.d.ts.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/dist/types/generated/frequentQuestions.entry.d.ts.map +1 -1
- package/dist/types/generated/legal.entry.d.ts.map +1 -1
- package/docs/ar/analytics.md +222 -0
- package/docs/ar/autoFill.md +28 -9
- package/docs/ar/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -0
- 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/bundle_optimization.md +58 -25
- package/docs/bn/configuration.md +25 -8
- package/docs/bn/intlayer_with_angular_21.md +9 -9
- package/docs/cs/bundle_optimization.md +58 -25
- 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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -0
- 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/bundle_optimization.md +51 -23
- 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/live-sync.md +4 -0
- package/docs/en-GB/analytics.md +222 -0
- package/docs/en-GB/autoFill.md +26 -7
- package/docs/en-GB/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -0
- 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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -0
- 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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -0
- 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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -0
- 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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -0
- 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/bundle_optimization.md +58 -25
- 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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -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/bundle_optimization.md +58 -24
- 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/live-sync.md +4 -0
- 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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -0
- 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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -0
- 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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -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/bundle_optimization.md +58 -25
- 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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -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/bundle_optimization.md +58 -25
- 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/live-sync.md +4 -0
- 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/bundle_optimization.md +58 -25
- package/docs/zh-TW/intlayer_with_angular_21.md +7 -7
- package/package.json +7 -7
- package/src/common.ts +39 -2
- package/src/generated/blog.entry.ts +66 -34
- package/src/generated/docs.entry.ts +273 -221
- package/src/generated/frequentQuestions.entry.ts +56 -24
- package/src/generated/legal.entry.ts +41 -9
|
@@ -0,0 +1,1078 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2025-08-06
|
|
3
|
+
updatedAt: 2026-08-06
|
|
4
|
+
title: "Solid Start i18n - Panduan lengkap menerjemahkan aplikasi Anda"
|
|
5
|
+
description: "Tidak ada lagi i18next. Panduan 2026 untuk membangun aplikasi SolidStart multibahasa (i18n). Pengarahan lokal yang dirender server, hreflang, peta situs, dan terjemahan dibantu 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
|
+
# Terjemahkan situs web SolidStart Anda menggunakan Intlayer | Internasionalisasi (i18n)
|
|
29
|
+
|
|
30
|
+
<Tabs defaultTab="video">
|
|
31
|
+
<Tab label="Video" value="video">
|
|
32
|
+
|
|
33
|
+
<iframe title="Solusi i18n terbaik untuk Vite dan Solid? Temukan 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="Kode" 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 - Cara Menginternasionalisasikan aplikasi Anda menggunakan 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
|
+
## Daftar Isi
|
|
50
|
+
|
|
51
|
+
<TOC/>
|
|
52
|
+
|
|
53
|
+
Panduan ini mencakup aplikasi SolidStart yang **dirender di server**: deteksi lokal terjadi pada permintaan, halaman dirender di server dalam bahasa yang tepat, dan sinyal `<html lang>`, `hreflang`, serta peta situs yang dibutuhkan mesin pencari dipancarkan di sisi server.
|
|
54
|
+
|
|
55
|
+
## Mengapa Intlayer dibandingkan alternatif lain?
|
|
56
|
+
|
|
57
|
+
Dibandingkan dengan solusi utama seperti `@solid-primitives/i18n` atau `i18next`, Intlayer adalah solusi yang dilengkapi dengan optimasi terintegrasi seperti:
|
|
58
|
+
|
|
59
|
+
<AccordionGroup>
|
|
60
|
+
|
|
61
|
+
<Accordion header="Cakupan Solid penuh">
|
|
62
|
+
|
|
63
|
+
Intlayer dioptimalkan untuk bekerja secara sempurna dengan Solid dengan menawarkan **pelingkup konten tingkat komponen**, **terjemahan reaktif**, dan semua fitur yang diperlukan untuk menskalakan internasionalisasi (i18n).
|
|
64
|
+
|
|
65
|
+
</Accordion>
|
|
66
|
+
|
|
67
|
+
<Accordion header="Ukuran bundel">
|
|
68
|
+
|
|
69
|
+
Alih-alih memuat file JSON yang sangat besar ke dalam halaman Anda, muat hanya konten yang diperlukan. Intlayer membantu **mengurangi ukuran bundel dan halaman Anda hingga 50%**.
|
|
70
|
+
|
|
71
|
+
</Accordion>
|
|
72
|
+
|
|
73
|
+
<Accordion header="Kemudahan pemeliharaan">
|
|
74
|
+
|
|
75
|
+
Melingkupi konten aplikasi Anda **memfasilitasi pemeliharaan** untuk aplikasi skala besar. Anda dapat menduplikasi atau menghapus satu folder fitur tanpa beban mental untuk meninjau seluruh basis kode konten Anda. Selain itu, Intlayer **bertipe penuh** untuk memastikan akurasi konten Anda.
|
|
76
|
+
|
|
77
|
+
</Accordion>
|
|
78
|
+
|
|
79
|
+
<Accordion header="Agen AI">
|
|
80
|
+
|
|
81
|
+
Menempatkan konten bersama **mengurangi konteks yang dibutuhkan** oleh Model Bahasa Besar (LLM). Intlayer juga dilengkapi dengan serangkaian alat, seperti **CLI** untuk menguji terjemahan yang hilang, **[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)**, dan **[keterampilan agen](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/agent_skills.md)**, untuk membuat pengalaman pengembang (DX) menjadi lebih lancar bagi agen AI.
|
|
82
|
+
|
|
83
|
+
</Accordion>
|
|
84
|
+
|
|
85
|
+
<Accordion header="Otomatisasi">
|
|
86
|
+
|
|
87
|
+
Gunakan otomatisasi untuk menerjemahkan dalam alur CI/CD Anda menggunakan LLM pilihan Anda dengan biaya penyedia AI Anda. Intlayer juga menawarkan **kompilator** untuk mengotomatiskan ekstraksi konten, serta [platform web](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_CMS.md) untuk membantu **menerjemahkan di latar belakang**.
|
|
88
|
+
|
|
89
|
+
</Accordion>
|
|
90
|
+
|
|
91
|
+
<Accordion header="Performa">
|
|
92
|
+
|
|
93
|
+
Menghubungkan file JSON yang besar ke komponen dapat menyebabkan masalah performa dan reaktivitas. Intlayer mengoptimalkan pemuatan konten Anda pada saat build.
|
|
94
|
+
|
|
95
|
+
</Accordion>
|
|
96
|
+
|
|
97
|
+
<Accordion header="Skalabilitas dengan non-pengembang">
|
|
98
|
+
|
|
99
|
+
Lebih dari sekadar solusi i18n, Intlayer menyediakan **[editor visual](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_visual_editor.md) mandiri** dan **[CMS lengkap](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_CMS.md)** untuk membantu Anda mengelola konten multibahasa Anda secara **real-time**, membuat kolaborasi dengan penerjemah, penulis teks, dan anggota tim lainnya menjadi mulus. Konten dapat disimpan secara lokal dan/atau jarak jauh.
|
|
100
|
+
|
|
101
|
+
</Accordion>
|
|
102
|
+
</AccordionGroup>
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Panduan Langkah demi Langkah untuk Mengatur Intlayer dalam Aplikasi SolidStart
|
|
107
|
+
|
|
108
|
+
<Steps>
|
|
109
|
+
|
|
110
|
+
<Step number={1} title="Install Dependensi">
|
|
111
|
+
|
|
112
|
+
Install paket yang diperlukan menggunakan 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
|
+
> bendera `--interactive` bersifat opsional. Gunakan `intlayer-cli init` jika Anda adalah agen AI.
|
|
131
|
+
|
|
132
|
+
> Perintah ini akan mendeteksi lingkungan Anda dan menginstal paket yang diperlukan. Sebagai contoh:
|
|
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
|
+
Paket inti yang menyediakan alat internasionalisasi untuk manajemen konfigurasi, terjemahan, [deklarasi konten](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dictionary/content_file.md), transpilasi, dan [perintah CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/cli/index.md).
|
|
153
|
+
|
|
154
|
+
- **solid-intlayer**
|
|
155
|
+
|
|
156
|
+
Paket yang mengintegrasikan Intlayer dengan aplikasi Solid. Paket ini menyediakan penyedia konteks dan hook untuk internasionalisasi Solid.
|
|
157
|
+
|
|
158
|
+
- **vite-intlayer**
|
|
159
|
+
|
|
160
|
+
Mencakup plugin Vite untuk mengintegrasikan Intlayer dengan [bundler Vite](https://vite.dev/guide/why.html#why-bundle-for-production), serta penangan pengarahan lokal yang mendeteksi lokal pilihan pengguna, mengelola cookie, dan menangani pengalihan URL.
|
|
161
|
+
|
|
162
|
+
> `vite-intlayer` adalah perhatian sisi server di sini, bukan hanya saat build: ini menyediakan penangan permintaan yang dijalankan oleh server Nitro SolidStart. Menyimpannya dalam `dependencies` adalah pilihan aman secara default — Anda dapat memindahkannya ke `devDependencies` hanya jika Anda menyebarkan direktori `.output` yang dibuat, di mana Nitro menyisipkan penangan tersebut.
|
|
163
|
+
|
|
164
|
+
</Step>
|
|
165
|
+
|
|
166
|
+
<Step number={2} title="Konfigurasi proyek Anda">
|
|
167
|
+
|
|
168
|
+
Buat file konfigurasi untuk mengonfigurasi bahasa aplikasi Anda:
|
|
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
|
+
// Lokal Anda lainnya
|
|
180
|
+
],
|
|
181
|
+
defaultLocale: Locales.ENGLISH,
|
|
182
|
+
},
|
|
183
|
+
routing: {
|
|
184
|
+
mode: "prefix-no-default",
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export default config;
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Dengan `prefix-no-default`, lokal default dilayani dari URL tanpa awalan:
|
|
192
|
+
|
|
193
|
+
```plaintext
|
|
194
|
+
/ /about → Bahasa Inggris (lokal default)
|
|
195
|
+
/fr /fr/about → Bahasa Prancis
|
|
196
|
+
/es /es/about → Bahasa Spanyol
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
> Melalui file konfigurasi ini, Anda dapat mengatur URL terlokalisasi, pengalihan middleware, nama cookie, lokasi dan ekstensi deklarasi konten Anda, menonaktifkan log Intlayer di konsol, dan banyak lagi. Untuk daftar lengkap parameter yang tersedia, lihat [dokumentasi konfigurasi](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/configuration.md).
|
|
200
|
+
|
|
201
|
+
</Step>
|
|
202
|
+
|
|
203
|
+
<Step number={3} title="Integrasikan Intlayer dalam Konfigurasi Vite Anda">
|
|
204
|
+
|
|
205
|
+
Tambahkan plugin Intlayer ke konfigurasi Anda:
|
|
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
|
+
> Plugin Vite `intlayer()` membangun file deklarasi konten Anda, memantaunya dalam mode pengembangan, dan menentukan variabel lingkungan Intlayer di dalam aplikasi. Ini juga menyediakan alias yang mengoptimalkan performa.
|
|
219
|
+
|
|
220
|
+
### Pengarahan lokal hadir bersama plugin
|
|
221
|
+
|
|
222
|
+
SolidStart berjalan di [Nitro](https://nitro.build), dan `intlayer()` mendaftarkan penangan pengarahan lokalnya secara langsung ke dalam alur server Nitro (melalui opsi `routing.enableProxy`, `true` secara default). Tidak ada hal lain yang perlu dihubungkan: pada server yang dibangun, setiap permintaan diperiksa sebelum mencapai router, dan
|
|
223
|
+
|
|
224
|
+
- lokal dibaca dari awalan URL, kemudian cookie `INTLAYER_LOCALE`, kemudian header `Accept-Language`;
|
|
225
|
+
- URL tanpa awalan dialihkan ke rekanannya yang terlokalisasi jika lokal yang diselesaikan bukan lokal default (`/` → `/fr`);
|
|
226
|
+
- URL dengan awalan redundan dialihkan kembali ke bentuk kanonisnya (`/en/about` → `/about`);
|
|
227
|
+
- cookie lokal ditulis kembali pada respons.
|
|
228
|
+
|
|
229
|
+
</Step>
|
|
230
|
+
|
|
231
|
+
<Step number={4} title="Deklarasikan Konten Anda">
|
|
232
|
+
|
|
233
|
+
Buat dan kelola deklarasi konten Anda untuk menyimpan terjemahan:
|
|
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
|
+
> ⚠️ **Catatan khusus SolidStart**: setiap file `.ts` / `.tsx` di bawah `src/routes` menjadi rute, dan file `.content.ts` memiliki ekspor default, sehingga akan diambil sebagai halaman. Simpan deklarasi konten **halaman** Anda di luar direktori routes (`src/contents/` bekerja dengan baik). Konten **komponen** dapat tetap ditempatkan bersama, karena `src/components` tidak dipindai oleh router sistem file.
|
|
298
|
+
|
|
299
|
+
> Deklarasi konten Anda dapat ditentukan di mana saja dalam aplikasi Anda selama disertakan dalam direktori `contentDir` (secara default, `./src`), dan cocok dengan ekstensi file deklarasi konten (secara default, `.content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml}`).
|
|
300
|
+
>
|
|
301
|
+
> Untuk detail selengkapnya, lihat [dokumentasi deklarasi konten](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dictionary/content_file.md).
|
|
302
|
+
|
|
303
|
+
</Step>
|
|
304
|
+
|
|
305
|
+
<Step number={5} title="Tambahkan pengarahan terlokalisasi">
|
|
306
|
+
|
|
307
|
+
Tujuan dari langkah ini adalah untuk memberikan URL-nya sendiri ke setiap bahasa, yang diindeks oleh mesin pencari.
|
|
308
|
+
|
|
309
|
+
Pindahkan halaman Anda ke bawah **segmen dinamik opsional**. Dalam router sistem file SolidStart, `[[locale]]` mengompilasi ke pola jalur `:locale?`:
|
|
310
|
+
|
|
311
|
+
```plaintext
|
|
312
|
+
src/routes/
|
|
313
|
+
[[locale]].tsx ← tata letak yang memvalidasi segmen
|
|
314
|
+
[[locale]]/
|
|
315
|
+
index.tsx → / dan /fr dan /es
|
|
316
|
+
about.tsx → /about dan /fr/about dan /es/about
|
|
317
|
+
[...404].tsx → penangkap semua untuk yang lainnya
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Satu-satunya tugas file tata letak adalah membatasi segmen ke lokal yang dikonfigurasi:
|
|
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` memperluas `:locale?` menjadi dua pola — satu dengan segmen dan satu tanpa — dan mencobanya berdasarkan spesifisitas yang menurun. `matchFilters` adalah apa yang membuat perbedaan antara pengaturan yang berfungsi dan yang membingungkan:
|
|
338
|
+
|
|
339
|
+
| URL | Tanpa `matchFilters` | Dengan `matchFilters` |
|
|
340
|
+
| ----------- | -------------------------------------------------------------- | ------------------------------------------ |
|
|
341
|
+
| `/fr/about` | Halaman tentang dalam bahasa Prancis | Halaman tentang dalam bahasa Prancis |
|
|
342
|
+
| `/about` | Halaman tentang (segmen statis menang) | Halaman tentang |
|
|
343
|
+
| `/unknown` | **Halaman beranda**, secara diam-diam, dengan `locale=unknown` | Tidak cocok → jatuh ke 404 penangkap semua |
|
|
344
|
+
|
|
345
|
+
> Lebih suka `[locale]` (wajib) daripada `[[locale]]` jika Anda menggunakan mode pengarahan `'prefix-all'`, dan hapus segmen sepenuhnya untuk `'no-prefix'` atau `'search-params'`.
|
|
346
|
+
|
|
347
|
+
</Step>
|
|
348
|
+
|
|
349
|
+
<Step number={6} title="Sediakan lokal ke aplikasi Anda">
|
|
350
|
+
|
|
351
|
+
URL adalah satu-satunya sumber kebenaran untuk lokal: middleware telah mengalihkan permintaan ke jalur terlokalisasi, jadi membaca jalur di tata letak root menjaga penyajian server dan hidrasi klien tetap sesuai, dan membuat setiap navigasi sisi klien memperbarui lokal secara gratis.
|
|
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
|
+
// Server merender <html> di entry-server.tsx; navigasi sisi klien
|
|
369
|
+
// antar lokal harus memperbarui atribut itu sendiri.
|
|
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` bereaksi terhadap prop `locale`-nya, jadi mempassing panggilan aksesor `locale()` di dalam JSX sudah cukup — Solid mengompilasinya ke getter, dan seluruh pohon dirender ulang dalam bahasa baru saat URL berubah.
|
|
397
|
+
|
|
398
|
+
</Step>
|
|
399
|
+
|
|
400
|
+
<Step number={7} title="Atur atribut lang dan dir HTML di server">
|
|
401
|
+
|
|
402
|
+
Elemen `<html>` dirender oleh `entry-server.tsx`, di luar `Router`. Baca lokal dari URL permintaan sebagai gantinya:
|
|
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
|
+
Praperamban (crawlers) sekarang menerima bahasa yang tepat pada byte pertama:
|
|
439
|
+
|
|
440
|
+
```html
|
|
441
|
+
<html dir="ltr" lang="fr"></html>
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
</Step>
|
|
445
|
+
|
|
446
|
+
<Step number={8} title="Gunakan Intlayer di Halaman Anda">
|
|
447
|
+
|
|
448
|
+
Akses kamus konten Anda di seluruh aplikasi Anda:
|
|
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
|
+
> Di Solid, `useIntlayer` mengembalikan konten reaktif (misalnya, `content`). Anda dapat mengakses propertinya secara langsung.
|
|
471
|
+
|
|
472
|
+
> Jika Anda ingin menggunakan konten Anda dalam atribut `string`, seperti `alt`, `title`, `href`, `aria-label`, dll., Anda dapat menggunakan nilai fungsi tersebut, seperti:
|
|
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
|
+
> Untuk mempelajari lebih lanjut tentang hook `useIntlayer`, lihat [dokumentasi](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/solid-intlayer/useIntlayer.md).
|
|
481
|
+
|
|
482
|
+
Node konten tidak terbatas pada terjemahan biasa. Penghitung jamak, misalnya:
|
|
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()` memilih kategori melalui `Intl.PluralRules` untuk lokal yang aktif, sehingga bahasa dengan lebih dari dua bentuk jamak bekerja tanpa kode ekstra.
|
|
525
|
+
|
|
526
|
+
</Step>
|
|
527
|
+
|
|
528
|
+
<Step number={9} title="Buat Komponen Tautan Terlokalisasi">
|
|
529
|
+
|
|
530
|
+
Buat komponent `Link` kustom yang secara otomatis memberi awalan URL internal dengan bahasa saat ini:
|
|
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
|
+
Menulis `href="/about"` sekali sekarang menghasilkan `/about`, `/fr/about` atau `/es/about` tergantung pada lokal aktif — tanpa pengawalan manual di mana pun di halaman Anda.
|
|
570
|
+
|
|
571
|
+
</Step>
|
|
572
|
+
|
|
573
|
+
<Step number={10} title="Buat Komponen Pengalih Lokal">
|
|
574
|
+
|
|
575
|
+
Render pengalih sebagai **jangkar (anchor) nyata** daripada `<select>`: setiap bahasa dari halaman saat ini menjadi tautan yang dapat merayap yang dapat dibuka di tab baru, yang tidak dapat ditawarkan oleh kontrol khusus JavaScript.
|
|
576
|
+
|
|
577
|
+
`getPathWithoutLocale` menghapus segmen lokal dari jalur saat ini, dan `getLocalizedUrl` membangunnya kembali untuk lokal target, sehingga tautan mengikuti mode pengarahan Anda tanpa hard-coding apa pun. Navigasi adalah apa yang mengubah lokal yang dirender — rute `[[locale]]` menurunkannya dari URL — sementara `setLocale` mempertahankan pilihan dalam cookie `INTLAYER_LOCALE` sehingga kunjungan berikutnya ke URL bebas lokal menyelesaikan ke bahasa yang sama.
|
|
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
|
+
// Jalur kanonis (bebas lokal) dari halaman yang sedang ditampilkan
|
|
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
|
+
// Hanya kecocokan persis, sehingga tautan lokal default tidak ditandai
|
|
613
|
+
// aktif di setiap halaman
|
|
614
|
+
end
|
|
615
|
+
href={getLocalizedUrl(pathWithoutLocale(), localeItem)}
|
|
616
|
+
hreflang={localeItem}
|
|
617
|
+
lang={localeItem}
|
|
618
|
+
onClick={() => setLocale(localeItem)}
|
|
619
|
+
// Memastikan tombol "kembali" di peramban kembali ke halaman sebelumnya
|
|
620
|
+
replace
|
|
621
|
+
>
|
|
622
|
+
{/* Bahasa dalam lokalnya sendiri - misal Français */}
|
|
623
|
+
{getLocaleName(localeItem)}
|
|
624
|
+
</A>
|
|
625
|
+
)}
|
|
626
|
+
</For>
|
|
627
|
+
</div>
|
|
628
|
+
</div>
|
|
629
|
+
);
|
|
630
|
+
};
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
> Di Solid, `locale` dari `useLocale` adalah **aksesor sinyal**. Gunakan `locale()` (dengan tanda kurung) untuk membaca nilai saat ini secara reaktif.
|
|
634
|
+
>
|
|
635
|
+
> `getLocaleName(localeItem)` merender setiap bahasa dalam bahasanya sendiri — `English / Français / Español`. Berikan argumen kedua untuk menerjemahkan nama-nama ke dalam bahasa yang sedang ditampilkan: `getLocaleName(localeItem, locale())` memberikan `English / French / Spanish` dalam bahasa Inggris, `anglais / français / espagnol` dalam bahasa Prancis.
|
|
636
|
+
>
|
|
637
|
+
> `<A>` sudah mengatur `aria-current="page"` pada tautan yang cocok dengan URL saat ini, jadi tidak ada yang perlu ditambahkan untuk itu. `replace` dibaca kembali dari atribut yang dirender oleh router: ini menukar entri riwayat alih-alih mendorongnya, sehingga tombol "kembali" di peramban kembali ke halaman yang dikunjungi sebelum pengalihan daripada ke halaman yang sama dalam bahasa sebelumnya.
|
|
638
|
+
>
|
|
639
|
+
> `dir` dan `hreflang` pada setiap tautan menjaga nama bahasa kanan-ke-kiri berorientasi dengan benar dan memberi tahu teknologi pemandu dan praperamban bahasa mana yang ditunjuk oleh setiap tautan.
|
|
640
|
+
>
|
|
641
|
+
> Untuk mempelajari lebih lanjut tentang hook `useLocale`, lihat [dokumentasi](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/solid-intlayer/useLocale.md).
|
|
642
|
+
|
|
643
|
+
</Step>
|
|
644
|
+
|
|
645
|
+
<Step number={11} title="Pancarkan tautan canonical dan hreflang" isOptional={true}>
|
|
646
|
+
|
|
647
|
+
Anotasi `hreflang` memberi tahu mesin pencari bahwa `/about`, `/fr/about` dan `/es/about` adalah halaman yang sama dalam bahasa yang berbeda. `getMultilingualUrls` menurunkannya dari jalur kanonis (bebas lokal), mengikuti mode pengarahan Anda, sehingga tidak ada yang di-hard-code:
|
|
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 mutlak dari halaman yang dirender. */
|
|
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
|
+
Render itu di head dokumen, tempat URL permintaan tersedia:
|
|
695
|
+
|
|
696
|
+
```tsx fileName="src/entry-server.tsx" codeFormat="typescript"
|
|
697
|
+
import { AlternateLinks } from "~/components/AlternateLinks";
|
|
698
|
+
|
|
699
|
+
// … di dalam <head>, di sebelah tag meta lainnya:
|
|
700
|
+
<AlternateLinks url={url} />;
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
`GET /fr/about` kemudian melayani:
|
|
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
|
+
> **Catatan tentang `@solidjs/meta`**: pada saat penulisan, `<Title>` dan `<Meta>` dari `@solidjs/meta` diterapkan pada klien setelah hidrasi tetapi **tidak** dipancarkan ke dalam `<head>` yang dirender server di SolidStart v2. Sampai itu diperbaiki di hulu, render tag yang harus dilihat praperamban tanpa JavaScript — `canonical`, `hreflang`, dan jika perlu `title` / `description` — secara langsung di `entry-server.tsx`, seperti yang ditunjukkan di atas.
|
|
714
|
+
|
|
715
|
+
</Step>
|
|
716
|
+
|
|
717
|
+
<Step number={12} title="Kelola halaman tidak ditemukan" isOptional={true}>
|
|
718
|
+
|
|
719
|
+
Rute splat di akar `src/routes` menangkap setiap jalur yang tidak cocok dengan segmen lokal — termasuk awalan lokal tidak valid yang ditolak oleh `matchFilters`. Karena lokal masih berasal dari URL melalui tata letak root, halaman 404 ditampilkan dalam bahasa pengunjung:
|
|
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
|
+
| Permintaan | Hasil |
|
|
742
|
+
| ----------------- | ----------------------------------------------- |
|
|
743
|
+
| `/xx` | `404` — `xx` bukan lokal yang dikonfigurasi |
|
|
744
|
+
| `/nonexistent` | `404` dalam lokal default |
|
|
745
|
+
| `/fr/nonexistent` | `404` dalam bahasa Prancis (`Page introuvable`) |
|
|
746
|
+
|
|
747
|
+
</Step>
|
|
748
|
+
|
|
749
|
+
<Step number={13} title="Hasilkan peta situs multibahasa" isOptional={true}>
|
|
750
|
+
|
|
751
|
+
Generator peta situs Intlayer memperluas setiap jalur menjadi satu entri per lokal dan menghubungkan alternatif `xhtml:link` di antara mereka, sehingga rute hanya perlu mencantumkan jalur kanonis bebas lokal.
|
|
752
|
+
|
|
753
|
+
> Tidak seperti generator dasar yang hanya memancarkan URL datar, Intlayer menghubungkan tautan dua arah antara setiap varian terlokalisasi dari setiap halaman, yang membantu mesin pencari menghubungkan URL terlokalisasi dan melayani yang tepat kepada audiens yang tepat.
|
|
754
|
+
|
|
755
|
+
SolidStart mengubah file yang mengekspor metode HTTP menjadi rute API, dan menghapus ekstensi `.ts` dari jalur — jadi `src/routes/sitemap.xml.ts` dilayani di `/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
|
+
> Rute API tidak mendukung parameter opsional, jadi simpan file ini di akar `src/routes`, di luar segmen `[[locale]]`. Peta situs sudah berisi setiap lokal.
|
|
797
|
+
|
|
798
|
+
Anda dapat membangun `robots.txt` dengan cara yang sama menggunakan `getMultilingualUrls`, sehingga entri `Disallow` mencakup setiap ejaan terlokalisasi dari jalur sensitif:
|
|
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="Dapatkan lokal di fungsi server Anda" isOptional={true}>
|
|
825
|
+
|
|
826
|
+
Anda mungkin ingin mengakses lokal saat ini dari dalam fungsi server atau rute API.
|
|
827
|
+
|
|
828
|
+
Dalam pengaturan berbasis awalan seperti ini, **URL adalah otoritatif**: `getLocaleFromPath` membaca awalan dari URL permintaan. `getLocale` adalah fallback untuk permintaan yang tidak membawa awalan lokal — ini memeriksa cookie `INTLAYER_LOCALE`, lalu header `x-intlayer-locale`, lalu menegosiasikan `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
|
+
// Ambil cookie dari permintaan (default: 'INTLAYER_LOCALE')
|
|
844
|
+
getCookie: (name) =>
|
|
845
|
+
getCookie(name, request?.headers.get("cookie") ?? ""),
|
|
846
|
+
// Ambil header dari permintaan (default: 'x-intlayer-locale'),
|
|
847
|
+
// beralih ke negosiasi Accept-Language
|
|
848
|
+
getHeader: (name) => request?.headers.get(name) ?? undefined,
|
|
849
|
+
}));
|
|
850
|
+
|
|
851
|
+
// Ambil beberapa konten di luar komponen menggunakan 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
|
+
> Jangan hanya mengandalkan `getLocale` di sini: cookie lokal hanya ditulis setelah pengunjung secara aktif beralih bahasa, jadi kunjungan pertama ke `/fr/...` akan menyelesaikan ke lokal default.
|
|
865
|
+
|
|
866
|
+
</Step>
|
|
867
|
+
|
|
868
|
+
<Step number={15} title="Ekstrak konten komponen Anda" isOptional={true}>
|
|
869
|
+
|
|
870
|
+
Jika Anda memiliki basis kode yang ada, mengubah ribuan file dapat memakan waktu.
|
|
871
|
+
|
|
872
|
+
Untuk mempermudah proses ini, Intlayer mengusulkan [kompilator](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/compiler.md) / [ekstraktor](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/cli/extract.md) untuk mengubah komponen Anda dan mengekstrak konten.
|
|
873
|
+
|
|
874
|
+
Untuk mengaturnya, Anda dapat menambahkan bagian `compiler` di file `intlayer.config.ts` Anda:
|
|
875
|
+
|
|
876
|
+
```typescript fileName="intlayer.config.ts" codeFormat={["typescript", "esm", "commonjs"]}
|
|
877
|
+
import { type IntlayerConfig } from "intlayer";
|
|
878
|
+
|
|
879
|
+
const config: IntlayerConfig = {
|
|
880
|
+
// ... Sisa konfigurasi Anda
|
|
881
|
+
compiler: {
|
|
882
|
+
/**
|
|
883
|
+
* Menunjukkan apakah kompilator harus diaktifkan.
|
|
884
|
+
*/
|
|
885
|
+
enabled: true,
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Menentukan jalur file keluaran
|
|
889
|
+
*/
|
|
890
|
+
output: ({ fileName, extension }) => `./${fileName}${extension}`,
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* Menunjukkan apakah komponen harus disimpan setelah diubah.
|
|
894
|
+
*
|
|
895
|
+
* - Jika `true`, kompilator akan menulis ulang file komponen di disk. Sehingga transformasi akan permanen, dan kompilator akan melewati transformasi untuk proses berikutnya. Dengan begitu, kompilator dapat mengubah aplikasi, lalu dapat dihapus.
|
|
896
|
+
*
|
|
897
|
+
* - Jika `false`, kompilator akan menyuntikkan pemanggilan fungsi `useIntlayer()` ke dalam kode di keluaran build saja, dan menjaga basis kode dasar tetap utuh. Transformasi akan dilakukan hanya di memori.
|
|
898
|
+
*/
|
|
899
|
+
saveComponents: false,
|
|
900
|
+
|
|
901
|
+
/**
|
|
902
|
+
* Awalan kunci kamus
|
|
903
|
+
*/
|
|
904
|
+
dictionaryKeyPrefix: "",
|
|
905
|
+
},
|
|
906
|
+
};
|
|
907
|
+
|
|
908
|
+
export default config;
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
<Tabs>
|
|
912
|
+
<Tab value='Extract command'>
|
|
913
|
+
|
|
914
|
+
Jalankan ekstraktor untuk mengubah komponen Anda dan mengekstrak konten
|
|
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
|
+
> Pindahkan file konten yang dihasilkan dari halaman Anda keluar dari `src/routes` setelahnya, untuk alasan yang dijelaskan dalam langkah 5.
|
|
933
|
+
|
|
934
|
+
</Tab>
|
|
935
|
+
<Tab value='Babel compiler'>
|
|
936
|
+
|
|
937
|
+
> Sejak v9, `intlayerCompiler` disertakan dalam plugin `intlayer`. Jadi Anda tidak perlu menambahkannya secara manual.
|
|
938
|
+
|
|
939
|
+
Perbarui `vite.config.ts` Anda untuk menyertakan 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(), // Menambahkan plugin kompilator
|
|
953
|
+
],
|
|
954
|
+
});
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
```bash packageManager="npm"
|
|
958
|
+
npm run build # Atau npm run dev
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
```bash packageManager="pnpm"
|
|
962
|
+
pnpm run build # Atau pnpm run dev
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
```bash packageManager="yarn"
|
|
966
|
+
yarn build # Atau yarn dev
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
```bash packageManager="bun"
|
|
970
|
+
bun run build # Atau bun run dev
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
</Tab>
|
|
974
|
+
</Tabs>
|
|
975
|
+
|
|
976
|
+
</Step>
|
|
977
|
+
|
|
978
|
+
<Step number={16} title="Konfigurasi TypeScript">
|
|
979
|
+
|
|
980
|
+
Intlayer menggunakan augmentasi modul untuk mendapatkan manfaat TypeScript dan membuat basis kode Anda lebih kuat.
|
|
981
|
+
|
|
982
|
+
Pastikan konfigurasi TypeScript Anda mencakup tipe yang dihasilkan secara otomatis:
|
|
983
|
+
|
|
984
|
+
```json5 fileName="tsconfig.json"
|
|
985
|
+
{
|
|
986
|
+
compilerOptions: {
|
|
987
|
+
// ... konfigurasi Anda yang ada
|
|
988
|
+
},
|
|
989
|
+
include: [
|
|
990
|
+
"src",
|
|
991
|
+
"*.ts",
|
|
992
|
+
".intlayer/**/*.ts", // Sertakan tipe yang dihasilkan secara otomatis
|
|
993
|
+
],
|
|
994
|
+
}
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
Kunci kamus dan jalur konten sekarang diperiksa saat kompilasi:
|
|
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
|
+
## Memverifikasi pengaturan Anda
|
|
1011
|
+
|
|
1012
|
+
Build dan jalankan server, lalu periksa apakah permintaan ini berperilaku seperti yang diharapkan:
|
|
1013
|
+
|
|
1014
|
+
```bash
|
|
1015
|
+
npm run build
|
|
1016
|
+
node .output/server/index.mjs
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
| Permintaan | Respons yang diharapkan |
|
|
1020
|
+
| ------------------------------------------ | ------------------------------------------ |
|
|
1021
|
+
| `GET /` | `200` — Bahasa Inggris |
|
|
1022
|
+
| `GET /` dengan `Accept-Language: fr` | `302` → `/fr` |
|
|
1023
|
+
| `GET /` dengan cookie `INTLAYER_LOCALE=es` | `302` → `/es` |
|
|
1024
|
+
| `GET /fr` | `200` — Bahasa Prancis, `<html lang="fr">` |
|
|
1025
|
+
| `GET /fr/about` | `200` — Halaman tentang bahasa Prancis |
|
|
1026
|
+
| `GET /en/about` | `302` → `/about` (pengalihan kanonis) |
|
|
1027
|
+
| `GET /xx` | `404` |
|
|
1028
|
+
| `GET /fr/nonexistent` | `404` dalam bahasa Prancis |
|
|
1029
|
+
| `GET /sitemap.xml` | `200` — peta situs XML multibahasa |
|
|
1030
|
+
|
|
1031
|
+
Baris yang merender halaman berperilaku secara identik di bawah `vite dev`. Tiga baris pengalihan hanya berlaku untuk server yang dibangun kecuali Anda mendaftarkan penangan sebagai middleware sendiri — lihat langkah 3.
|
|
1032
|
+
|
|
1033
|
+
> Jalankan server pengembangan di Node (`vite dev`) daripada di Bun (`bun --bun vite dev`): SSR SolidStart saat ini gagal di bawah runtime Bun dengan `Expected a Response object, but received 'NodeResponse'`. Ini tidak terkait dengan Intlayer — ini mereproduksi pada templat biasa — dan hanya memengaruhi server pengembangan, bukan `vite build`.
|
|
1034
|
+
|
|
1035
|
+
---
|
|
1036
|
+
|
|
1037
|
+
## Konfigurasi Git
|
|
1038
|
+
|
|
1039
|
+
Disarankan untuk mengabaikan file yang dihasilkan oleh Intlayer. Ini memungkinkan Anda untuk menghindari melakukan commit file tersebut ke repositori Git Anda.
|
|
1040
|
+
|
|
1041
|
+
Untuk melakukan ini, Anda dapat menambahkan instruksi berikut ke file `.gitignore` Anda:
|
|
1042
|
+
|
|
1043
|
+
```plaintext fileName=".gitignore"
|
|
1044
|
+
# Abaikan file yang dihasilkan oleh Intlayer
|
|
1045
|
+
.intlayer
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
---
|
|
1049
|
+
|
|
1050
|
+
## Ekstensi VS Code
|
|
1051
|
+
|
|
1052
|
+
Untuk meningkatkan pengalaman pengembangan Anda dengan Intlayer, Anda dapat menginstal **Ekstensi VS Code Intlayer** resmi.
|
|
1053
|
+
|
|
1054
|
+
[Instal dari VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=intlayer.intlayer-vs-code-extension)
|
|
1055
|
+
|
|
1056
|
+
Ekstensi ini menyediakan:
|
|
1057
|
+
|
|
1058
|
+
- **Autokomplit** untuk kunci terjemahan.
|
|
1059
|
+
- **Deteksi kesalahan real-time** untuk terjemahan yang hilang.
|
|
1060
|
+
- **Pratinjau langsung** dari konten yang diterjemahkan.
|
|
1061
|
+
- **Tindakan cepat** untuk membuat dan memperbarui terjemahan dengan mudah.
|
|
1062
|
+
|
|
1063
|
+
---
|
|
1064
|
+
|
|
1065
|
+
## Melangkah Lebih Jauh
|
|
1066
|
+
|
|
1067
|
+
Untuk melangkah lebih jauh, Anda dapat mengimplementasikan [editor visual](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_visual_editor.md) atau mengeksternalisasi konten Anda menggunakan [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_CMS.md).
|
|
1068
|
+
|
|
1069
|
+
---
|
|
1070
|
+
|
|
1071
|
+
## Referensi Dokumentasi
|
|
1072
|
+
|
|
1073
|
+
- [Dokumentasi Intlayer](https://intlayer.org)
|
|
1074
|
+
- [Dokumentasi SolidStart](https://start.solidjs.com)
|
|
1075
|
+
- [Hook useIntlayer](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/solid-intlayer/useIntlayer.md)
|
|
1076
|
+
- [Hook useLocale](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/solid-intlayer/useLocale.md)
|
|
1077
|
+
- [Deklarasi Konten](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dictionary/content_file.md)
|
|
1078
|
+
- [Konfigurasi](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/configuration.md)
|