@intlayer/docs 9.5.3 → 9.5.4
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/README.md +8 -8
- package/blog/ar/history_of_i18n.md +54 -54
- package/blog/ar/how_to_pick_react_i18n_library.md +548 -0
- package/blog/ar/how_to_pick_solid_i18n_library.md +438 -0
- package/blog/ar/how_to_pick_svelte_i18n_library.md +454 -0
- package/blog/ar/how_to_pick_vue_i18n_library.md +442 -0
- package/blog/ar/is_i18next_outdated.md +5 -1
- package/blog/ar/is_next-intl_outdated.md +5 -1
- package/blog/ar/is_vue-i18n_outdated.md +7 -1
- package/blog/ar/next-i18next_vs_next-intl_vs_intlayer.md +8 -4
- package/blog/ar/per-component_vs_centralized_i18n.md +9 -4
- package/blog/ar/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/de/history_of_i18n.md +54 -54
- package/blog/de/how_to_pick_react_i18n_library.md +548 -0
- package/blog/de/how_to_pick_solid_i18n_library.md +451 -0
- package/blog/de/how_to_pick_svelte_i18n_library.md +454 -0
- package/blog/de/how_to_pick_vue_i18n_library.md +448 -0
- package/blog/de/is_i18next_outdated.md +5 -1
- package/blog/de/is_next-intl_outdated.md +5 -1
- package/blog/de/is_vue-i18n_outdated.md +7 -1
- package/blog/de/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/de/per-component_vs_centralized_i18n.md +9 -4
- package/blog/de/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/en/history_of_i18n.md +54 -54
- package/blog/en/how_to_pick_react_i18n_library.md +542 -0
- package/blog/en/how_to_pick_solid_i18n_library.md +438 -0
- package/blog/en/how_to_pick_svelte_i18n_library.md +448 -0
- package/blog/en/how_to_pick_vue_i18n_library.md +442 -0
- package/blog/en/is_i18next_outdated.md +5 -1
- package/blog/en/is_next-intl_outdated.md +5 -1
- package/blog/en/is_vue-i18n_outdated.md +7 -1
- package/blog/en/list_i18n_technologies/frameworks/react-router.md +2 -3
- package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/en/per-component_vs_centralized_i18n.md +9 -4
- package/blog/en/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/en-GB/history_of_i18n.md +54 -54
- package/blog/en-GB/how_to_pick_react_i18n_library.md +542 -0
- package/blog/en-GB/how_to_pick_solid_i18n_library.md +438 -0
- package/blog/en-GB/how_to_pick_svelte_i18n_library.md +448 -0
- package/blog/en-GB/how_to_pick_vue_i18n_library.md +448 -0
- package/blog/en-GB/is_i18next_outdated.md +5 -1
- package/blog/en-GB/is_next-intl_outdated.md +5 -1
- package/blog/en-GB/is_vue-i18n_outdated.md +7 -1
- package/blog/en-GB/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/en-GB/per-component_vs_centralized_i18n.md +9 -4
- package/blog/en-GB/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/es/history_of_i18n.md +54 -54
- package/blog/es/how_to_pick_react_i18n_library.md +542 -0
- package/blog/es/how_to_pick_solid_i18n_library.md +446 -0
- package/blog/es/how_to_pick_svelte_i18n_library.md +448 -0
- package/blog/es/how_to_pick_vue_i18n_library.md +442 -0
- package/blog/es/is_i18next_outdated.md +5 -1
- package/blog/es/is_next-intl_outdated.md +5 -1
- package/blog/es/is_vue-i18n_outdated.md +7 -1
- package/blog/es/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/es/per-component_vs_centralized_i18n.md +9 -4
- package/blog/es/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/fr/history_of_i18n.md +54 -54
- package/blog/fr/how_to_pick_react_i18n_library.md +542 -0
- package/blog/fr/how_to_pick_solid_i18n_library.md +438 -0
- package/blog/fr/how_to_pick_svelte_i18n_library.md +448 -0
- package/blog/fr/how_to_pick_vue_i18n_library.md +442 -0
- package/blog/fr/is_i18next_outdated.md +5 -1
- package/blog/fr/is_next-intl_outdated.md +5 -1
- package/blog/fr/is_vue-i18n_outdated.md +7 -1
- package/blog/fr/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/fr/per-component_vs_centralized_i18n.md +9 -4
- package/blog/fr/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/hi/history_of_i18n.md +54 -54
- package/blog/hi/how_to_pick_react_i18n_library.md +548 -0
- package/blog/hi/how_to_pick_solid_i18n_library.md +451 -0
- package/blog/hi/how_to_pick_svelte_i18n_library.md +448 -0
- package/blog/hi/how_to_pick_vue_i18n_library.md +442 -0
- package/blog/hi/is_i18next_outdated.md +5 -1
- package/blog/hi/is_next-intl_outdated.md +5 -1
- package/blog/hi/is_vue-i18n_outdated.md +7 -1
- package/blog/hi/next-i18next_vs_next-intl_vs_intlayer.md +8 -4
- package/blog/hi/per-component_vs_centralized_i18n.md +9 -4
- package/blog/hi/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/id/history_of_i18n.md +54 -54
- package/blog/id/how_to_pick_react_i18n_library.md +548 -0
- package/blog/id/how_to_pick_solid_i18n_library.md +451 -0
- package/blog/id/how_to_pick_svelte_i18n_library.md +454 -0
- package/blog/id/how_to_pick_vue_i18n_library.md +442 -0
- package/blog/id/is_i18next_outdated.md +5 -1
- package/blog/id/is_next-intl_outdated.md +5 -1
- package/blog/id/is_vue-i18n_outdated.md +7 -1
- package/blog/id/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/id/per-component_vs_centralized_i18n.md +9 -4
- package/blog/id/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/it/history_of_i18n.md +54 -54
- package/blog/it/how_to_pick_react_i18n_library.md +549 -0
- package/blog/it/how_to_pick_solid_i18n_library.md +451 -0
- package/blog/it/how_to_pick_svelte_i18n_library.md +455 -0
- package/blog/it/how_to_pick_vue_i18n_library.md +449 -0
- package/blog/it/is_i18next_outdated.md +5 -1
- package/blog/it/is_next-intl_outdated.md +5 -1
- package/blog/it/is_vue-i18n_outdated.md +7 -1
- package/blog/it/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/it/per-component_vs_centralized_i18n.md +9 -4
- package/blog/it/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/ja/history_of_i18n.md +54 -54
- package/blog/ja/how_to_pick_react_i18n_library.md +542 -0
- package/blog/ja/how_to_pick_solid_i18n_library.md +451 -0
- package/blog/ja/how_to_pick_svelte_i18n_library.md +457 -0
- package/blog/ja/how_to_pick_vue_i18n_library.md +442 -0
- package/blog/ja/is_i18next_outdated.md +5 -1
- package/blog/ja/is_next-intl_outdated.md +5 -1
- package/blog/ja/is_vue-i18n_outdated.md +7 -1
- package/blog/ja/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/ja/per-component_vs_centralized_i18n.md +9 -4
- package/blog/ja/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/ko/history_of_i18n.md +54 -54
- package/blog/ko/how_to_pick_react_i18n_library.md +548 -0
- package/blog/ko/how_to_pick_solid_i18n_library.md +451 -0
- package/blog/ko/how_to_pick_svelte_i18n_library.md +454 -0
- package/blog/ko/how_to_pick_vue_i18n_library.md +448 -0
- package/blog/ko/is_i18next_outdated.md +5 -1
- package/blog/ko/is_next-intl_outdated.md +5 -1
- package/blog/ko/is_vue-i18n_outdated.md +7 -1
- package/blog/ko/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/ko/per-component_vs_centralized_i18n.md +9 -4
- package/blog/ko/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/pl/history_of_i18n.md +54 -54
- package/blog/pl/how_to_pick_react_i18n_library.md +549 -0
- package/blog/pl/how_to_pick_solid_i18n_library.md +438 -0
- package/blog/pl/how_to_pick_svelte_i18n_library.md +460 -0
- package/blog/pl/how_to_pick_vue_i18n_library.md +442 -0
- package/blog/pl/is_i18next_outdated.md +5 -1
- package/blog/pl/is_next-intl_outdated.md +5 -1
- package/blog/pl/is_vue-i18n_outdated.md +7 -1
- package/blog/pl/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/pl/per-component_vs_centralized_i18n.md +9 -4
- package/blog/pl/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/pt/history_of_i18n.md +54 -54
- package/blog/pt/how_to_pick_react_i18n_library.md +549 -0
- package/blog/pt/how_to_pick_solid_i18n_library.md +451 -0
- package/blog/pt/how_to_pick_svelte_i18n_library.md +454 -0
- package/blog/pt/how_to_pick_vue_i18n_library.md +448 -0
- package/blog/pt/is_i18next_outdated.md +5 -1
- package/blog/pt/is_next-intl_outdated.md +5 -1
- package/blog/pt/is_vue-i18n_outdated.md +7 -1
- package/blog/pt/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/pt/per-component_vs_centralized_i18n.md +9 -4
- package/blog/pt/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/ru/history_of_i18n.md +54 -54
- package/blog/ru/how_to_pick_react_i18n_library.md +553 -0
- package/blog/ru/how_to_pick_solid_i18n_library.md +451 -0
- package/blog/ru/how_to_pick_svelte_i18n_library.md +459 -0
- package/blog/ru/how_to_pick_vue_i18n_library.md +453 -0
- package/blog/ru/is_i18next_outdated.md +5 -1
- package/blog/ru/is_next-intl_outdated.md +5 -1
- package/blog/ru/is_vue-i18n_outdated.md +7 -1
- package/blog/ru/next-i18next_vs_next-intl_vs_intlayer.md +8 -4
- package/blog/ru/per-component_vs_centralized_i18n.md +9 -4
- package/blog/ru/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/tr/history_of_i18n.md +54 -54
- package/blog/tr/how_to_pick_react_i18n_library.md +548 -0
- package/blog/tr/how_to_pick_solid_i18n_library.md +451 -0
- package/blog/tr/how_to_pick_svelte_i18n_library.md +454 -0
- package/blog/tr/how_to_pick_vue_i18n_library.md +448 -0
- package/blog/tr/is_i18next_outdated.md +5 -1
- package/blog/tr/is_next-intl_outdated.md +5 -1
- package/blog/tr/is_vue-i18n_outdated.md +7 -1
- package/blog/tr/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/tr/per-component_vs_centralized_i18n.md +9 -4
- package/blog/tr/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/uk/history_of_i18n.md +54 -54
- package/blog/uk/how_to_pick_react_i18n_library.md +542 -0
- package/blog/uk/how_to_pick_solid_i18n_library.md +451 -0
- package/blog/uk/how_to_pick_svelte_i18n_library.md +448 -0
- package/blog/uk/how_to_pick_vue_i18n_library.md +443 -0
- package/blog/uk/is_i18next_outdated.md +5 -1
- package/blog/uk/is_next-intl_outdated.md +5 -1
- package/blog/uk/is_vue-i18n_outdated.md +7 -1
- package/blog/uk/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/uk/per-component_vs_centralized_i18n.md +9 -4
- package/blog/uk/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/vi/history_of_i18n.md +54 -54
- package/blog/vi/how_to_pick_react_i18n_library.md +548 -0
- package/blog/vi/how_to_pick_solid_i18n_library.md +438 -0
- package/blog/vi/how_to_pick_svelte_i18n_library.md +448 -0
- package/blog/vi/how_to_pick_vue_i18n_library.md +442 -0
- package/blog/vi/is_i18next_outdated.md +5 -1
- package/blog/vi/is_next-intl_outdated.md +5 -1
- package/blog/vi/is_vue-i18n_outdated.md +7 -1
- package/blog/vi/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/vi/per-component_vs_centralized_i18n.md +9 -4
- package/blog/vi/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/blog/zh/history_of_i18n.md +54 -54
- package/blog/zh/how_to_pick_react_i18n_library.md +548 -0
- package/blog/zh/how_to_pick_solid_i18n_library.md +451 -0
- package/blog/zh/how_to_pick_svelte_i18n_library.md +454 -0
- package/blog/zh/how_to_pick_vue_i18n_library.md +448 -0
- package/blog/zh/is_i18next_outdated.md +5 -1
- package/blog/zh/is_next-intl_outdated.md +5 -1
- package/blog/zh/is_vue-i18n_outdated.md +7 -1
- package/blog/zh/next-i18next_vs_next-intl_vs_intlayer.md +9 -5
- package/blog/zh/per-component_vs_centralized_i18n.md +9 -4
- package/blog/zh/react-i18next_vs_react-intl_vs_intlayer.md +5 -1
- package/dist/cjs/generated/blog.entry.cjs +80 -0
- package/dist/cjs/generated/blog.entry.cjs.map +1 -1
- package/dist/cjs/index.cjs +1 -1
- package/dist/esm/generated/blog.entry.mjs +80 -0
- package/dist/esm/generated/blog.entry.mjs.map +1 -1
- package/dist/esm/index.mjs +1 -1
- package/dist/types/generated/blog.entry.d.ts +4 -0
- package/dist/types/generated/blog.entry.d.ts.map +1 -1
- package/docs/ar/bundle_optimization.md +5 -1
- package/docs/ar/how_works_intlayer.md +2 -2
- package/docs/ar/interest_of_intlayer.md +6 -6
- package/docs/ar/intlayer_CMS.md +1 -1
- package/docs/ar/intlayer_with_adonisjs.md +1 -1
- package/docs/ar/intlayer_with_analog.md +1 -1
- package/docs/ar/intlayer_with_angular_19.md +1 -1
- package/docs/ar/intlayer_with_angular_21.md +1 -1
- package/docs/ar/intlayer_with_astro.md +1 -1
- package/docs/ar/intlayer_with_astro_lit.md +1 -1
- package/docs/ar/intlayer_with_astro_preact.md +1 -1
- package/docs/ar/intlayer_with_astro_react.md +1 -1
- package/docs/ar/intlayer_with_astro_solid.md +1 -1
- package/docs/ar/intlayer_with_astro_svelte.md +1 -1
- package/docs/ar/intlayer_with_astro_vanilla.md +1 -1
- package/docs/ar/intlayer_with_astro_vue.md +1 -1
- package/docs/ar/intlayer_with_create_react_app.md +1 -1
- package/docs/ar/intlayer_with_express.md +1 -1
- package/docs/ar/intlayer_with_hono.md +1 -1
- package/docs/ar/intlayer_with_nestjs.md +1 -1
- package/docs/ar/intlayer_with_nextjs_14.md +1 -1
- package/docs/ar/intlayer_with_nextjs_15.md +1 -1
- package/docs/ar/intlayer_with_nextjs_16.md +1 -1
- package/docs/ar/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/ar/intlayer_with_react_router_v7.md +1 -1
- package/docs/ar/intlayer_with_vite+preact.md +1 -1
- package/docs/ar/intlayer_with_vite+react.md +1 -1
- package/docs/ar/intlayer_with_vite+vue.md +1 -1
- package/docs/ar/introduction.md +0 -1
- package/docs/ar/readme.md +8 -8
- package/docs/bn/bundle_optimization.md +5 -1
- package/docs/bn/interest_of_intlayer.md +21 -21
- package/docs/bn/intlayer_CMS.md +1 -1
- package/docs/bn/intlayer_with_angular_21.md +1 -1
- package/docs/bn/intlayer_with_hono.md +1 -1
- package/docs/bn/introduction.md +0 -1
- package/docs/cs/bundle_optimization.md +5 -1
- package/docs/cs/interest_of_intlayer.md +6 -6
- package/docs/cs/intlayer_with_angular_21.md +1 -1
- package/docs/cs/intlayer_with_hono.md +1 -1
- package/docs/cs/introduction.md +0 -1
- package/docs/de/bundle_optimization.md +5 -1
- package/docs/de/how_works_intlayer.md +2 -2
- package/docs/de/interest_of_intlayer.md +6 -6
- package/docs/de/intlayer_CMS.md +1 -1
- package/docs/de/intlayer_with_adonisjs.md +1 -1
- package/docs/de/intlayer_with_analog.md +1 -1
- package/docs/de/intlayer_with_angular_19.md +1 -1
- package/docs/de/intlayer_with_angular_21.md +1 -1
- package/docs/de/intlayer_with_astro.md +1 -1
- package/docs/de/intlayer_with_astro_lit.md +1 -1
- package/docs/de/intlayer_with_astro_preact.md +1 -1
- package/docs/de/intlayer_with_astro_react.md +1 -1
- package/docs/de/intlayer_with_astro_solid.md +1 -1
- package/docs/de/intlayer_with_astro_svelte.md +1 -1
- package/docs/de/intlayer_with_astro_vanilla.md +1 -1
- package/docs/de/intlayer_with_astro_vue.md +1 -1
- package/docs/de/intlayer_with_create_react_app.md +1 -1
- package/docs/de/intlayer_with_express.md +1 -1
- package/docs/de/intlayer_with_hono.md +1 -1
- package/docs/de/intlayer_with_nestjs.md +1 -1
- package/docs/de/intlayer_with_nextjs_14.md +1 -1
- package/docs/de/intlayer_with_nextjs_15.md +1 -1
- package/docs/de/intlayer_with_nextjs_16.md +1 -1
- package/docs/de/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/de/intlayer_with_vite+preact.md +1 -1
- package/docs/de/intlayer_with_vite+react.md +1 -1
- package/docs/de/intlayer_with_vite+vue.md +1 -1
- package/docs/de/introduction.md +0 -1
- package/docs/de/readme.md +8 -8
- package/docs/en/bundle_optimization.md +5 -1
- package/docs/en/how_works_intlayer.md +2 -2
- package/docs/en/interest_of_intlayer.md +6 -6
- package/docs/en/intlayer_CMS.md +1 -1
- package/docs/en/intlayer_with_adonisjs.md +1 -1
- package/docs/en/intlayer_with_analog.md +1 -1
- package/docs/en/intlayer_with_angular_19.md +1 -1
- package/docs/en/intlayer_with_angular_21.md +1 -1
- package/docs/en/intlayer_with_astro.md +1 -1
- package/docs/en/intlayer_with_astro_lit.md +1 -1
- package/docs/en/intlayer_with_astro_preact.md +1 -1
- package/docs/en/intlayer_with_astro_react.md +1 -1
- package/docs/en/intlayer_with_astro_solid.md +1 -1
- package/docs/en/intlayer_with_astro_svelte.md +1 -1
- package/docs/en/intlayer_with_astro_vanilla.md +1 -1
- package/docs/en/intlayer_with_astro_vue.md +1 -1
- package/docs/en/intlayer_with_create_react_app.md +1 -1
- package/docs/en/intlayer_with_express.md +1 -1
- package/docs/en/intlayer_with_hono.md +1 -1
- package/docs/en/intlayer_with_nestjs.md +1 -1
- package/docs/en/intlayer_with_nextjs_14.md +1 -1
- package/docs/en/intlayer_with_nextjs_15.md +1 -1
- package/docs/en/intlayer_with_nextjs_16.md +1 -1
- package/docs/en/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/en/intlayer_with_vite+preact.md +1 -1
- package/docs/en/intlayer_with_vite+react.md +1 -1
- package/docs/en/intlayer_with_vite+vue.md +1 -1
- package/docs/en/introduction.md +0 -1
- package/docs/en/readme.md +8 -8
- package/docs/en-GB/bundle_optimization.md +5 -1
- package/docs/en-GB/how_works_intlayer.md +2 -2
- package/docs/en-GB/interest_of_intlayer.md +6 -6
- package/docs/en-GB/intlayer_CMS.md +1 -1
- package/docs/en-GB/intlayer_with_adonisjs.md +1 -1
- package/docs/en-GB/intlayer_with_analog.md +1 -1
- package/docs/en-GB/intlayer_with_angular_19.md +1 -1
- package/docs/en-GB/intlayer_with_angular_21.md +1 -1
- package/docs/en-GB/intlayer_with_astro.md +1 -1
- package/docs/en-GB/intlayer_with_astro_lit.md +1 -1
- package/docs/en-GB/intlayer_with_astro_preact.md +1 -1
- package/docs/en-GB/intlayer_with_astro_react.md +1 -1
- package/docs/en-GB/intlayer_with_astro_solid.md +1 -1
- package/docs/en-GB/intlayer_with_astro_svelte.md +1 -1
- package/docs/en-GB/intlayer_with_astro_vanilla.md +1 -1
- package/docs/en-GB/intlayer_with_astro_vue.md +1 -1
- package/docs/en-GB/intlayer_with_create_react_app.md +1 -1
- package/docs/en-GB/intlayer_with_express.md +1 -1
- package/docs/en-GB/intlayer_with_hono.md +1 -1
- package/docs/en-GB/intlayer_with_nestjs.md +1 -1
- package/docs/en-GB/intlayer_with_nextjs_14.md +1 -1
- package/docs/en-GB/intlayer_with_nextjs_15.md +1 -1
- package/docs/en-GB/intlayer_with_nextjs_16.md +1 -1
- package/docs/en-GB/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/en-GB/intlayer_with_vite+preact.md +1 -1
- package/docs/en-GB/intlayer_with_vite+react.md +1 -1
- package/docs/en-GB/intlayer_with_vite+vue.md +1 -1
- package/docs/en-GB/introduction.md +0 -1
- package/docs/en-GB/readme.md +8 -8
- package/docs/es/bundle_optimization.md +5 -1
- package/docs/es/how_works_intlayer.md +2 -2
- package/docs/es/interest_of_intlayer.md +6 -6
- package/docs/es/intlayer_CMS.md +1 -1
- package/docs/es/intlayer_with_adonisjs.md +1 -1
- package/docs/es/intlayer_with_analog.md +1 -1
- package/docs/es/intlayer_with_angular_19.md +1 -1
- package/docs/es/intlayer_with_angular_21.md +1 -1
- package/docs/es/intlayer_with_astro.md +1 -1
- package/docs/es/intlayer_with_astro_lit.md +1 -1
- package/docs/es/intlayer_with_astro_preact.md +1 -1
- package/docs/es/intlayer_with_astro_react.md +1 -1
- package/docs/es/intlayer_with_astro_solid.md +1 -1
- package/docs/es/intlayer_with_astro_svelte.md +1 -1
- package/docs/es/intlayer_with_astro_vanilla.md +1 -1
- package/docs/es/intlayer_with_astro_vue.md +1 -1
- package/docs/es/intlayer_with_create_react_app.md +1 -1
- package/docs/es/intlayer_with_express.md +1 -1
- package/docs/es/intlayer_with_hono.md +1 -1
- package/docs/es/intlayer_with_nestjs.md +1 -1
- package/docs/es/intlayer_with_nextjs_14.md +1 -1
- package/docs/es/intlayer_with_nextjs_15.md +1 -1
- package/docs/es/intlayer_with_nextjs_16.md +1 -1
- package/docs/es/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/es/intlayer_with_vite+preact.md +1 -1
- package/docs/es/intlayer_with_vite+react.md +1 -1
- package/docs/es/intlayer_with_vite+vue.md +1 -1
- package/docs/es/introduction.md +0 -1
- package/docs/es/readme.md +8 -8
- package/docs/fr/bundle_optimization.md +5 -1
- package/docs/fr/how_works_intlayer.md +2 -2
- package/docs/fr/interest_of_intlayer.md +6 -6
- package/docs/fr/intlayer_CMS.md +1 -1
- package/docs/fr/intlayer_with_adonisjs.md +1 -1
- package/docs/fr/intlayer_with_analog.md +1 -1
- package/docs/fr/intlayer_with_angular_19.md +1 -1
- package/docs/fr/intlayer_with_angular_21.md +1 -1
- package/docs/fr/intlayer_with_astro.md +1 -1
- package/docs/fr/intlayer_with_astro_lit.md +1 -1
- package/docs/fr/intlayer_with_astro_preact.md +1 -1
- package/docs/fr/intlayer_with_astro_react.md +1 -1
- package/docs/fr/intlayer_with_astro_solid.md +1 -1
- package/docs/fr/intlayer_with_astro_svelte.md +1 -1
- package/docs/fr/intlayer_with_astro_vanilla.md +1 -1
- package/docs/fr/intlayer_with_astro_vue.md +1 -1
- package/docs/fr/intlayer_with_create_react_app.md +1 -1
- package/docs/fr/intlayer_with_express.md +1 -1
- package/docs/fr/intlayer_with_hono.md +1 -1
- package/docs/fr/intlayer_with_nestjs.md +1 -1
- package/docs/fr/intlayer_with_nextjs_14.md +1 -1
- package/docs/fr/intlayer_with_nextjs_15.md +1 -1
- package/docs/fr/intlayer_with_nextjs_16.md +1 -1
- package/docs/fr/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/fr/intlayer_with_react_router_v7.md +2 -2
- package/docs/fr/intlayer_with_vite+preact.md +1 -1
- package/docs/fr/intlayer_with_vite+react.md +1 -1
- package/docs/fr/intlayer_with_vite+vue.md +1 -1
- package/docs/fr/introduction.md +0 -1
- package/docs/fr/readme.md +8 -8
- package/docs/hi/bundle_optimization.md +5 -1
- package/docs/hi/how_works_intlayer.md +2 -2
- package/docs/hi/interest_of_intlayer.md +6 -6
- package/docs/hi/intlayer_CMS.md +1 -1
- package/docs/hi/intlayer_with_adonisjs.md +1 -1
- package/docs/hi/intlayer_with_analog.md +1 -1
- package/docs/hi/intlayer_with_angular_19.md +1 -1
- package/docs/hi/intlayer_with_angular_21.md +1 -1
- package/docs/hi/intlayer_with_astro.md +1 -1
- package/docs/hi/intlayer_with_astro_lit.md +1 -1
- package/docs/hi/intlayer_with_astro_preact.md +1 -1
- package/docs/hi/intlayer_with_astro_react.md +1 -1
- package/docs/hi/intlayer_with_astro_solid.md +1 -1
- package/docs/hi/intlayer_with_astro_svelte.md +1 -1
- package/docs/hi/intlayer_with_astro_vanilla.md +1 -1
- package/docs/hi/intlayer_with_astro_vue.md +1 -1
- package/docs/hi/intlayer_with_create_react_app.md +1 -1
- package/docs/hi/intlayer_with_express.md +1 -1
- package/docs/hi/intlayer_with_hono.md +1 -1
- package/docs/hi/intlayer_with_nestjs.md +1 -1
- package/docs/hi/intlayer_with_nextjs_14.md +1 -1
- package/docs/hi/intlayer_with_nextjs_15.md +1 -1
- package/docs/hi/intlayer_with_nextjs_16.md +1 -1
- package/docs/hi/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/hi/intlayer_with_react_router_v7.md +1 -1
- package/docs/hi/intlayer_with_vite+preact.md +1 -1
- package/docs/hi/intlayer_with_vite+react.md +1 -1
- package/docs/hi/intlayer_with_vite+vue.md +1 -1
- package/docs/hi/introduction.md +0 -1
- package/docs/hi/readme.md +8 -8
- package/docs/id/bundle_optimization.md +5 -1
- package/docs/id/how_works_intlayer.md +2 -2
- package/docs/id/interest_of_intlayer.md +6 -6
- package/docs/id/intlayer_CMS.md +1 -1
- package/docs/id/intlayer_with_adonisjs.md +1 -1
- package/docs/id/intlayer_with_analog.md +1 -1
- package/docs/id/intlayer_with_angular_19.md +1 -1
- package/docs/id/intlayer_with_angular_21.md +1 -1
- package/docs/id/intlayer_with_astro.md +1 -1
- package/docs/id/intlayer_with_astro_lit.md +1 -1
- package/docs/id/intlayer_with_astro_preact.md +1 -1
- package/docs/id/intlayer_with_astro_react.md +1 -1
- package/docs/id/intlayer_with_astro_solid.md +1 -1
- package/docs/id/intlayer_with_astro_svelte.md +1 -1
- package/docs/id/intlayer_with_astro_vanilla.md +1 -1
- package/docs/id/intlayer_with_astro_vue.md +1 -1
- package/docs/id/intlayer_with_create_react_app.md +1 -1
- package/docs/id/intlayer_with_express.md +1 -1
- package/docs/id/intlayer_with_hono.md +1 -1
- package/docs/id/intlayer_with_nestjs.md +1 -1
- package/docs/id/intlayer_with_nextjs_14.md +1 -1
- package/docs/id/intlayer_with_nextjs_15.md +1 -1
- package/docs/id/intlayer_with_nextjs_16.md +1 -1
- package/docs/id/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/id/intlayer_with_react_router_v7.md +1 -1
- package/docs/id/intlayer_with_vite+preact.md +1 -1
- package/docs/id/intlayer_with_vite+react.md +1 -1
- package/docs/id/intlayer_with_vite+vue.md +1 -1
- package/docs/id/introduction.md +0 -1
- package/docs/id/readme.md +8 -8
- package/docs/it/bundle_optimization.md +5 -1
- package/docs/it/how_works_intlayer.md +2 -2
- package/docs/it/interest_of_intlayer.md +6 -6
- package/docs/it/intlayer_CMS.md +1 -1
- package/docs/it/intlayer_with_adonisjs.md +1 -1
- package/docs/it/intlayer_with_analog.md +1 -1
- package/docs/it/intlayer_with_angular_19.md +1 -1
- package/docs/it/intlayer_with_angular_21.md +1 -1
- package/docs/it/intlayer_with_astro.md +1 -1
- package/docs/it/intlayer_with_astro_lit.md +1 -1
- package/docs/it/intlayer_with_astro_preact.md +1 -1
- package/docs/it/intlayer_with_astro_react.md +1 -1
- package/docs/it/intlayer_with_astro_solid.md +1 -1
- package/docs/it/intlayer_with_astro_svelte.md +1 -1
- package/docs/it/intlayer_with_astro_vanilla.md +1 -1
- package/docs/it/intlayer_with_astro_vue.md +1 -1
- package/docs/it/intlayer_with_create_react_app.md +1 -1
- package/docs/it/intlayer_with_express.md +1 -1
- package/docs/it/intlayer_with_hono.md +1 -1
- package/docs/it/intlayer_with_nestjs.md +1 -1
- package/docs/it/intlayer_with_nextjs_14.md +1 -1
- package/docs/it/intlayer_with_nextjs_15.md +1 -1
- package/docs/it/intlayer_with_nextjs_16.md +1 -1
- package/docs/it/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/it/intlayer_with_react_router_v7.md +2 -2
- package/docs/it/intlayer_with_vite+preact.md +1 -1
- package/docs/it/intlayer_with_vite+react.md +1 -1
- package/docs/it/intlayer_with_vite+vue.md +1 -1
- package/docs/it/introduction.md +0 -1
- package/docs/it/readme.md +8 -8
- package/docs/ja/bundle_optimization.md +5 -1
- package/docs/ja/how_works_intlayer.md +2 -2
- package/docs/ja/interest_of_intlayer.md +6 -6
- package/docs/ja/intlayer_CMS.md +1 -1
- package/docs/ja/intlayer_with_adonisjs.md +1 -1
- package/docs/ja/intlayer_with_analog.md +1 -1
- package/docs/ja/intlayer_with_angular_19.md +1 -1
- package/docs/ja/intlayer_with_angular_21.md +1 -1
- package/docs/ja/intlayer_with_astro.md +1 -1
- package/docs/ja/intlayer_with_astro_lit.md +1 -1
- package/docs/ja/intlayer_with_astro_preact.md +1 -1
- package/docs/ja/intlayer_with_astro_react.md +1 -1
- package/docs/ja/intlayer_with_astro_solid.md +1 -1
- package/docs/ja/intlayer_with_astro_svelte.md +1 -1
- package/docs/ja/intlayer_with_astro_vanilla.md +1 -1
- package/docs/ja/intlayer_with_astro_vue.md +1 -1
- package/docs/ja/intlayer_with_create_react_app.md +1 -1
- package/docs/ja/intlayer_with_express.md +1 -1
- package/docs/ja/intlayer_with_hono.md +1 -1
- package/docs/ja/intlayer_with_nestjs.md +1 -1
- package/docs/ja/intlayer_with_nextjs_14.md +1 -1
- package/docs/ja/intlayer_with_nextjs_15.md +1 -1
- package/docs/ja/intlayer_with_nextjs_16.md +1 -1
- package/docs/ja/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/ja/intlayer_with_vite+preact.md +1 -1
- package/docs/ja/intlayer_with_vite+react.md +1 -1
- package/docs/ja/intlayer_with_vite+vue.md +1 -1
- package/docs/ja/introduction.md +0 -1
- package/docs/ja/readme.md +8 -8
- package/docs/ko/bundle_optimization.md +5 -1
- package/docs/ko/how_works_intlayer.md +2 -2
- package/docs/ko/interest_of_intlayer.md +6 -6
- package/docs/ko/intlayer_CMS.md +1 -1
- package/docs/ko/intlayer_with_adonisjs.md +1 -1
- package/docs/ko/intlayer_with_analog.md +1 -1
- package/docs/ko/intlayer_with_angular_19.md +1 -1
- package/docs/ko/intlayer_with_angular_21.md +1 -1
- package/docs/ko/intlayer_with_astro.md +1 -1
- package/docs/ko/intlayer_with_astro_lit.md +1 -1
- package/docs/ko/intlayer_with_astro_preact.md +1 -1
- package/docs/ko/intlayer_with_astro_react.md +1 -1
- package/docs/ko/intlayer_with_astro_solid.md +1 -1
- package/docs/ko/intlayer_with_astro_svelte.md +1 -1
- package/docs/ko/intlayer_with_astro_vanilla.md +1 -1
- package/docs/ko/intlayer_with_astro_vue.md +1 -1
- package/docs/ko/intlayer_with_create_react_app.md +1 -1
- package/docs/ko/intlayer_with_express.md +1 -1
- package/docs/ko/intlayer_with_hono.md +1 -1
- package/docs/ko/intlayer_with_nestjs.md +1 -1
- package/docs/ko/intlayer_with_nextjs_14.md +1 -1
- package/docs/ko/intlayer_with_nextjs_15.md +1 -1
- package/docs/ko/intlayer_with_nextjs_16.md +1 -1
- package/docs/ko/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/ko/intlayer_with_react_router_v7.md +2 -2
- package/docs/ko/intlayer_with_vite+preact.md +1 -1
- package/docs/ko/intlayer_with_vite+react.md +1 -1
- package/docs/ko/intlayer_with_vite+vue.md +1 -1
- package/docs/ko/introduction.md +0 -1
- package/docs/ko/readme.md +8 -8
- package/docs/nl/bundle_optimization.md +5 -1
- package/docs/nl/interest_of_intlayer.md +6 -6
- package/docs/nl/intlayer_with_angular_21.md +1 -1
- package/docs/nl/intlayer_with_hono.md +1 -1
- package/docs/nl/introduction.md +0 -1
- package/docs/pl/bundle_optimization.md +5 -1
- package/docs/pl/how_works_intlayer.md +2 -2
- package/docs/pl/interest_of_intlayer.md +6 -6
- package/docs/pl/intlayer_CMS.md +1 -1
- package/docs/pl/intlayer_with_adonisjs.md +1 -1
- package/docs/pl/intlayer_with_analog.md +1 -1
- package/docs/pl/intlayer_with_angular_19.md +1 -1
- package/docs/pl/intlayer_with_angular_21.md +1 -1
- package/docs/pl/intlayer_with_astro.md +1 -1
- package/docs/pl/intlayer_with_astro_lit.md +1 -1
- package/docs/pl/intlayer_with_astro_preact.md +1 -1
- package/docs/pl/intlayer_with_astro_react.md +1 -1
- package/docs/pl/intlayer_with_astro_solid.md +1 -1
- package/docs/pl/intlayer_with_astro_svelte.md +1 -1
- package/docs/pl/intlayer_with_astro_vanilla.md +1 -1
- package/docs/pl/intlayer_with_astro_vue.md +1 -1
- package/docs/pl/intlayer_with_create_react_app.md +1 -1
- package/docs/pl/intlayer_with_express.md +1 -1
- package/docs/pl/intlayer_with_hono.md +1 -1
- package/docs/pl/intlayer_with_nestjs.md +1 -1
- package/docs/pl/intlayer_with_nextjs_14.md +1 -1
- package/docs/pl/intlayer_with_nextjs_15.md +1 -1
- package/docs/pl/intlayer_with_nextjs_16.md +1 -1
- package/docs/pl/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/pl/intlayer_with_react_router_v7.md +2 -2
- package/docs/pl/intlayer_with_vite+preact.md +1 -1
- package/docs/pl/intlayer_with_vite+react.md +1 -1
- package/docs/pl/intlayer_with_vite+vue.md +1 -1
- package/docs/pl/introduction.md +0 -1
- package/docs/pl/readme.md +8 -8
- package/docs/pt/bundle_optimization.md +5 -1
- package/docs/pt/how_works_intlayer.md +2 -2
- package/docs/pt/interest_of_intlayer.md +6 -6
- package/docs/pt/intlayer_CMS.md +1 -1
- package/docs/pt/intlayer_with_adonisjs.md +1 -1
- package/docs/pt/intlayer_with_analog.md +1 -1
- package/docs/pt/intlayer_with_angular_19.md +1 -1
- package/docs/pt/intlayer_with_angular_21.md +1 -1
- package/docs/pt/intlayer_with_astro.md +1 -1
- package/docs/pt/intlayer_with_astro_lit.md +1 -1
- package/docs/pt/intlayer_with_astro_preact.md +1 -1
- package/docs/pt/intlayer_with_astro_react.md +1 -1
- package/docs/pt/intlayer_with_astro_solid.md +1 -1
- package/docs/pt/intlayer_with_astro_svelte.md +1 -1
- package/docs/pt/intlayer_with_astro_vanilla.md +1 -1
- package/docs/pt/intlayer_with_astro_vue.md +1 -1
- package/docs/pt/intlayer_with_create_react_app.md +1 -1
- package/docs/pt/intlayer_with_express.md +1 -1
- package/docs/pt/intlayer_with_hono.md +1 -1
- package/docs/pt/intlayer_with_nestjs.md +1 -1
- package/docs/pt/intlayer_with_nextjs_14.md +1 -1
- package/docs/pt/intlayer_with_nextjs_15.md +1 -1
- package/docs/pt/intlayer_with_nextjs_16.md +1 -1
- package/docs/pt/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/pt/intlayer_with_react_router_v7.md +2 -2
- package/docs/pt/intlayer_with_vite+preact.md +1 -1
- package/docs/pt/intlayer_with_vite+react.md +1 -1
- package/docs/pt/intlayer_with_vite+vue.md +1 -1
- package/docs/pt/introduction.md +0 -1
- package/docs/pt/readme.md +8 -8
- package/docs/ru/bundle_optimization.md +5 -1
- package/docs/ru/how_works_intlayer.md +2 -2
- package/docs/ru/interest_of_intlayer.md +6 -6
- package/docs/ru/intlayer_CMS.md +1 -1
- package/docs/ru/intlayer_with_adonisjs.md +1 -1
- package/docs/ru/intlayer_with_analog.md +1 -1
- package/docs/ru/intlayer_with_angular_19.md +1 -1
- package/docs/ru/intlayer_with_angular_21.md +1 -1
- package/docs/ru/intlayer_with_astro.md +1 -1
- package/docs/ru/intlayer_with_astro_lit.md +1 -1
- package/docs/ru/intlayer_with_astro_preact.md +1 -1
- package/docs/ru/intlayer_with_astro_react.md +1 -1
- package/docs/ru/intlayer_with_astro_solid.md +1 -1
- package/docs/ru/intlayer_with_astro_svelte.md +1 -1
- package/docs/ru/intlayer_with_astro_vanilla.md +1 -1
- package/docs/ru/intlayer_with_astro_vue.md +1 -1
- package/docs/ru/intlayer_with_create_react_app.md +1 -1
- package/docs/ru/intlayer_with_express.md +1 -1
- package/docs/ru/intlayer_with_hono.md +1 -1
- package/docs/ru/intlayer_with_nestjs.md +1 -1
- package/docs/ru/intlayer_with_nextjs_14.md +1 -1
- package/docs/ru/intlayer_with_nextjs_15.md +1 -1
- package/docs/ru/intlayer_with_nextjs_16.md +1 -1
- package/docs/ru/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/ru/intlayer_with_react_router_v7.md +2 -2
- package/docs/ru/intlayer_with_vite+preact.md +1 -1
- package/docs/ru/intlayer_with_vite+react.md +1 -1
- package/docs/ru/intlayer_with_vite+vue.md +1 -1
- package/docs/ru/introduction.md +0 -1
- package/docs/ru/readme.md +8 -8
- package/docs/tr/bundle_optimization.md +5 -1
- package/docs/tr/how_works_intlayer.md +2 -2
- package/docs/tr/interest_of_intlayer.md +6 -6
- package/docs/tr/intlayer_CMS.md +1 -1
- package/docs/tr/intlayer_with_adonisjs.md +1 -1
- package/docs/tr/intlayer_with_analog.md +1 -1
- package/docs/tr/intlayer_with_angular_19.md +1 -1
- package/docs/tr/intlayer_with_angular_21.md +1 -1
- package/docs/tr/intlayer_with_astro.md +1 -1
- package/docs/tr/intlayer_with_astro_lit.md +1 -1
- package/docs/tr/intlayer_with_astro_preact.md +1 -1
- package/docs/tr/intlayer_with_astro_react.md +1 -1
- package/docs/tr/intlayer_with_astro_solid.md +1 -1
- package/docs/tr/intlayer_with_astro_svelte.md +1 -1
- package/docs/tr/intlayer_with_astro_vanilla.md +1 -1
- package/docs/tr/intlayer_with_astro_vue.md +1 -1
- package/docs/tr/intlayer_with_create_react_app.md +1 -1
- package/docs/tr/intlayer_with_express.md +1 -1
- package/docs/tr/intlayer_with_hono.md +1 -1
- package/docs/tr/intlayer_with_nestjs.md +1 -1
- package/docs/tr/intlayer_with_nextjs_14.md +1 -1
- package/docs/tr/intlayer_with_nextjs_15.md +1 -1
- package/docs/tr/intlayer_with_nextjs_16.md +1 -1
- package/docs/tr/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/tr/intlayer_with_react_router_v7.md +1 -1
- package/docs/tr/intlayer_with_vite+preact.md +1 -1
- package/docs/tr/intlayer_with_vite+react.md +1 -1
- package/docs/tr/intlayer_with_vite+vue.md +1 -1
- package/docs/tr/introduction.md +0 -1
- package/docs/tr/readme.md +8 -8
- package/docs/uk/bundle_optimization.md +5 -1
- package/docs/uk/how_works_intlayer.md +2 -2
- package/docs/uk/interest_of_intlayer.md +6 -6
- package/docs/uk/intlayer_CMS.md +1 -1
- package/docs/uk/intlayer_with_adonisjs.md +1 -1
- package/docs/uk/intlayer_with_analog.md +1 -1
- package/docs/uk/intlayer_with_angular_19.md +1 -1
- package/docs/uk/intlayer_with_angular_21.md +1 -1
- package/docs/uk/intlayer_with_astro.md +1 -1
- package/docs/uk/intlayer_with_astro_lit.md +1 -1
- package/docs/uk/intlayer_with_astro_preact.md +1 -1
- package/docs/uk/intlayer_with_astro_react.md +1 -1
- package/docs/uk/intlayer_with_astro_solid.md +1 -1
- package/docs/uk/intlayer_with_astro_svelte.md +1 -1
- package/docs/uk/intlayer_with_astro_vanilla.md +1 -1
- package/docs/uk/intlayer_with_astro_vue.md +1 -1
- package/docs/uk/intlayer_with_create_react_app.md +1 -1
- package/docs/uk/intlayer_with_express.md +1 -1
- package/docs/uk/intlayer_with_hono.md +1 -1
- package/docs/uk/intlayer_with_nestjs.md +1 -1
- package/docs/uk/intlayer_with_nextjs_14.md +1 -1
- package/docs/uk/intlayer_with_nextjs_15.md +1 -1
- package/docs/uk/intlayer_with_nextjs_16.md +1 -1
- package/docs/uk/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/uk/intlayer_with_react_router_v7.md +1 -1
- package/docs/uk/intlayer_with_vite+preact.md +1 -1
- package/docs/uk/intlayer_with_vite+react.md +1 -1
- package/docs/uk/intlayer_with_vite+vue.md +1 -1
- package/docs/uk/introduction.md +0 -1
- package/docs/uk/readme.md +8 -8
- package/docs/ur/bundle_optimization.md +5 -1
- package/docs/ur/interest_of_intlayer.md +6 -6
- package/docs/ur/intlayer_with_angular_21.md +1 -1
- package/docs/ur/intlayer_with_hono.md +1 -1
- package/docs/ur/introduction.md +0 -1
- package/docs/vi/bundle_optimization.md +5 -1
- package/docs/vi/how_works_intlayer.md +2 -2
- package/docs/vi/interest_of_intlayer.md +6 -6
- package/docs/vi/intlayer_CMS.md +1 -1
- package/docs/vi/intlayer_with_adonisjs.md +1 -1
- package/docs/vi/intlayer_with_analog.md +1 -1
- package/docs/vi/intlayer_with_angular_19.md +1 -1
- package/docs/vi/intlayer_with_angular_21.md +1 -1
- package/docs/vi/intlayer_with_astro.md +1 -1
- package/docs/vi/intlayer_with_astro_lit.md +1 -1
- package/docs/vi/intlayer_with_astro_preact.md +1 -1
- package/docs/vi/intlayer_with_astro_react.md +1 -1
- package/docs/vi/intlayer_with_astro_solid.md +1 -1
- package/docs/vi/intlayer_with_astro_svelte.md +1 -1
- package/docs/vi/intlayer_with_astro_vanilla.md +1 -1
- package/docs/vi/intlayer_with_astro_vue.md +1 -1
- package/docs/vi/intlayer_with_create_react_app.md +1 -1
- package/docs/vi/intlayer_with_express.md +1 -1
- package/docs/vi/intlayer_with_hono.md +1 -1
- package/docs/vi/intlayer_with_nestjs.md +1 -1
- package/docs/vi/intlayer_with_nextjs_14.md +1 -1
- package/docs/vi/intlayer_with_nextjs_15.md +1 -1
- package/docs/vi/intlayer_with_nextjs_16.md +1 -1
- package/docs/vi/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/vi/intlayer_with_vite+preact.md +1 -1
- package/docs/vi/intlayer_with_vite+react.md +1 -1
- package/docs/vi/intlayer_with_vite+vue.md +1 -1
- package/docs/vi/introduction.md +0 -1
- package/docs/vi/readme.md +8 -8
- package/docs/zh/bundle_optimization.md +5 -1
- package/docs/zh/how_works_intlayer.md +2 -2
- package/docs/zh/interest_of_intlayer.md +6 -6
- package/docs/zh/intlayer_CMS.md +1 -1
- package/docs/zh/intlayer_with_adonisjs.md +1 -1
- package/docs/zh/intlayer_with_analog.md +1 -1
- package/docs/zh/intlayer_with_angular_19.md +1 -1
- package/docs/zh/intlayer_with_angular_21.md +1 -1
- package/docs/zh/intlayer_with_astro.md +1 -1
- package/docs/zh/intlayer_with_astro_lit.md +1 -1
- package/docs/zh/intlayer_with_astro_preact.md +1 -1
- package/docs/zh/intlayer_with_astro_react.md +1 -1
- package/docs/zh/intlayer_with_astro_solid.md +1 -1
- package/docs/zh/intlayer_with_astro_svelte.md +1 -1
- package/docs/zh/intlayer_with_astro_vanilla.md +1 -1
- package/docs/zh/intlayer_with_astro_vue.md +1 -1
- package/docs/zh/intlayer_with_create_react_app.md +1 -1
- package/docs/zh/intlayer_with_express.md +1 -1
- package/docs/zh/intlayer_with_hono.md +1 -1
- package/docs/zh/intlayer_with_nestjs.md +1 -1
- package/docs/zh/intlayer_with_nextjs_14.md +1 -1
- package/docs/zh/intlayer_with_nextjs_15.md +1 -1
- package/docs/zh/intlayer_with_nextjs_16.md +1 -1
- package/docs/zh/intlayer_with_nextjs_page_router.md +1 -1
- package/docs/zh/intlayer_with_react_router_v7.md +2 -2
- package/docs/zh/intlayer_with_vite+preact.md +1 -1
- package/docs/zh/intlayer_with_vite+react.md +1 -1
- package/docs/zh/intlayer_with_vite+vue.md +1 -1
- package/docs/zh/introduction.md +0 -1
- package/docs/zh/readme.md +8 -8
- package/docs/zh-TW/bundle_optimization.md +5 -1
- package/docs/zh-TW/interest_of_intlayer.md +6 -6
- package/docs/zh-TW/intlayer_with_angular_21.md +1 -1
- package/docs/zh-TW/introduction.md +0 -1
- package/package.json +8 -7
- package/src/generated/blog.entry.ts +80 -0
- package/blog/en/___per-component_vs_centralized_i18n.md +0 -255
- package/blog/pl/___per-component_vs_centralized_i18n.md +0 -100
- package/docs/en/benchmark/___NOTE.md +0 -101
- package/docs/en/benchmark/___nextjs.md +0 -197
- package/docs/en/benchmark/___solid.md +0 -12
- package/docs/en/benchmark/___svelte.md +0 -16
- package/docs/en/benchmark/___tanstack.md +0 -190
- package/docs/en/benchmark/___vue.md +0 -7
- package/docs/pl/benchmark/___NOTE.md +0 -101
- package/docs/pl/benchmark/___nextjs.md +0 -198
- package/docs/pl/benchmark/___solid.md +0 -36
- package/docs/pl/benchmark/___svelte.md +0 -36
- package/docs/pl/benchmark/___tanstack.md +0 -36
- package/docs/pl/benchmark/___vue.md +0 -36
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-09-16
|
|
3
|
+
updatedAt: 2026-09-16
|
|
4
|
+
title: "Cách chọn đúng thư viện Vue i18n năm 2026"
|
|
5
|
+
description: Hướng dẫn ra quyết định cho việc quốc tế hóa (i18n) Vue và Nuxt. Những câu hỏi cần trả lời trước khi so sánh vue-i18n, @nuxtjs/i18n, fluent-vue, Paraglide và Intlayer, cùng chi phí của từng lựa chọn về bundle size, typing và SSR payload.
|
|
6
|
+
keywords:
|
|
7
|
+
- vue i18n
|
|
8
|
+
- vue internationalization
|
|
9
|
+
- vue-i18n
|
|
10
|
+
- nuxt i18n
|
|
11
|
+
- fluent-vue
|
|
12
|
+
- Paraglide
|
|
13
|
+
- Intlayer
|
|
14
|
+
- so sánh thư viện i18n
|
|
15
|
+
slugs:
|
|
16
|
+
- blog
|
|
17
|
+
- how-to-pick-vue-i18n-library
|
|
18
|
+
author: aymericzip
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Cách chọn đúng thư viện Vue i18n
|
|
22
|
+
|
|
23
|
+
"Vue i18n" vừa là một thuật ngữ chung vừa là tên của thư viện mà hầu như ai cũng cài đặt. Điều đó vừa tiện lợi vừa dễ gây hiểu lầm: `vue-i18n` là một lựa chọn mặc định tốt, nhưng không phải là lựa chọn duy nhất, và những câu hỏi định hình quyết định (có dùng SSR hay không, bao nhiêu trang, ai là người viết bản dịch) hiếm khi được đặt ra trước khi chạy `npm install`.
|
|
24
|
+
|
|
25
|
+
Hướng dẫn này sẽ đặt ra những câu hỏi đó trước, sau đó ánh xạ các câu trả lời tới những thư viện phù hợp, cho cả Vite + Vue thuần lẫn Nuxt.
|
|
26
|
+
|
|
27
|
+

|
|
28
|
+
|
|
29
|
+
## Mục lục
|
|
30
|
+
|
|
31
|
+
<TOC/>
|
|
32
|
+
|
|
33
|
+
## Sáu câu hỏi cần trả lời trước khi so sánh các thư viện
|
|
34
|
+
|
|
35
|
+
1. **Vite SPA hay Nuxt?** Trong một SPA, chi phí catalog là vấn đề về JS bundle. Trong Nuxt, đó còn là vấn đề về HTML payload, bởi vì các message được serialize vào SSR state và hydrate. Hầu hết các báo cáo "vue-i18n chạy chậm" xuất phát từ các ứng dụng Nuxt chính vì lý do này.
|
|
36
|
+
2. **Ai là người viết bản dịch?** Developer, một TMS, một agency bàn giao chuỗi ICU, hay một AI pipeline. `vue-i18n` sử dụng cú pháp số nhiều riêng biệt phân cách bằng dấu gạch đứng (pipe-separated), không phải ICU. Điều này rất quan trọng nếu các chuỗi văn bản đến từ bên ngoài.
|
|
37
|
+
3. **Có bao nhiêu locale và trang?** Hai locale và năm trang có thể chuyển giao (ship) tất cả mọi thứ cùng lúc. Mười locale và bốn mươi route thì không thể, và chiến lược tải dữ liệu (loading strategy) sẽ trở thành chi phí chính.
|
|
38
|
+
4. **Bạn có cần type trên các key không?** `t("cart.totl")` vẫn biên dịch bình thường trong `vue-i18n` trừ khi bạn truyền một message schema generic, và schema đó lại xung đột với các catalog được lazy load.
|
|
39
|
+
5. **Nội dung bao gồm những gì?** Chỉ các nhãn UI, hay cả markdown, liên kết bên trong câu, và các block riêng theo từng locale. Rich content là nơi mà việc `t()` trả về một chuỗi string trở nên bất tiện.
|
|
40
|
+
6. **CSP có phải là một ràng buộc không?** Bản build mặc định của `vue-i18n` biên dịch message trong trình duyệt bằng `new Function`. Các bản build runtime-only cần `@intlify/unplugin-vue-i18n` để precompile tại thời điểm build time.
|
|
41
|
+
|
|
42
|
+
Hãy ghi lại các câu trả lời. Mọi phân tích bên dưới đều sẽ đối chiếu lại với chúng.
|
|
43
|
+
|
|
44
|
+
## Bức tranh toàn cảnh qua một hình ảnh
|
|
45
|
+
|
|
46
|
+
Hệ sinh thái Vue có ít thư viện i18n hơn React, và chúng đến từ các làn sóng kiến trúc khác nhau.
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
<AccordionGroup>
|
|
51
|
+
<Accordion header="Runtime dictionary (2015 đến 2019): vue-i18n, @nuxt/i18n">
|
|
52
|
+
|
|
53
|
+
`vue-i18n` xuất hiện vào năm 2015 và luôn là lựa chọn mặc định kể từ đó. `@nuxt/i18n` bọc lấy nó với tính năng định tuyến locale (locale routing), thẻ SEO và lazy loading theo từng locale. Các message được biên dịch thành các render function, tại thời điểm build time nếu bạn thêm unplugin, hoặc trực tiếp trong trình duyệt nếu không cấu hình thêm.
|
|
54
|
+
|
|
55
|
+
</Accordion>
|
|
56
|
+
<Accordion header="Định dạng thay thế (2020): fluent-vue">
|
|
57
|
+
|
|
58
|
+
Các file `.ftl` của Mozilla Fluent mang lại cú pháp message thân thiện hơn cùng các biến thể nhận biết ngữ pháp (grammar-aware). Không có key type, và Vite plugin sẽ nạp mọi locale vào từng trang.
|
|
59
|
+
|
|
60
|
+
</Accordion>
|
|
61
|
+
<Accordion header="Compiler và nội dung đồng vị trí (2024 đến 2026): Paraglide, Intlayer">
|
|
62
|
+
|
|
63
|
+
Paraglide sinh ra một hàm cho mỗi message và để bundler tự động tree-shake phần còn lại. Intlayer khai báo nội dung theo từng component trong các file `.content.ts`, sinh type tự động, và chỉ chuyển giao những gì một route thực sự render.
|
|
64
|
+
|
|
65
|
+
</Accordion>
|
|
66
|
+
</AccordionGroup>
|
|
67
|
+
|
|
68
|
+
Bài viết [lịch sử của JavaScript i18n](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/history_of_i18n.md) đi sâu chi tiết vào từng làn sóng.
|
|
69
|
+
|
|
70
|
+
## Quyết định quan trọng nhất: nội dung nằm ở đâu và được tải khi nào
|
|
71
|
+
|
|
72
|
+
Hai lựa chọn mang tính cấu trúc giải thích cho hầu hết sự khác biệt về bundle size giữa các thiết lập:
|
|
73
|
+
|
|
74
|
+
- **Nội dung tập trung hay phân tán theo phạm vi (scoped).** Một file `locales/en.json` cho toàn bộ ứng dụng, hay một khai báo riêng cho từng component.
|
|
75
|
+
- **Static hay dynamic import.** Nạp tất cả mọi thứ khi khởi động, hay chỉ tải locale đang hoạt động (và lý tưởng nhất là route đang hoạt động) theo nhu cầu (on demand).
|
|
76
|
+
|
|
77
|
+
Biểu đồ ước tính payload cho một ứng dụng trên lý thuyết từ 1 đến 10 trang, được dịch sang 1 đến 10 locale, với khoảng 30 KB văn bản trên mỗi trang.
|
|
78
|
+
|
|
79
|
+

|
|
80
|
+
|
|
81
|
+
`vue-i18n` hỗ trợ trục dynamic: gọi `setLocaleMessage` sau một lệnh `import()` đồng nghĩa với việc bạn không còn phải chuyển giao chín locale mà không ai đọc. Điều mà nó không mang lại cho bạn là trục theo trang. Một catalog locale là một đối tượng duy nhất, và việc nạp nó sẽ nạp toàn bộ nội dung của mọi trang. Trong một SPA, không ai nhận ra điều đó. Nhưng trong Nuxt, với `@nuxtjs/i18n` và nhiều hơn mười trang, mỗi route đều phải gánh các chuỗi của mọi route khác hai lần: trong JS chunk và trong SSR payload.
|
|
82
|
+
|
|
83
|
+
Bài [benchmark Vue](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/benchmark/vue.md) đo lường điều này dưới dạng "rò rỉ từ các route khác" (leakage from other routes) và "rò rỉ từ các locale khác" (leakage from other locales). Nếu câu trả lời của bạn cho câu hỏi 3 là "nhiều trang", phần này sẽ quan trọng hơn bất kỳ sở thích API nào. Bài viết [i18n theo từng component so với tập trung](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/per-component_vs_centralized_i18n.md) đề cập đến khía cạnh bảo trì của cùng sự đánh đổi này.
|
|
84
|
+
|
|
85
|
+
## Các ứng cử viên
|
|
86
|
+
|
|
87
|
+
Kích thước thư viện được lấy từ bài [benchmark Vue](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/benchmark/vue.md): plugin cộng với composable trong một component rỗng, sau khi bundling, tree-shaking và minification, trên một ứng dụng 10 trang, 10 locale. Nội dung được đo lường riêng biệt.
|
|
88
|
+
|
|
89
|
+
| Thư viện | Mô hình nội dung | An toàn kiểu | Định dạng message | Phân tách theo route | Kích thước thư viện |
|
|
90
|
+
| :------------- | :--------------------------------------------------------- | :------------------------------- | :---------------------------------- | :--------------------- | :------------------------------------------------- |
|
|
91
|
+
| `vue-i18n` | Catalog tập trung theo locale, tùy chọn SFC `<i18n>` block | 2/5 — Opt-in qua schema generic | Riêng (pipe plural) | Không | ~24.3 kB |
|
|
92
|
+
| `@nuxtjs/i18n` | Tương tự `vue-i18n`, cộng thêm routing và thẻ SEO | 2/5 — Tương tự | Tương tự | Không, chỉ theo locale | ~24.3 kB |
|
|
93
|
+
| `fluent-vue` | File `.ftl` (Mozilla Fluent) | 1/5 — Không | Fluent | Không | ~29.7 kB |
|
|
94
|
+
| Paraglide | Project inlang, các hàm được sinh ra | 3.5/5 — Được sinh ra | Riêng | Qua tree-shaking | Gần như bằng 0 (do mã được sinh ra trong codebase) |
|
|
95
|
+
| Intlayer | Một file `.content.ts` cho mỗi component | 5/5 — Được sinh ra, bật mặc định | Intlayer (+ ICU, i18next, vue-i18n) | Có, theo component | ~3.9 kB |
|
|
96
|
+
|
|
97
|
+
> Các con số là ảnh chụp nhanh tại các phiên bản của bài benchmark. Hãy chạy thử nghiệm trên chính ứng dụng của bạn trước khi đưa ra quyết định chỉ dựa vào kích thước.
|
|
98
|
+
> An toàn kiểu: 5/5 nghĩa là khóa, tham số và mọi locale đều được kiểm tra mà không cần thiết lập thủ công, bao gồm cả trình định dạng URL và các helper.
|
|
99
|
+
|
|
100
|
+
Kích thước thư viện gần như bằng 0 của Paraglide đạt được nhờ thiết kế: runtime được sinh trực tiếp vào repository của bạn, điều này đồng nghĩa với việc cần một bước sinh lại mã (regeneration) trước mỗi lần push và nguy cơ merge conflict trên các file được sinh ra. Intlayer cần `vite-intlayer` (hoặc Nuxt module), vì vậy nó không thể chạy nếu không có một build step.
|
|
101
|
+
|
|
102
|
+
## Đối chiếu câu trả lời với thư viện phù hợp
|
|
103
|
+
|
|
104
|
+
<AccordionGroup>
|
|
105
|
+
<Accordion header="Vite SPA, team nhỏ, ít locale">
|
|
106
|
+
|
|
107
|
+
`vue-i18n` ở chế độ Composition (`legacy: false`), kết hợp với `@intlify/unplugin-vue-i18n` để bạn chuyển giao bản build runtime-only. Lazy-load các locale bằng `import()`. Cấu hình này đáp ứng hầu hết các ứng dụng nhỏ và câu trả lời từ cộng đồng có ở khắp mọi nơi. Các block SFC `<i18n>` đặt message đồng vị trí với component, điều này rất hữu ích, nhưng công cụ trích xuất và hỗ trợ TMS xung quanh chúng còn hạn chế hơn so với catalog JSON, vì vậy hãy sớm thống nhất lựa chọn mà team sẽ sử dụng.
|
|
108
|
+
|
|
109
|
+
</Accordion>
|
|
110
|
+
<Accordion header="Nuxt với định tuyến locale, sitemap và hreflang">
|
|
111
|
+
|
|
112
|
+
`@nuxtjs/i18n` cung cấp chiến lược định tuyến, các thẻ `hreflang` và tự động phát hiện locale mà không cần viết thêm code, và chỉ riêng điều đó đã đủ để chọn nó cho các trang nội dung có vài trang. Giới hạn của nó nằm ở catalog theo từng locale: khi vượt quá khoảng mười trang, SSR payload sẽ phải gánh toàn bộ nội dung của mọi route. Nếu đó là trường hợp của bạn, hãy tự cấu hình thủ công `vue-i18n` với message theo từng route, hoặc chuyển sang mô hình nội dung scoped. Bài viết [Nuxt i18n](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/list_i18n_technologies/frameworks/nuxt.md) sẽ hướng dẫn bạn lựa chọn chiến lược định tuyến trước tiên.
|
|
113
|
+
|
|
114
|
+
</Accordion>
|
|
115
|
+
<Accordion header="Bản dịch đến từ TMS hoặc agency bàn giao định dạng ICU">
|
|
116
|
+
|
|
117
|
+
Cú pháp số nhiều của `vue-i18n` (`"no item | one item | {count} items"`) không phải là ICU và không mang tính tương thích cao (portable). Các biên dịch viên cần được thông báo trước về điều này, và bản xuất từ TMS thông thường sẽ không tạo ra định dạng đó. Hãy thống nhất định dạng trước khi tạo catalog đầu tiên, hoặc chọn một thư viện có định dạng phù hợp với vendor của bạn. Khả năng hỗ trợ ICU của Intlayer mới ở mức một phần, vì vậy nếu hiện tại bạn nhận chuỗi ICU, hãy cân nhắc đó cũng là một yếu tố cản trở.
|
|
118
|
+
|
|
119
|
+
</Accordion>
|
|
120
|
+
<Accordion header="Ứng dụng lớn, nhiều route, ngân sách bundle hoặc SSR payload hạn chế">
|
|
121
|
+
|
|
122
|
+
Nên ưu tiên nội dung scoped được biên dịch tại build time. Paraglide đạt được điều này thông qua tree-shaking, hoạt động rất hiệu quả trên Vite. Intlayer đạt được điều này thông qua các khai báo theo từng component và chỉ chuyển giao những gì route thực sự render. Với `vue-i18n`, bạn có thể chia tách message theo route một cách thủ công, nhưng không có gì đảm bảo tính thực thi và một component dùng chung import namespace toàn cục có thể âm thầm phá vỡ cấu trúc đó.
|
|
123
|
+
|
|
124
|
+
</Accordion>
|
|
125
|
+
<Accordion header="Type safety là yêu cầu bắt buộc">
|
|
126
|
+
|
|
127
|
+
`vue-i18n` có thể được gán type bằng cách truyền một schema generic vào `createI18n`. Cách này hoạt động được, nhưng sẽ bị phá vỡ ngay khi các catalog được lazy load, bởi vì schema mô tả các message có thể chưa được tải về. Nếu không muốn phải tự bảo trì điều đó, hãy chọn thư viện có type được sinh trực tiếp từ nội dung: Paraglide hoặc Intlayer. Bài viết [phát hiện bản dịch còn thiếu](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/detecting_missing_translations.md) so sánh những gì mỗi công cụ phát hiện được tại build time.
|
|
128
|
+
|
|
129
|
+
</Accordion>
|
|
130
|
+
<Accordion header="Nội dung phức tạp hơn các nhãn UI thông thường">
|
|
131
|
+
|
|
132
|
+
Các trang markdown, câu có chứa `<RouterLink>` ở giữa, hoặc các component riêng biệt theo locale. `vue-i18n` có `<i18n-t>` cho phép nội suy component (component interpolation), hoạt động ổn nhưng khá dài dòng. Content node của Intlayer chấp nhận markdown, HTML và các object lồng nhau trực tiếp, phù hợp hơn nhiều khi ứng dụng chứa nhiều nội dung phong phú.
|
|
133
|
+
|
|
134
|
+
</Accordion>
|
|
135
|
+
<Accordion header="Bản dịch sẽ được tạo bởi AI">
|
|
136
|
+
|
|
137
|
+
Khi đó, file JSON tập trung không còn đối tượng sử dụng nào để duy trì sự tồn tại của nó. Nội dung đồng vị trí kết hợp với một CLI tự động điền các locale còn thiếu là con đường ngắn hơn nhiều. Lệnh `fill` của Intlayer chạy trực tiếp với API key của chính bạn (OpenAI, Anthropic, Mistral, Gemini) và chỉ dịch lại những gì đã thay đổi.
|
|
138
|
+
|
|
139
|
+
</Accordion>
|
|
140
|
+
</AccordionGroup>
|
|
141
|
+
|
|
142
|
+
## Hạn chế của từng thư viện
|
|
143
|
+
|
|
144
|
+
- **`vue-i18n`**: nặng nhất trong nhóm, định dạng số nhiều riêng, type là tùy chọn (opt-in) và dễ vỡ khi lazy loading, không hỗ trợ phân tách phạm vi theo route, các key không dùng tích tụ một cách âm thầm. Việc để lại `legacy: true` trong ứng dụng Vue 3 sẽ giữ lại layer tương thích Vue 2 và làm mất khả năng gõ type của `useI18n()`.
|
|
145
|
+
- **`@nuxtjs/i18n`**: thừa hưởng tất cả các nhược điểm trên, và SSR payload sẽ gánh toàn bộ chuỗi ký tự của mọi trang khi ứng dụng vượt quá khoảng một tá route.
|
|
146
|
+
- **`fluent-vue`**: cú pháp message tốt, không có key type, và Vite plugin nạp tất cả nội dung ở mọi ngôn ngữ vào từng trang. Nặng nhất trong bài benchmark.
|
|
147
|
+
- **Paraglide**: các file được sinh ra phải commit vào repo, cần regenerate trước mỗi lần push, và locale được đọc từ cookie hoặc storage trên mỗi lệnh gọi message thay vì từ một reactive store, làm tốn thêm tài nguyên xử lý khi chuyển đổi locale.
|
|
148
|
+
- **Intlayer**: bắt buộc phải có build plugin, hệ sinh thái nhỏ hơn, hỗ trợ ICU một phần, và nội dung phân tán khắp codebase theo thiết kế, vì vậy việc xuất ra một file JSON duy nhất cho biên dịch viên sẽ cần đến công cụ hỗ trợ.
|
|
149
|
+
|
|
150
|
+
## Mã nguồn thực tế của từng lựa chọn
|
|
151
|
+
|
|
152
|
+
Cùng một component, phần tóm tắt giỏ hàng với tiêu đề và định dạng số nhiều, được viết bằng từng ứng cử viên. Điểm thú vị không nằm ở template, mà ở vị trí lưu trữ nội dung và những gì `vue-tsc` nhận biết được về nó.
|
|
153
|
+
|
|
154
|
+
<Tabs defaultTab="vue-i18n">
|
|
155
|
+
<Tab label="vue-i18n" value="vue-i18n">
|
|
156
|
+
|
|
157
|
+
<Tabs group="locale">
|
|
158
|
+
<Tab value="en" label="Tiếng Anh">
|
|
159
|
+
|
|
160
|
+
```json fileName="src/locales/en.json"
|
|
161
|
+
{
|
|
162
|
+
"cart": {
|
|
163
|
+
"title": "Your cart",
|
|
164
|
+
"items": "no item | one item | {count} items"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
</Tab>
|
|
170
|
+
<Tab value="fr" label="Tiếng Pháp">
|
|
171
|
+
|
|
172
|
+
```json fileName="src/locales/fr.json"
|
|
173
|
+
{
|
|
174
|
+
"cart": {
|
|
175
|
+
"title": "Votre panier",
|
|
176
|
+
"items": "aucun article | un article | {count} articles"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
</Tab>
|
|
182
|
+
<Tab value="es" label="Tiếng Tây Ban Nha">
|
|
183
|
+
|
|
184
|
+
```json fileName="src/locales/es.json"
|
|
185
|
+
{
|
|
186
|
+
"cart": {
|
|
187
|
+
"title": "Tu carrito",
|
|
188
|
+
"items": "ningún artículo | un artículo | {count} artículos"
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
</Tab>
|
|
194
|
+
</Tabs>
|
|
195
|
+
|
|
196
|
+
```vue fileName="src/components/CartSummary.vue"
|
|
197
|
+
<script setup lang="ts">
|
|
198
|
+
import { useI18n } from "vue-i18n";
|
|
199
|
+
|
|
200
|
+
const props = defineProps<{ count: number }>();
|
|
201
|
+
const { t } = useI18n();
|
|
202
|
+
</script>
|
|
203
|
+
|
|
204
|
+
<template>
|
|
205
|
+
<section>
|
|
206
|
+
<h2>{{ t("cart.title") }}</h2>
|
|
207
|
+
<p>{{ t("cart.items", { count: props.count }, props.count) }}</p>
|
|
208
|
+
</section>
|
|
209
|
+
</template>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Số nhiều phân cách bằng dấu gạch đứng (pipe) là định dạng riêng của vue-i18n, không phải ICU. `t` chấp nhận bất kỳ chuỗi nào trừ khi bạn truyền một message schema generic vào `createI18n`.
|
|
213
|
+
|
|
214
|
+
</Tab>
|
|
215
|
+
<Tab label="fluent-vue" value="fluent-vue">
|
|
216
|
+
|
|
217
|
+
<Tabs group="locale">
|
|
218
|
+
<Tab value="en" label="Tiếng Anh">
|
|
219
|
+
|
|
220
|
+
```ftl fileName="src/locales/en.ftl"
|
|
221
|
+
cart-title = Your cart
|
|
222
|
+
cart-items = { $count ->
|
|
223
|
+
[one] { $count } item
|
|
224
|
+
*[other] { $count } items
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
</Tab>
|
|
229
|
+
<Tab value="fr" label="Tiếng Pháp">
|
|
230
|
+
|
|
231
|
+
```ftl fileName="src/locales/fr.ftl"
|
|
232
|
+
cart-title = Votre panier
|
|
233
|
+
cart-items = { $count ->
|
|
234
|
+
[one] { $count } article
|
|
235
|
+
*[other] { $count } articles
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
</Tab>
|
|
240
|
+
<Tab value="es" label="Tiếng Tây Ban Nha">
|
|
241
|
+
|
|
242
|
+
```ftl fileName="src/locales/es.ftl"
|
|
243
|
+
cart-title = Tu carrito
|
|
244
|
+
cart-items = { $count ->
|
|
245
|
+
[one] { $count } artículo
|
|
246
|
+
*[other] { $count } artículos
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
</Tab>
|
|
251
|
+
</Tabs>
|
|
252
|
+
|
|
253
|
+
```vue fileName="src/components/CartSummary.vue"
|
|
254
|
+
<script setup lang="ts">
|
|
255
|
+
import { useFluent } from "fluent-vue";
|
|
256
|
+
|
|
257
|
+
const props = defineProps<{ count: number }>();
|
|
258
|
+
const { $t } = useFluent();
|
|
259
|
+
</script>
|
|
260
|
+
|
|
261
|
+
<template>
|
|
262
|
+
<section>
|
|
263
|
+
<h2>{{ $t("cart-title") }}</h2>
|
|
264
|
+
<p>{{ $t("cart-items", { count: props.count }) }}</p>
|
|
265
|
+
</section>
|
|
266
|
+
</template>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Cú pháp của Fluent xử lý số nhiều và các biến thể ngữ pháp rất tốt. Message id là các chuỗi untyped, và Vite plugin đóng gói mọi locale vào từng trang.
|
|
270
|
+
|
|
271
|
+
</Tab>
|
|
272
|
+
<Tab label="Paraglide" value="paraglide">
|
|
273
|
+
|
|
274
|
+
<Tabs group="locale">
|
|
275
|
+
<Tab value="en" label="Tiếng Anh">
|
|
276
|
+
|
|
277
|
+
```json fileName="messages/en.json"
|
|
278
|
+
{
|
|
279
|
+
"cart_title": "Your cart",
|
|
280
|
+
"cart_items": "{count} items"
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
</Tab>
|
|
285
|
+
<Tab value="fr" label="Tiếng Pháp">
|
|
286
|
+
|
|
287
|
+
```json fileName="messages/fr.json"
|
|
288
|
+
{
|
|
289
|
+
"cart_title": "Votre panier",
|
|
290
|
+
"cart_items": "{count} articles"
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
</Tab>
|
|
295
|
+
<Tab value="es" label="Tiếng Tây Ban Nha">
|
|
296
|
+
|
|
297
|
+
```json fileName="messages/es.json"
|
|
298
|
+
{
|
|
299
|
+
"cart_title": "Tu carrito",
|
|
300
|
+
"cart_items": "{count} artículos"
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
</Tab>
|
|
305
|
+
</Tabs>
|
|
306
|
+
|
|
307
|
+
```vue fileName="src/components/CartSummary.vue"
|
|
308
|
+
<script setup lang="ts">
|
|
309
|
+
import { m } from "../paraglide/messages.js";
|
|
310
|
+
|
|
311
|
+
const props = defineProps<{ count: number }>();
|
|
312
|
+
</script>
|
|
313
|
+
|
|
314
|
+
<template>
|
|
315
|
+
<section>
|
|
316
|
+
<h2>{{ m.cart_title() }}</h2>
|
|
317
|
+
<p>{{ m.cart_items({ count: props.count }) }}</p>
|
|
318
|
+
</section>
|
|
319
|
+
</template>
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Mỗi message là một hàm được sinh ra và có đầy đủ type, vì vậy một key bị thiếu sẽ dẫn đến lỗi import. Thư mục `paraglide/` được sinh trực tiếp vào repo của bạn và được regenerate lại sau mỗi lần thay đổi.
|
|
323
|
+
|
|
324
|
+
</Tab>
|
|
325
|
+
<Tab label="Intlayer" value="intlayer">
|
|
326
|
+
|
|
327
|
+
```ts fileName="src/components/cartSummary.content.ts"
|
|
328
|
+
import { plural, t, type Dictionary } from "intlayer";
|
|
329
|
+
|
|
330
|
+
const cartSummaryContent = {
|
|
331
|
+
key: "cart-summary",
|
|
332
|
+
content: {
|
|
333
|
+
title: t({ en: "Your cart", fr: "Votre panier", es: "Tu carrito" }),
|
|
334
|
+
items: t({
|
|
335
|
+
en: plural({ one: "{{count}} item", other: "{{count}} items" }),
|
|
336
|
+
fr: plural({ one: "{{count}} article", other: "{{count}} articles" }),
|
|
337
|
+
es: plural({ one: "{{count}} artículo", other: "{{count}} artículos" }),
|
|
338
|
+
}),
|
|
339
|
+
},
|
|
340
|
+
} satisfies Dictionary;
|
|
341
|
+
|
|
342
|
+
export default cartSummaryContent;
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
```vue fileName="src/components/CartSummary.vue"
|
|
346
|
+
<script setup lang="ts">
|
|
347
|
+
import { useIntlayer } from "vue-intlayer";
|
|
348
|
+
|
|
349
|
+
const props = defineProps<{ count: number }>();
|
|
350
|
+
const { title, items } = useIntlayer("cart-summary");
|
|
351
|
+
</script>
|
|
352
|
+
|
|
353
|
+
<template>
|
|
354
|
+
<section>
|
|
355
|
+
<h2><title /></h2>
|
|
356
|
+
<p>{{ items(props.count) }}</p>
|
|
357
|
+
</section>
|
|
358
|
+
</template>
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Tất cả các locale nằm trong một file duy nhất cạnh component. Type được sinh ra tại thời điểm build, vì vậy `title` được tự động gợi ý (autocomplete) và lỗi chính tả sẽ khiến `vue-tsc` báo lỗi ngay. `<title />` render một node mà visual editor có thể nhắm tới; `{{ items(props.count) }}` trả về chuỗi văn bản thuần.
|
|
362
|
+
|
|
363
|
+
</Tab>
|
|
364
|
+
</Tabs>
|
|
365
|
+
|
|
366
|
+
Bạn đang sử dụng `vue-i18n`? [Compat adapter `@intlayer/vue-i18n`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/compat/vue-i18n.md) alias package ở cấp độ bundler, nhờ đó `useI18n()`, `$t`, pipe plural và `v-t` tiếp tục hoạt động trong khi Intlayer đảm nhận cung cấp nội dung. [Hướng dẫn di chuyển](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/migration_from_vue-i18n_to_intlayer.md) sẽ hướng dẫn bạn cách gỡ bỏ adapter sau đó, và cũng có [hướng dẫn dành riêng cho Nuxt](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/migration_from_nuxtjs_i18n_to_intlayer.md).
|
|
367
|
+
|
|
368
|
+
## Những điều cần cân nhắc trước khi quyết định
|
|
369
|
+
|
|
370
|
+
Bảng tính năng chỉ cho bạn biết một thư viện có thể làm được gì hôm nay. Những điểm dưới đây cho bạn biết trải nghiệm thực tế khi đồng hành cùng nó sẽ như thế nào.
|
|
371
|
+
|
|
372
|
+
**Kiểm tra mức độ hoạt động của repository.**
|
|
373
|
+
|
|
374
|
+
Các commit, thời gian phản hồi issue, và liệu bản phát hành minor gần nhất có diễn ra trong năm nay hay không. Một thiết kế hoàn hảo nhưng không có người duy trì sẽ sớm trở thành một cuộc di chuyển (migration) bắt buộc trong tương lai.
|
|
375
|
+
|
|
376
|
+
**Đừng chọn thư viện chỉ dựa vào lượt tải trên npm.**
|
|
377
|
+
|
|
378
|
+
Thư viện được cài đặt nhiều nhất là thư viện xuất hiện đầu tiên, không phải thư viện phù hợp nhất cho một codebase Vue năm 2026. Lượt tải phản ánh lịch sử, không phản ánh sự phù hợp.
|
|
379
|
+
|
|
380
|
+

|
|
381
|
+
|
|
382
|
+
**Tìm hiểu xem ai tài trợ cho người duy trì, và họ bán sản phẩm gì.**
|
|
383
|
+
|
|
384
|
+
`vue-i18n` được bảo trợ bởi Crowdin, tương tự như `next-intl` và `svelte-i18n`. `i18next` được bảo trợ bởi Locize. Tolgee, Paraglide (inlang) và Intlayer tự vận hành nền tảng riêng của mình. Một vendor có nguồn thu đến từ dịch vụ lưu trữ bản dịch (hosted translation) ít có lý do để cung cấp bản dịch miễn phí ngay bên trong chuỗi công cụ của bạn. Intlayer là thư viện duy nhất trong nhóm cung cấp tính năng dịch AI qua CLI bằng chính API key của bạn, cùng một CMS mà bạn có thể tự host.
|
|
385
|
+
|
|
386
|
+
**Thư viện đã sẵn sàng cho AI-agent chưa?**
|
|
387
|
+
|
|
388
|
+
Các agent vẫn còn gặp khó khăn với i18n: chúng quên locale, tự tạo key bừa bãi, và trộn lẫn các cú pháp message. Thư viện có cung cấp [Agent Skills](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/agent_skills.md) hoặc một [MCP server](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/mcp_server.md) để agent có thể liệt kê, điền và kiểm thử nội dung hay không? Và việc nạp nội dung có được tối ưu hóa theo mặc định không, hay ai đó phải xem xét lại các namespace và lazy import mỗi quý một lần?
|
|
389
|
+
|
|
390
|
+
**Type safety ngay từ đầu.**
|
|
391
|
+
|
|
392
|
+
Không phải "có thể gõ type nếu cấu hình thêm" mà là "sai key sẽ khiến `tsc` báo lỗi ngay trên một bản cài đặt mới". Hãy kiểm tra xem điều gì sẽ xảy ra khi một key không tồn tại, và khi một locale bị thiếu một bản dịch.
|
|
393
|
+
|
|
394
|
+
**Phát hiện nội dung không sử dụng.**
|
|
395
|
+
|
|
396
|
+
Các catalog chỉ có xu hướng phình to. Quá trình build của Intlayer sẽ loại bỏ các trường không sử dụng và ghi log chúng (`build.purge`). Paraglide đạt được điều này nhờ kiến trúc, vì một hàm message không được gọi sẽ bị tree-shake. Tất cả các giải pháp khác đều để lại công việc dọn dẹp cho bạn.
|
|
397
|
+
|
|
398
|
+
**Trải nghiệm lập trình viên (Developer experience).**
|
|
399
|
+
|
|
400
|
+
Thời gian thiết lập cho đến chuỗi dịch đầu tiên, một [LSP](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/lsp.md) hoặc [tiện ích mở rộng VS Code](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/vs_code_extension.md) hiển thị bản dịch khi hover và nhảy thẳng tới định nghĩa, một [CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/cli/index.md) để fill, test và push, một [trình biên dịch](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/compiler.md) hoặc trình trích xuất lấy các chuỗi hard-code ra khỏi component để bạn không phải quản lý từng chuỗi theo từng khóa, cùng phương thức để người không phải developer có thể chỉnh sửa nội dung ([visual editor](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/intlayer_visual_editor.md) hoặc [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/intlayer_CMS.md)) mà không cần tạo pull request.
|
|
401
|
+
|
|
402
|
+
## Câu hỏi thường gặp
|
|
403
|
+
|
|
404
|
+
<FAQ>
|
|
405
|
+
|
|
406
|
+
<Question title="vue-i18n có còn là lựa chọn mặc định phù hợp trong năm 2026?">
|
|
407
|
+
|
|
408
|
+
Đối với hầu hết các ứng dụng Vue, câu trả lời là có. Hệ sinh thái lớn nhất, tài liệu kỹ lưỡng, và các chi phí đều có thể dự đoán được: runtime nặng, định dạng số nhiều tùy chỉnh, và việc phân tách phạm vi theo route đòi hỏi bạn phải tự xây dựng và kiểm soát.
|
|
409
|
+
|
|
410
|
+
</Question>
|
|
411
|
+
|
|
412
|
+
<Question title="Tôi nên sử dụng @nuxtjs/i18n hay tự cấu hình vue-i18n thủ công trong Nuxt?">
|
|
413
|
+
|
|
414
|
+
Hãy sử dụng module trừ khi việc định tuyến của bạn có yêu cầu đặc biệt hoặc ứng dụng chỉ có rất ít trang. Cấu hình thủ công đồng nghĩa với việc bạn phải tự xây dựng lại locale route, middleware, `hreflang` và sitemap, và những thứ đó phức tạp hơn vẻ bề ngoài rất nhiều.
|
|
415
|
+
|
|
416
|
+
</Question>
|
|
417
|
+
|
|
418
|
+
<Question title="Tôi có cần một thư viện dựa trên compiler không?">
|
|
419
|
+
|
|
420
|
+
Chỉ khi bundle size, SSR payload, type được sinh tự động hoặc kiểm tra thiếu key tại build time là các yêu cầu thực tế của dự án. Bài viết [so sánh i18n compiler và declarative](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/compiler_vs_declarative_i18n.md) giải thích những gì compiler mang lại và những điểm chúng có thể xử lý chưa tối ưu.
|
|
421
|
+
|
|
422
|
+
</Question>
|
|
423
|
+
|
|
424
|
+
<Question title="Việc lựa chọn thư viện có ảnh hưởng đến SEO không?">
|
|
425
|
+
|
|
426
|
+
Ảnh hưởng gián tiếp. Các công cụ tìm kiếm quan tâm đến định tuyến, `hreflang`, `<html lang>` và việc văn bản có nằm trong HTML được render từ server hay không. Xem thêm [hướng dẫn hreflang](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/hreflang_guide_multilingual_seo.md).
|
|
427
|
+
|
|
428
|
+
</Question>
|
|
429
|
+
|
|
430
|
+
</FAQ>
|
|
431
|
+
|
|
432
|
+
## Tìm hiểu thêm
|
|
433
|
+
|
|
434
|
+
- [Benchmark Vue i18n: bundle size, độ rò rỉ và thời gian chuyển đổi locale](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/benchmark/vue.md)
|
|
435
|
+
- [Vue i18n: cách vue-i18n hoạt động và những điểm bất cập](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/list_i18n_technologies/frameworks/vue.md) và [bài viết về Nuxt i18n](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/list_i18n_technologies/frameworks/nuxt.md)
|
|
436
|
+
- [vue-i18n so với Intlayer, từng tính năng chi tiết](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/vue-i18n_vs_intlayer.md) và [benchmark vue-i18n so với Intlayer](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/vue-i18n_vs_intlayer_benchmark.md)
|
|
437
|
+
- [vue-i18n có lỗi thời không?](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/is_vue-i18n_outdated.md)
|
|
438
|
+
- [Lịch sử của JavaScript i18n](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/history_of_i18n.md)
|
|
439
|
+
- [So sánh i18n compiler và declarative](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/compiler_vs_declarative_i18n.md)
|
|
440
|
+
- [i18n theo từng component so với tập trung](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/per-component_vs_centralized_i18n.md)
|
|
441
|
+
- [Cài đặt i18n trong ứng dụng Vite + Vue](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/intlayer_with_vite+vue.md) và trong [ứng dụng Nuxt](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/intlayer_with_nuxt.md)
|
|
442
|
+
- Cùng hướng dẫn cho [React](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/how_to_pick_react_i18n_library.md), [Svelte](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/how_to_pick_svelte_i18n_library.md) và [Solid](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/how_to_pick_solid_i18n_library.md)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-09-02
|
|
3
|
-
updatedAt: 2026-09-
|
|
3
|
+
updatedAt: 2026-09-16
|
|
4
4
|
title: Liệu i18next Đã Lỗi Thời Vào Năm 2026?
|
|
5
5
|
description: i18next đang vận hành hàng triệu trang web, nhưng kiến trúc runtime từ năm 2011 đang bộc lộ giới hạn. Phân tích về dung lượng bundle, hạn chế tree-shaking và tốc độ đổi mới.
|
|
6
6
|
keywords:
|
|
@@ -125,6 +125,10 @@ Trên Next.js, `next-i18next` thêm vào **76.7 KB gzipped** so với ứng dụ
|
|
|
125
125
|
|
|
126
126
|
Theo mặc định, khoảng **90% văn bản dịch** gửi tới một route thực chất thuộc về các trang khác. Việc phân chia namespace thủ công tốn nhiều công sức và rất dễ phát sinh lỗi sót từ khóa.
|
|
127
127
|
|
|
128
|
+
Biểu đồ dưới đây ước tính dung lượng nội dung cho một ứng dụng giả định gồm 1 đến 10 trang, được dịch sang 1 đến 10 ngôn ngữ, với khoảng 30 KB văn bản mỗi trang. Tải nội dung động theo locale loại bỏ trục ngôn ngữ, giới hạn nội dung theo component hoặc route loại bỏ trục trang, và chỉ khi kết hợp cả hai thì dung lượng mới giữ nguyên.
|
|
129
|
+
|
|
130
|
+

|
|
131
|
+
|
|
128
132
|
**Độ trễ hydration:**
|
|
129
133
|
|
|
130
134
|
Component sử dụng `react-i18next` mất tới **85 ms** để hoàn tất hydration, so với chỉ **24 ms** ở Intlayer. Việc chuyển giao các cây JSON khổng lồ tới component client làm chậm khả năng tương tác ban đầu.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-09-02
|
|
3
|
-
updatedAt: 2026-09-
|
|
3
|
+
updatedAt: 2026-09-16
|
|
4
4
|
title: Liệu next-intl Đã Lỗi Thời Vào Năm 2026?
|
|
5
5
|
description: next-intl đã trở thành lựa chọn phổ biến cho Next.js App Router. Nhưng nó vẫn mang gánh nặng bundle lúc runtime và yêu cầu quản lý namespace thủ công.
|
|
6
6
|
keywords:
|
|
@@ -127,6 +127,10 @@ Bởi vì `messages` được đưa vào client provider ở cấp cao nhất, t
|
|
|
127
127
|
|
|
128
128
|
Có thể giảm bớt điều này bằng cách chia nhỏ file JSON thành các namespace. Tuy nhiên, việc tự quản lý ánh xạ này tốn nhiều công sức và rất dễ bỏ sót.
|
|
129
129
|
|
|
130
|
+
Biểu đồ dưới đây ước tính dung lượng nội dung cho một ứng dụng giả định gồm 1 đến 10 trang, được dịch sang 1 đến 10 ngôn ngữ, với khoảng 30 KB văn bản mỗi trang. Tải nội dung động theo locale loại bỏ trục ngôn ngữ, giới hạn nội dung theo component hoặc route loại bỏ trục trang, và chỉ khi kết hợp cả hai thì dung lượng mới giữ nguyên.
|
|
131
|
+
|
|
132
|
+

|
|
133
|
+
|
|
130
134
|
Intlayer giải quyết vấn đề bằng phân tích tĩnh: [trình biên dịch Intlayer](https://intlayer.org/vi/doc/compiler) chỉ đóng gói những nội dung thực sự được gọi trên route đó, đưa tỷ lệ rò rỉ giữa các trang về mức **0.0%**.
|
|
131
135
|
|
|
132
136
|
## Tại Sao next-intl Không Thể Tree-Shaking?
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-09-02
|
|
3
|
-
updatedAt: 2026-09-
|
|
3
|
+
updatedAt: 2026-09-16
|
|
4
4
|
title: Liệu vue-i18n Đã Lỗi Thời Vào Năm 2026?
|
|
5
5
|
description: vue-i18n là chuẩn mực cho Vue và Nuxt suốt cả thập kỷ. Nhưng trong các bài kiểm tra benchmark, nó lại là runtime i18n nặng nhất trên web. Tìm hiểu nguyên nhân tại đây.
|
|
6
6
|
keywords:
|
|
@@ -116,6 +116,12 @@ Theo mặc định, **90% dữ liệu dịch** được gửi tới một route
|
|
|
116
116
|
|
|
117
117
|
Các component có phạm vi dịch cục bộ đạt kích thước trung bình 196 KB ở `vue-i18n` do trùng lặp từ điển, so với chỉ **6.5 KB** khi dùng Intlayer.
|
|
118
118
|
|
|
119
|
+
**Rò rỉ tăng như thế nào:**
|
|
120
|
+
|
|
121
|
+
Biểu đồ dưới đây ước tính dung lượng nội dung cho một ứng dụng giả định gồm 1 đến 10 trang, được dịch sang 1 đến 10 ngôn ngữ, với khoảng 30 KB văn bản mỗi trang. Tải nội dung động theo locale loại bỏ trục ngôn ngữ, giới hạn nội dung theo component hoặc route loại bỏ trục trang, và chỉ khi kết hợp cả hai thì dung lượng mới giữ nguyên.
|
|
122
|
+
|
|
123
|
+

|
|
124
|
+
|
|
119
125
|
## Tại Sao vue-i18n Lại Nặng?
|
|
120
126
|
|
|
121
127
|
### Trình Biên Dịch AST Bị Gửi Xuống Trình Duyệt
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2025-08-23
|
|
3
|
-
updatedAt: 2026-
|
|
3
|
+
updatedAt: 2026-09-16
|
|
4
4
|
title: "next-i18next vs next-intl vs Intlayer - Hướng dẫn đầy đủ để dịch next-i18next vs next-intl vs Intlayer: 2026 Comparison"
|
|
5
5
|
description: Giải pháp tốt nhất cho kích thước bundle, SEO, hiệu suất & khả năng bảo trì. Làm cho Next.js trang web của bạn đa ngôn ngữ vào năm 2026, dịch thuật LLM, Agent Skills & MCP.
|
|
6
6
|
keywords:
|
|
@@ -20,7 +20,7 @@ author: aymericzip
|
|
|
20
20
|
|
|
21
21
|
# next-i18next VS next-intl VS intlayer | Quốc tế hóa Next.js (i18n)
|
|
22
22
|
|
|
23
|
-

|
|
24
24
|
|
|
25
25
|
Hãy cùng xem xét những điểm tương đồng và khác biệt giữa ba lựa chọn i18n cho Next.js: next-i18next, next-intl và Intlayer.
|
|
26
26
|
|
|
@@ -126,6 +126,10 @@ Hai vấn đề quan trọng:
|
|
|
126
126
|
|
|
127
127
|
> Nếu tôi đang ở trang `/fr/about`, tôi không muốn tải nội dung của trang `/en/about`
|
|
128
128
|
|
|
129
|
+
Biểu đồ dưới đây ước tính dung lượng nội dung cho một ứng dụng giả định gồm 1 đến 10 trang, được dịch sang 1 đến 10 ngôn ngữ, với khoảng 30 KB văn bản mỗi trang. Tải nội dung động theo locale loại bỏ trục ngôn ngữ, giới hạn nội dung theo component hoặc route loại bỏ trục trang, và chỉ khi kết hợp cả hai thì dung lượng mới giữ nguyên.
|
|
130
|
+
|
|
131
|
+

|
|
132
|
+
|
|
129
133
|
Một lần nữa, cả ba giải pháp đều nhận thức được những vấn đề này và cho phép quản lý các tối ưu hóa này. Sự khác biệt giữa ba giải pháp là trải nghiệm nhà phát triển (DX).
|
|
130
134
|
|
|
131
135
|
`next-intl` và `next-i18next` sử dụng phương pháp tập trung để quản lý bản dịch, cho phép phân tách JSON theo locale và theo các tệp con. Trong `next-i18next`, chúng ta gọi các tệp JSON là 'namespaces'; `next-intl` cho phép khai báo các messages. Trong `intlayer`, chúng ta gọi các tệp JSON là 'dictionaries'.
|
|
@@ -150,9 +154,9 @@ Trong trường hợp của `next-intl` và `next-i18next`, thư viện yêu c
|
|
|
150
154
|
|
|
151
155
|
Dưới đây là ví dụ về tác động của việc tối ưu kích thước bundle sử dụng `intlayer` trong ứng dụng vite + react:
|
|
152
156
|
|
|
153
|
-
| Gói tối ưu hóa
|
|
154
|
-
|
|
|
155
|
-
|  |  |
|
|
156
160
|
|
|
157
161
|
## TypeScript & an toàn
|
|
158
162
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2025-09-10
|
|
3
|
-
updatedAt:
|
|
3
|
+
updatedAt: 2026-09-16
|
|
4
4
|
title: "i18n theo thành phần so với i18n tập trung: Một cách tiếp cận mới với Intlayer"
|
|
5
5
|
description: Phân tích sâu các chiến lược quốc tế hóa trong React, so sánh các phương pháp tập trung, theo khóa và theo thành phần, và giới thiệu Intlayer.
|
|
6
6
|
keywords:
|
|
@@ -63,6 +63,7 @@ Tuy nhiên, trong thế giới React, chúng ta chủ yếu thấy các cách ti
|
|
|
63
63
|
- phân nhỏ việc truy xuất nội dung theo key, hoặc theo component.
|
|
64
64
|
|
|
65
65
|
</Column>
|
|
66
|
+
|
|
66
67
|
</Columns>
|
|
67
68
|
|
|
68
69
|
> Trong blog này, tôi sẽ không tập trung vào các giải pháp dựa trên compiler, những cái tôi đã đề cập ở đây: [Compiler vs Declarative i18n](https://github.com/aymericzip/intlayer/blob/main/docs/blog/vi/compiler_vs_declarative_i18n.md).
|
|
@@ -79,6 +80,10 @@ So, broadly speaking, the decision breaks down like this:
|
|
|
79
80
|
|
|
80
81
|
Tất nhiên, các tác giả thư viện nhận thức được những giới hạn này và cung cấp các cách khắc phục. Trong số đó: tách thành namespaces, tải động các file JSON (`await import()`), hoặc loại bỏ (purge) nội dung trong quá trình build.
|
|
81
82
|
|
|
83
|
+
Biểu đồ dưới đây ước tính dung lượng nội dung cho một ứng dụng giả định gồm 1 đến 10 trang, được dịch sang 1 đến 10 ngôn ngữ, với khoảng 30 KB văn bản mỗi trang. Tải nội dung động theo locale loại bỏ trục ngôn ngữ, giới hạn nội dung theo component hoặc route loại bỏ trục trang, và chỉ khi kết hợp cả hai thì dung lượng mới giữ nguyên.
|
|
84
|
+
|
|
85
|
+

|
|
86
|
+
|
|
82
87
|
Đồng thời, bạn cần biết rằng khi bạn tải nội dung một cách động, bạn sẽ tạo thêm các yêu cầu tới server. Mỗi `useState` bổ sung hoặc hook đồng nghĩa với một yêu cầu server thêm.
|
|
83
88
|
|
|
84
89
|
> Để khắc phục vấn đề này, Intlayer đề xuất gom nhiều định nghĩa nội dung dưới cùng một khóa; Intlayer sau đó sẽ hợp nhất những nội dung đó.
|
|
@@ -111,9 +116,9 @@ Chắc chắn, và đó là một bước tiến lớn. Hãy xem so sánh kích
|
|
|
111
116
|
|
|
112
117
|
Ví dụ đầu tiên không bao gồm việc lazy-load các bản dịch theo locale và không tách namespace. Ví dụ thứ hai bao gồm content purging + tải động các bản dịch.
|
|
113
118
|
|
|
114
|
-
| Bundle tối ưu hóa
|
|
115
|
-
|
|
|
116
|
-
|  |  |
|
|
117
122
|
|
|
118
123
|
Nhờ có namespaces, chúng ta đã chuyển từ cấu trúc này:
|
|
119
124
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2025-01-02
|
|
3
|
-
updatedAt:
|
|
3
|
+
updatedAt: 2026-09-16
|
|
4
4
|
title: react-i18next vs react-intl vs Intlayer
|
|
5
5
|
description: Tích hợp react-i18next với next-intl và Intlayer cho việc quốc tế hóa (i18n) của ứng dụng React
|
|
6
6
|
keywords:
|
|
@@ -106,6 +106,10 @@ Chúng tôi đánh giá:
|
|
|
106
106
|
|
|
107
107
|
**Tại sao điều này quan trọng:** Gói nhỏ hơn và ít chuỗi không sử dụng giúp cải thiện hiệu suất khởi động và điều hướng.
|
|
108
108
|
|
|
109
|
+
Biểu đồ dưới đây ước tính dung lượng nội dung cho một ứng dụng giả định gồm 1 đến 10 trang, được dịch sang 1 đến 10 ngôn ngữ, với khoảng 30 KB văn bản mỗi trang. Tải nội dung động theo locale loại bỏ trục ngôn ngữ, giới hạn nội dung theo component hoặc route loại bỏ trục trang, và chỉ khi kết hợp cả hai thì dung lượng mới giữ nguyên.
|
|
110
|
+
|
|
111
|
+

|
|
112
|
+
|
|
109
113
|
### 6) DX, công cụ & bảo trì
|
|
110
114
|
|
|
111
115
|
- **react-intl / react-i18next**: Hệ sinh thái cộng đồng rộng lớn; đối với quy trình biên tập, bạn thường sử dụng các nền tảng nội địa hóa bên ngoài.
|