@intlayer/docs 9.5.2 → 9.5.3
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 +1 -1
- package/blog/ar/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/ar/i18next_vs_intlayer.md +445 -0
- package/blog/ar/is_i18next_outdated.md +1 -1
- package/blog/ar/is_next-intl_outdated.md +1 -1
- package/blog/ar/is_vue-i18n_outdated.md +1 -1
- package/blog/ar/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/ar/lingui_vs_intlayer.md +381 -0
- package/blog/ar/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/ar/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/ar/next-intl_vs_intlayer.md +397 -0
- package/blog/ar/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/ar/vue-i18n_vs_intlayer-vue-i18n.md +286 -0
- package/blog/ar/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/de/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/de/i18next_vs_intlayer.md +445 -0
- package/blog/de/is_i18next_outdated.md +1 -1
- package/blog/de/is_next-intl_outdated.md +1 -1
- package/blog/de/is_vue-i18n_outdated.md +1 -1
- package/blog/de/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/de/lingui_vs_intlayer.md +381 -0
- package/blog/de/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/de/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/de/next-intl_vs_intlayer.md +415 -0
- package/blog/de/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/de/vue-i18n_vs_intlayer_benchmark.md +355 -0
- package/blog/en/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/en/i18next_vs_intlayer.md +445 -0
- package/blog/en/is_i18next_outdated.md +1 -1
- package/blog/en/is_next-intl_outdated.md +1 -1
- package/blog/en/is_vue-i18n_outdated.md +1 -1
- package/blog/en/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/en/lingui_vs_intlayer.md +381 -0
- package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/en/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/en/next-intl_vs_intlayer.md +415 -0
- package/blog/en/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/en/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/en/vue-i18n_vs_intlayer.md +1 -1
- package/blog/en/vue-i18n_vs_intlayer_benchmark.md +361 -0
- package/blog/en-GB/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/en-GB/i18next_vs_intlayer.md +445 -0
- package/blog/en-GB/is_i18next_outdated.md +1 -1
- package/blog/en-GB/is_next-intl_outdated.md +1 -1
- package/blog/en-GB/is_vue-i18n_outdated.md +1 -1
- package/blog/en-GB/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/en-GB/lingui_vs_intlayer.md +381 -0
- package/blog/en-GB/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/en-GB/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/en-GB/next-intl_vs_intlayer.md +415 -0
- package/blog/en-GB/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/en-GB/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/en-GB/vue-i18n_vs_intlayer.md +1 -1
- package/blog/en-GB/vue-i18n_vs_intlayer_benchmark.md +245 -0
- package/blog/es/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/es/i18next_vs_intlayer.md +445 -0
- package/blog/es/is_i18next_outdated.md +1 -1
- package/blog/es/is_next-intl_outdated.md +1 -1
- package/blog/es/is_vue-i18n_outdated.md +1 -1
- package/blog/es/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/es/lingui_vs_intlayer.md +381 -0
- package/blog/es/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/es/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/es/next-intl_vs_intlayer.md +417 -0
- package/blog/es/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/es/vue-i18n_vs_intlayer_benchmark.md +363 -0
- package/blog/fr/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/fr/i18next_vs_intlayer.md +445 -0
- package/blog/fr/is_i18next_outdated.md +1 -1
- package/blog/fr/is_next-intl_outdated.md +1 -1
- package/blog/fr/is_vue-i18n_outdated.md +1 -1
- package/blog/fr/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/fr/lingui_vs_intlayer.md +381 -0
- package/blog/fr/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/fr/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/fr/next-intl_vs_intlayer.md +417 -0
- package/blog/fr/vue-i18n_vs_intlayer-vue-i18n.md +287 -0
- package/blog/fr/vue-i18n_vs_intlayer_benchmark.md +39 -0
- package/blog/hi/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/hi/i18next_vs_intlayer.md +445 -0
- package/blog/hi/is_i18next_outdated.md +1 -1
- package/blog/hi/is_next-intl_outdated.md +1 -1
- package/blog/hi/is_vue-i18n_outdated.md +1 -1
- package/blog/hi/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/hi/lingui_vs_intlayer.md +381 -0
- package/blog/hi/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/hi/next-intl_vs_intlayer.md +397 -0
- package/blog/hi/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/hi/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/hi/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/id/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/id/i18next_vs_intlayer.md +445 -0
- package/blog/id/is_i18next_outdated.md +1 -1
- package/blog/id/is_next-intl_outdated.md +1 -1
- package/blog/id/is_vue-i18n_outdated.md +1 -1
- package/blog/id/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/id/lingui_vs_intlayer.md +381 -0
- package/blog/id/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/id/next-intl_vs_intlayer-next-intl.md +310 -0
- package/blog/id/next-intl_vs_intlayer.md +397 -0
- package/blog/id/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/id/vue-i18n_vs_intlayer-vue-i18n.md +36 -0
- package/blog/id/vue-i18n_vs_intlayer.md +1 -1
- package/blog/id/vue-i18n_vs_intlayer_benchmark.md +41 -0
- package/blog/it/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/it/i18next_vs_intlayer.md +445 -0
- package/blog/it/is_i18next_outdated.md +1 -1
- package/blog/it/is_next-intl_outdated.md +1 -1
- package/blog/it/is_vue-i18n_outdated.md +1 -1
- package/blog/it/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/it/lingui_vs_intlayer.md +381 -0
- package/blog/it/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/it/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/it/next-intl_vs_intlayer.md +418 -0
- package/blog/it/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/it/vue-i18n_vs_intlayer_benchmark.md +34 -0
- package/blog/ja/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/ja/i18next_vs_intlayer.md +447 -0
- package/blog/ja/is_i18next_outdated.md +1 -1
- package/blog/ja/is_next-intl_outdated.md +1 -1
- package/blog/ja/is_vue-i18n_outdated.md +1 -1
- package/blog/ja/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/ja/lingui_vs_intlayer.md +381 -0
- package/blog/ja/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/ja/next-intl_vs_intlayer-next-intl.md +310 -0
- package/blog/ja/next-intl_vs_intlayer.md +422 -0
- package/blog/ja/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/ja/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/ja/vue-i18n_vs_intlayer.md +1 -1
- package/blog/ja/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/ko/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/ko/i18next_vs_intlayer.md +447 -0
- package/blog/ko/is_i18next_outdated.md +1 -1
- package/blog/ko/is_next-intl_outdated.md +1 -1
- package/blog/ko/is_vue-i18n_outdated.md +1 -1
- package/blog/ko/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/ko/lingui_vs_intlayer.md +381 -0
- package/blog/ko/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/ko/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/ko/next-intl_vs_intlayer.md +397 -0
- package/blog/ko/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/ko/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/ko/vue-i18n_vs_intlayer.md +1 -1
- package/blog/ko/vue-i18n_vs_intlayer_benchmark.md +366 -0
- package/blog/pl/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/pl/i18next_vs_intlayer.md +445 -0
- package/blog/pl/is_i18next_outdated.md +1 -1
- package/blog/pl/is_next-intl_outdated.md +1 -1
- package/blog/pl/is_vue-i18n_outdated.md +1 -1
- package/blog/pl/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/pl/lingui_vs_intlayer.md +381 -0
- package/blog/pl/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/pl/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/pl/next-intl_vs_intlayer.md +397 -0
- package/blog/pl/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/pl/vue-i18n_vs_intlayer-vue-i18n.md +289 -0
- package/blog/pl/vue-i18n_vs_intlayer.md +1 -1
- package/blog/pl/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/pt/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/pt/i18next_vs_intlayer.md +445 -0
- package/blog/pt/is_i18next_outdated.md +1 -1
- package/blog/pt/is_next-intl_outdated.md +1 -1
- package/blog/pt/is_vue-i18n_outdated.md +1 -1
- package/blog/pt/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/pt/lingui_vs_intlayer.md +381 -0
- package/blog/pt/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/pt/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/pt/next-intl_vs_intlayer.md +411 -0
- package/blog/pt/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/pt/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/ru/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/ru/i18next_vs_intlayer.md +445 -0
- package/blog/ru/is_i18next_outdated.md +1 -1
- package/blog/ru/is_next-intl_outdated.md +1 -1
- package/blog/ru/is_vue-i18n_outdated.md +1 -1
- package/blog/ru/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/ru/lingui_vs_intlayer.md +381 -0
- package/blog/ru/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/ru/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/ru/next-intl_vs_intlayer.md +417 -0
- package/blog/ru/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/ru/vue-i18n_vs_intlayer_benchmark.md +54 -0
- package/blog/tr/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/tr/i18next_vs_intlayer.md +445 -0
- package/blog/tr/is_i18next_outdated.md +1 -1
- package/blog/tr/is_next-intl_outdated.md +1 -1
- package/blog/tr/is_vue-i18n_outdated.md +1 -1
- package/blog/tr/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/tr/lingui_vs_intlayer.md +381 -0
- package/blog/tr/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/tr/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/tr/next-intl_vs_intlayer.md +397 -0
- package/blog/tr/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/tr/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/tr/vue-i18n_vs_intlayer.md +1 -1
- package/blog/tr/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/uk/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/uk/i18next_vs_intlayer.md +445 -0
- package/blog/uk/is_i18next_outdated.md +1 -1
- package/blog/uk/is_next-intl_outdated.md +1 -1
- package/blog/uk/is_vue-i18n_outdated.md +1 -1
- package/blog/uk/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/uk/lingui_vs_intlayer.md +381 -0
- package/blog/uk/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/uk/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/uk/next-intl_vs_intlayer.md +397 -0
- package/blog/uk/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/uk/vue-i18n_vs_intlayer-vue-i18n.md +270 -0
- package/blog/uk/vue-i18n_vs_intlayer.md +1 -1
- package/blog/uk/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/vi/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/vi/i18next_vs_intlayer.md +445 -0
- package/blog/vi/is_i18next_outdated.md +1 -1
- package/blog/vi/is_next-intl_outdated.md +1 -1
- package/blog/vi/is_vue-i18n_outdated.md +1 -1
- package/blog/vi/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/vi/lingui_vs_intlayer.md +381 -0
- package/blog/vi/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/vi/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/vi/next-intl_vs_intlayer.md +397 -0
- package/blog/vi/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/vi/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/vi/vue-i18n_vs_intlayer.md +1 -1
- package/blog/vi/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/zh/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/zh/i18next_vs_intlayer.md +445 -0
- package/blog/zh/is_i18next_outdated.md +1 -1
- package/blog/zh/is_next-intl_outdated.md +1 -1
- package/blog/zh/is_vue-i18n_outdated.md +1 -1
- package/blog/zh/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/zh/lingui_vs_intlayer.md +381 -0
- package/blog/zh/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/zh/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/zh/next-intl_vs_intlayer.md +422 -0
- package/blog/zh/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/zh/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/zh/vue-i18n_vs_intlayer.md +1 -1
- package/blog/zh/vue-i18n_vs_intlayer_benchmark.md +30 -0
- package/dist/cjs/generated/blog.entry.cjs +160 -0
- package/dist/cjs/generated/blog.entry.cjs.map +1 -1
- package/dist/cjs/generated/frequentQuestions.entry.cjs +20 -0
- package/dist/cjs/generated/frequentQuestions.entry.cjs.map +1 -1
- package/dist/esm/generated/blog.entry.mjs +160 -0
- package/dist/esm/generated/blog.entry.mjs.map +1 -1
- package/dist/esm/generated/frequentQuestions.entry.mjs +20 -0
- package/dist/esm/generated/frequentQuestions.entry.mjs.map +1 -1
- package/dist/types/generated/blog.entry.d.ts +8 -0
- package/dist/types/generated/blog.entry.d.ts.map +1 -1
- package/dist/types/generated/frequentQuestions.entry.d.ts +1 -0
- package/dist/types/generated/frequentQuestions.entry.d.ts.map +1 -1
- package/docs/ar/benchmark/nextjs.md +1 -1
- package/docs/ar/benchmark/solid.md +1 -1
- package/docs/ar/benchmark/svelte.md +1 -1
- package/docs/ar/benchmark/tanstack.md +1 -1
- package/docs/ar/benchmark/vue.md +1 -1
- package/docs/ar/interest_of_intlayer.md +1 -1
- package/docs/bn/interest_of_intlayer.md +1 -1
- package/docs/cs/interest_of_intlayer.md +1 -1
- package/docs/de/benchmark/nextjs.md +1 -1
- package/docs/de/benchmark/solid.md +1 -1
- package/docs/de/benchmark/svelte.md +1 -1
- package/docs/de/benchmark/tanstack.md +1 -1
- package/docs/de/benchmark/vue.md +1 -1
- package/docs/de/interest_of_intlayer.md +1 -1
- package/docs/en/benchmark/nextjs.md +1 -1
- package/docs/en/benchmark/solid.md +1 -1
- package/docs/en/benchmark/svelte.md +1 -1
- package/docs/en/benchmark/tanstack.md +1 -1
- package/docs/en/benchmark/vue.md +1 -1
- package/docs/en/interest_of_intlayer.md +1 -1
- package/docs/en-GB/benchmark/nextjs.md +1 -1
- package/docs/en-GB/benchmark/solid.md +1 -1
- package/docs/en-GB/benchmark/svelte.md +1 -1
- package/docs/en-GB/benchmark/tanstack.md +1 -1
- package/docs/en-GB/benchmark/vue.md +1 -1
- package/docs/en-GB/interest_of_intlayer.md +1 -1
- package/docs/es/benchmark/nextjs.md +1 -1
- package/docs/es/benchmark/solid.md +1 -1
- package/docs/es/benchmark/svelte.md +1 -1
- package/docs/es/benchmark/tanstack.md +1 -1
- package/docs/es/benchmark/vue.md +1 -1
- package/docs/es/interest_of_intlayer.md +1 -1
- package/docs/fr/benchmark/nextjs.md +1 -1
- package/docs/fr/benchmark/solid.md +1 -1
- package/docs/fr/benchmark/svelte.md +1 -1
- package/docs/fr/benchmark/tanstack.md +1 -1
- package/docs/fr/benchmark/vue.md +1 -1
- package/docs/fr/interest_of_intlayer.md +1 -1
- package/docs/hi/benchmark/nextjs.md +1 -1
- package/docs/hi/benchmark/solid.md +1 -1
- package/docs/hi/benchmark/svelte.md +1 -1
- package/docs/hi/benchmark/tanstack.md +1 -1
- package/docs/hi/benchmark/vue.md +1 -1
- package/docs/hi/interest_of_intlayer.md +1 -1
- package/docs/id/benchmark/nextjs.md +1 -1
- package/docs/id/benchmark/solid.md +1 -1
- package/docs/id/benchmark/svelte.md +1 -1
- package/docs/id/benchmark/tanstack.md +1 -1
- package/docs/id/benchmark/vue.md +1 -1
- package/docs/id/interest_of_intlayer.md +1 -1
- package/docs/it/benchmark/nextjs.md +1 -1
- package/docs/it/benchmark/solid.md +1 -1
- package/docs/it/benchmark/svelte.md +1 -1
- package/docs/it/benchmark/tanstack.md +1 -1
- package/docs/it/benchmark/vue.md +1 -1
- package/docs/it/interest_of_intlayer.md +1 -1
- package/docs/ja/benchmark/nextjs.md +1 -1
- package/docs/ja/benchmark/solid.md +1 -1
- package/docs/ja/benchmark/svelte.md +1 -1
- package/docs/ja/benchmark/tanstack.md +1 -1
- package/docs/ja/benchmark/vue.md +1 -1
- package/docs/ja/interest_of_intlayer.md +1 -1
- package/docs/ko/benchmark/nextjs.md +1 -1
- package/docs/ko/benchmark/solid.md +1 -1
- package/docs/ko/benchmark/svelte.md +1 -1
- package/docs/ko/benchmark/tanstack.md +1 -1
- package/docs/ko/benchmark/vue.md +1 -1
- package/docs/ko/interest_of_intlayer.md +1 -1
- package/docs/nl/interest_of_intlayer.md +1 -1
- package/docs/pl/benchmark/nextjs.md +1 -1
- package/docs/pl/benchmark/solid.md +1 -1
- package/docs/pl/benchmark/svelte.md +1 -1
- package/docs/pl/benchmark/tanstack.md +1 -1
- package/docs/pl/benchmark/vue.md +1 -1
- package/docs/pl/interest_of_intlayer.md +1 -1
- package/docs/pt/benchmark/nextjs.md +1 -1
- package/docs/pt/benchmark/solid.md +1 -1
- package/docs/pt/benchmark/svelte.md +1 -1
- package/docs/pt/benchmark/tanstack.md +1 -1
- package/docs/pt/benchmark/vue.md +1 -1
- package/docs/pt/interest_of_intlayer.md +1 -1
- package/docs/ru/benchmark/nextjs.md +1 -1
- package/docs/ru/benchmark/solid.md +1 -1
- package/docs/ru/benchmark/svelte.md +1 -1
- package/docs/ru/benchmark/tanstack.md +1 -1
- package/docs/ru/benchmark/vue.md +1 -1
- package/docs/ru/interest_of_intlayer.md +1 -1
- package/docs/tr/benchmark/nextjs.md +1 -1
- package/docs/tr/benchmark/solid.md +1 -1
- package/docs/tr/benchmark/svelte.md +1 -1
- package/docs/tr/benchmark/tanstack.md +1 -1
- package/docs/tr/benchmark/vue.md +1 -1
- package/docs/tr/interest_of_intlayer.md +1 -1
- package/docs/uk/benchmark/nextjs.md +1 -1
- package/docs/uk/benchmark/solid.md +1 -1
- package/docs/uk/benchmark/svelte.md +1 -1
- package/docs/uk/benchmark/tanstack.md +1 -1
- package/docs/uk/benchmark/vue.md +1 -1
- package/docs/uk/interest_of_intlayer.md +1 -1
- package/docs/ur/interest_of_intlayer.md +1 -1
- package/docs/vi/benchmark/nextjs.md +1 -1
- package/docs/vi/benchmark/solid.md +1 -1
- package/docs/vi/benchmark/svelte.md +1 -1
- package/docs/vi/benchmark/tanstack.md +1 -1
- package/docs/vi/benchmark/vue.md +1 -1
- package/docs/vi/interest_of_intlayer.md +1 -1
- package/docs/zh/benchmark/nextjs.md +1 -1
- package/docs/zh/benchmark/solid.md +1 -1
- package/docs/zh/benchmark/svelte.md +1 -1
- package/docs/zh/benchmark/tanstack.md +1 -1
- package/docs/zh/benchmark/vue.md +1 -1
- package/docs/zh/interest_of_intlayer.md +1 -1
- package/docs/zh-TW/interest_of_intlayer.md +1 -1
- package/frequent_questions/ar/claude_code_token_consumption.md +152 -0
- package/frequent_questions/de/claude_code_token_consumption.md +152 -0
- package/frequent_questions/en/claude_code_token_consumption.md +152 -0
- package/frequent_questions/en-GB/claude_code_token_consumption.md +152 -0
- package/frequent_questions/es/claude_code_token_consumption.md +152 -0
- package/frequent_questions/fr/claude_code_token_consumption.md +152 -0
- package/frequent_questions/hi/claude_code_token_consumption.md +152 -0
- package/frequent_questions/id/claude_code_token_consumption.md +152 -0
- package/frequent_questions/it/claude_code_token_consumption.md +152 -0
- package/frequent_questions/ja/claude_code_token_consumption.md +152 -0
- package/frequent_questions/ko/claude_code_token_consumption.md +152 -0
- package/frequent_questions/pl/claude_code_token_consumption.md +152 -0
- package/frequent_questions/pt/claude_code_token_consumption.md +152 -0
- package/frequent_questions/ru/claude_code_token_consumption.md +152 -0
- package/frequent_questions/tr/claude_code_token_consumption.md +152 -0
- package/frequent_questions/uk/claude_code_token_consumption.md +152 -0
- package/frequent_questions/vi/claude_code_token_consumption.md +152 -0
- package/frequent_questions/zh/claude_code_token_consumption.md +152 -0
- package/package.json +6 -6
- package/src/generated/blog.entry.ts +160 -0
- package/src/generated/frequentQuestions.entry.ts +20 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-09-13
|
|
3
|
+
updatedAt: 2026-09-13
|
|
4
|
+
title: "next-intl مقابل Intlayer: معيار ومقارنة 2026"
|
|
5
|
+
description: "مقارنة دقيقة بين next-intl وIntlayer على Next.js App Router وTanStack Start. حجم الحزمة، تسرب المحتوى، حجم المكونات، وسرعة تبديل اللغة وتجربة المطور."
|
|
6
|
+
keywords:
|
|
7
|
+
- next-intl
|
|
8
|
+
- use-intl
|
|
9
|
+
- Intlayer
|
|
10
|
+
- Internationalization
|
|
11
|
+
- i18n
|
|
12
|
+
- Benchmark
|
|
13
|
+
- Bundle size
|
|
14
|
+
- Next.js
|
|
15
|
+
- TanStack Start
|
|
16
|
+
- React
|
|
17
|
+
slugs:
|
|
18
|
+
- blog
|
|
19
|
+
- next-intl-vs-intlayer
|
|
20
|
+
author: aymericzip
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# next-intl مقابل Intlayer | مقارنة أداء التدويل (i18n) في React وNext.js
|
|
24
|
+
|
|
25
|
+
مكتبة `next-intl` هي الخيار الافتراضي لتدويل تطبيقات Next.js App Router اليوم: تكامل محكم مع التوجيه، دعم كامل لـ ICU MessageFormat، وتجربة مطور مألوفة لأي شخص استخدم أنظمة i18n الكلاسيكية.
|
|
26
|
+
|
|
27
|
+
أما `Intlayer` فتعيد التفكير في المشكلة من أساسها: لا توجد قواميس مركزية، ولا حاجة لمطابقة مساحات الأسماء (namespaces) مع المسارات يدوياً. يتم الإعلان عن المحتوى بجانب كل مكون، بينما يتكفل مترجم وقت البناء بحزم ما تحتاجه كل صفحة فقط.
|
|
28
|
+
|
|
29
|
+
تقارن هذه المقالة المكتبتين بناءً على بيانات مستخرجة من [Benchmark Bloom](https://github.com/intlayer-org/benchmark-bloom)، وهو مشروع اختبار مفتوح المصدر يبني التطبيق نفسه مع كل مكتبة ويسجل ما يقوم المتصفح بتنزيله وتنفيذه فعلياً.
|
|
30
|
+
|
|
31
|
+
<TOC/>
|
|
32
|
+
|
|
33
|
+
> **باختصار (tl;dr)**: تضيف `next-intl` ما لا يقل عن **+12.6 كيلوبايت gzip** في كل صفحة لمجرد وقت التشغيل (runtime)، وتسرب **~90% من سلاسل الصفحات الأخرى** في إعداداتها القياسية (`static` و`dynamic`). يتطلب التخلص من هذا التسرب تقسيم الكتالوجات إلى مساحات أسماء واختيارها يدوياً لكل صفحة، وهي مهمة معقدة يتجنبها معظم المطورين. في المقابل، يضمن مترجم `Intlayer` تسريباً بنسبة **0%**، ومكونات أصغر **بثلاث مرات**، و**+0.3 كيلوبايت** فقط فوق التطبيق الأساسي، كل ذلك بدون أي إعدادات يدوية إضافية.
|
|
34
|
+
|
|
35
|
+
## نظرة عامة
|
|
36
|
+
|
|
37
|
+
- **next-intl** - معيار مجتمع Next.js. قواميس JSON مركزية لكل لغة، دعم كامل لـ ICU MessageFormat، وتكامل وثيق مع معالجة طلبات Next.js ونظام التوجيه الخاص به.
|
|
38
|
+
- **Intlayer** - نموذج محتوى يتمحور حول المكونات. توضع ملفات `.content.ts` بجانب مكوناتها، ويقوم مترجم وقت البناء بتقليم الشجرة (tree-shaking) والتحميل الكسول للمحتوى لكل مكون ولكل لغة، مع توليد أنواع TypeScript صارمة تلقائياً.
|
|
39
|
+
|
|
40
|
+
| المكتبة | نجوم GitHub | إجمالي التعديلات | آخر تعديل | الإصدار الأول | إصدار NPM | تنزيلات NPM |
|
|
41
|
+
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
42
|
+
| `aymericzip/intlayer` | [](https://github.com/aymericzip/intlayer/stargazers) | [](https://github.com/aymericzip/intlayer/commits) | [](https://github.com/aymericzip/intlayer/commits) | أبريل 2024 | [](https://www.npmjs.com/package/intlayer) | [](https://www.npmjs.com/package/intlayer) |
|
|
43
|
+
| `amannn/next-intl` | [](https://github.com/amannn/next-intl/stargazers) | [](https://github.com/amannn/next-intl/commits) | [](https://github.com/amannn/next-intl/commits) | مارس 2021 | [](https://www.npmjs.com/package/next-intl) | [](https://www.npmjs.com/package/next-intl) |
|
|
44
|
+
|
|
45
|
+
> يتم تحديث الشارات تلقائياً.
|
|
46
|
+
|
|
47
|
+
## مقارنة الميزات جنباً إلى جنب
|
|
48
|
+
|
|
49
|
+
| الميزة | Intlayer (`react-intlayer` / `next-intlayer`) | next-intl (`next-intl` / `use-intl`) |
|
|
50
|
+
| ------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------- |
|
|
51
|
+
| **الترجمات بجانب المكونات** | ✅ نعم، ملف `.content.ts` بجوار كل مكون | ❌ قواميس JSON مركزية في مجلد `messages/` |
|
|
52
|
+
| **التكامل مع TypeScript** | ✅ أنواع صارمة مولدة تلقائياً من المحتوى | ⚠️ مدعوم عبر إعدادات `global.d.ts` يدوية لمسارات الرسائل |
|
|
53
|
+
| **اكتشاف الترجمات المفقودة** | ✅ خطأ TypeScript + خطأ/تحذير وقت البناء | ⚠️ وقت التشغيل يعيد المفتاح أو يرمي خطأ حسب الإعدادات |
|
|
54
|
+
| **المحتوى الغني (JSX / Markdown / مكونات)** | ✅ دعم مباشر | ⚠️ عبر `t.rich()` مع توفير مكونات التحويل |
|
|
55
|
+
| **دعم ICU MessageFormat** | ⚠️ قيد التطوير | ✅ نعم، دعم كامل لمعيار ICU |
|
|
56
|
+
| **مكونات الخادم المتزامنة** | ✅ `useIntlayer` من `next-intlayer/server` يعمل في أي مكون خادم متزامن | ❌ يتطلب تمرير الترجمات عبر الـ props من خادم غير متزامن |
|
|
57
|
+
| **تقليم الشجرة (Tree-shaking)** | ✅ تلقائي لكل مكون ولكل لغة | ⚠️ يتطلب تقسيماً يدوياً لمساحات الأسماء واستخدام `pick()` |
|
|
58
|
+
| **التحميل الكسول (Lazy loading)** | ✅ سطر إعداد واحد (`importMode: 'dynamic'`) | ⚠️ يتطلب استيراداً ديناميكياً يدوياً في `getRequestConfig` |
|
|
59
|
+
| **محرر مرئي / CMS** | ✅ محرر مرئي مجاني + CMS اختياري | ❌ لا يوجد |
|
|
60
|
+
| **ترجمة مدعومة بالذكاء الاصطناعي** | ✅ مدمجة وتستخدم مفاتيحك الخاصة | ❌ لا يوجد |
|
|
61
|
+
| **خادم MCP ومهارات الوكلاء** | ✅ نعم | ❌ لا يوجد |
|
|
62
|
+
|
|
63
|
+
## الاختبار
|
|
64
|
+
|
|
65
|
+
### ما تم قياسه
|
|
66
|
+
|
|
67
|
+
تبني مجموعة [Benchmark Bloom](https://github.com/intlayer-org/benchmark-bloom) **نفس التطبيق** مع كل مكتبة: **10 صفحات** (الرئيسية، من نحن، المدونة، الوظائف، اتصل بنا، الأسئلة الشائعة، الأسعار، المنتجات، الإعدادات، الفريق)، و**10 لغات** (`en`، `fr`، `es`، `de`، `it`، `pt`، `zh`، `ja`, `ko`, `ru`)، مع مكونات متطابقة ومحتوى متطابق. يتم قياس الصفحات باللغتين `en` و`fr`. يتم تطبيق كل مكتبة في ما يصل إلى أربع **استراتيجيات تحميل**:
|
|
68
|
+
|
|
69
|
+
| الاستراتيجية | الوصف | من يستخدمها |
|
|
70
|
+
| ------------------ | ------------------------------------------------------------------------------- | ------------------------------------------------ |
|
|
71
|
+
| **static** | يتم تجميع كل لغة وكل صفحة معاً وتحميلها دفعة واحدة | النماذج الأولية السريعة، الأكواد المولدة بالذكاء |
|
|
72
|
+
| **dynamic** | يتم تحميل لغة العرض النشطة فقط، ولكن لجميع الصفحات دفعة واحدة | معظم المشاريع |
|
|
73
|
+
| **scoped-static** | مساحات أسماء لكل مسار، بدون تحميل كسول | نادرة |
|
|
74
|
+
| **scoped-dynamic** | مساحات أسماء لكل مسار + تحميل كسول. يتم إرسال الصفحة الحالية باللغة الحالية فقط | التطبيقات ذات الميزانيات الصارمة في الأداء |
|
|
75
|
+
|
|
76
|
+
لا تملك Intlayer متغيراً "مخصص النطاق" (scoped): يقوم المترجم تلقائياً بتحديد نطاق المحتوى **لكل مكون**، لذلك فإن صفي `static` و`dynamic` محصوران بالفعل.
|
|
77
|
+
|
|
78
|
+
لكل بناء، تسجل المجموعة:
|
|
79
|
+
|
|
80
|
+
- **حجم المكتبة (Lib size)**: حجم gzip لمكون فارغ يستورد مكتبة i18n فقط.
|
|
81
|
+
- **JS للصفحة (Page JS)**: متوسط حجم JavaScript بتنسيق gzip الذي تم تنزيله لكل صفحة.
|
|
82
|
+
- **نسبة تسرب اللغة (Locale leak %)**: نسبة السلاسل التي تنتمي إلى لغة لا يعرضها المستخدم.
|
|
83
|
+
- **نسبة تسرب الصفحة (Page leak %)**: نسبة السلاسل التي تنتمي إلى صفحة لا يتصفحها المستخدم.
|
|
84
|
+
- **متوسط حجم المكون (Component avg)**: متوسط حجم gzip لكل مكون تم تجميعه بمعزل.
|
|
85
|
+
- **تفاعلية E2E**: الوقت المنقضي بين اختيار لغة جديدة وتحديث `html[lang]` في الـ DOM.
|
|
86
|
+
- **الترطيب (Hydration)**: مدة مرحلة ترطيب React.
|
|
87
|
+
|
|
88
|
+
> الأرقام أدناه مأخوذة من اختبار بتاريخ **2026-09-12** باستخدام `next-intl` 4.14.2 و`intlayer` 9.5.1.
|
|
89
|
+
|
|
90
|
+
### النتائج على Next.js (App Router)
|
|
91
|
+
|
|
92
|
+
| المكتبة | الاستراتيجية | حجم المكتبة (gz) | متوسط JS للصفحة (gz) | تسرب اللغة | تسرب الصفحة | متوسط المكون (gz) | تفاعلية E2E | الترطيب |
|
|
93
|
+
| ----------------------------- | -------------- | ---------------: | -------------------: | ---------: | ----------: | ----------------: | ----------: | ------: |
|
|
94
|
+
| **base** (بدون i18n) | - | 0.0 KB | 141.0 KB | 0.0% | 0.0% | 0.9 KB | 13.4 ms | 11.8 ms |
|
|
95
|
+
| `next-intl` | static | 14.7 KB | 153.6 KB | 4.2% | 89.8% | 21.8 KB | 16.0 ms | 14.7 ms |
|
|
96
|
+
| `next-intl` | dynamic | 14.7 KB | 153.6 KB | 9.7% | 89.9% | 21.8 KB | 15.6 ms | 14.8 ms |
|
|
97
|
+
| `next-intl` | scoped-static | 14.7 KB | 153.6 KB | 0.0% | 0.0% | 80.1 KB | 17.9 ms | 17.4 ms |
|
|
98
|
+
| `next-intl` | scoped-dynamic | 14.7 KB | 153.6 KB | 0.0% | 0.0% | 22.9 KB | 17.8 ms | 16.8 ms |
|
|
99
|
+
| **`next-intlayer`** | static | **5.5 KB** | **141.3 KB** | **0.0%** | **0.0%** | **8.5 KB** | **15.5 ms** | 16.9 ms |
|
|
100
|
+
| **`next-intlayer`** | dynamic | **5.5 KB** | **141.3 KB** | **0.0%** | **0.0%** | **6.9 KB** | **15.3 ms** | 15.9 ms |
|
|
101
|
+
| `@intlayer/next-intl` (توافق) | static | 8.0 KB | 147.5 KB | 0.0% | 0.0% | 8.1 KB | 14.5 ms | 12.8 ms |
|
|
102
|
+
| `@intlayer/next-intl` (توافق) | dynamic | 8.0 KB | 148.7 KB | 0.0% | 0.0% | 8.1 KB | 11.7 ms | 12.8 ms |
|
|
103
|
+
|
|
104
|
+
**كيف تقرأ هذه النتائج**
|
|
105
|
+
|
|
106
|
+
- **تكلفة وقت التشغيل.** يزن التطبيق الأساسي 141.0 كيلوبايت لكل صفحة. ترفعه `next-intl` إلى 153.6 كيلوبايت (**+12.6 كيلوبايت gzip في كل صفحة**)، بينما يرفعه Intlayer إلى 141.3 كيلوبايت فقط (**+0.3 كيلوبايت**).
|
|
107
|
+
- **التسريب.** في الإعدادين الأكثر استخداماً (`static` و`dynamic`)، ترسل `next-intl` ما يقرب من **~90% من سلاسل الصفحات الأخرى** في كل صفحة، لأن ملف `en.json` كاملاً يدخل في مزود العميل. يتطلب الوصول إلى 0% تقسيماً يدوياً دقيقاً. أما Intlayer فيحقق 0% تلقائياً.
|
|
108
|
+
- **حجم المكون.** المكون الذي يستدعي `useTranslations()` يُترجم في المتوسط إلى 21.8 كيلوبايت؛ والمكون نفسه مع `useIntlayer()` يبلغ 6.9 كيلوبايت فقط. وفي وضع `scoped-static` تقفز مكونات `next-intl` إلى 80.1 كيلوبايت لأن كل مكون يُضمن مساحة أسمائه داخلياً.
|
|
109
|
+
|
|
110
|
+
### النتائج على TanStack Start (`use-intl`)
|
|
111
|
+
|
|
112
|
+
| المكتبة | الاستراتيجية | حجم المكتبة (gz) | متوسط JS للصفحة (gz) | تسرب اللغة | تسرب الصفحة | متوسط المكون (gz) | تفاعلية E2E |
|
|
113
|
+
| ---------------------------- | -------------- | ---------------: | -------------------: | ---------: | ----------: | ----------------: | ----------: |
|
|
114
|
+
| **base** (بدون i18n) | - | 0.0 KB | 111.0 KB | 0.0% | 0.0% | 0.7 KB | 8.1 ms |
|
|
115
|
+
| `use-intl` | static | 14.1 KB | 179.8 KB | 50.0% | 89.8% | 76.0 KB | 6.7 ms |
|
|
116
|
+
| `use-intl` | dynamic | 14.1 KB | 119.4 KB | 0.0% | 89.8% | 75.9 KB | 7.0 ms |
|
|
117
|
+
| `use-intl` | scoped-static | 14.1 KB | 128.7 KB | 0.0% | 0.0% | 87.1 KB | 20.9 ms |
|
|
118
|
+
| `use-intl` | scoped-dynamic | 14.1 KB | 128.7 KB | 0.0% | 0.0% | 87.1 KB | 13.3 ms |
|
|
119
|
+
| **`intlayer`** | static | **5.0 KB** | **125.8 KB** | 50.0% | **0.0%** | **8.1 KB** | **3.2 ms** |
|
|
120
|
+
| **`intlayer`** | dynamic | **5.0 KB** | **118.6 KB** | **0.0%** | **0.0%** | **6.3 KB** | **3.6 ms** |
|
|
121
|
+
| `@intlayer/use-intl` (توافق) | dynamic | 7.3 KB | 129.7 KB | 0.0% | 0.0% | 9.3 KB | 8.7 ms |
|
|
122
|
+
|
|
123
|
+
**كيف تقرأ هذه النتائج**
|
|
124
|
+
|
|
125
|
+
- يرسل الإعداد البسيط لـ `use-intl` ما مقداره **68.8 كيلوبايت أكثر من JavaScript لكل صفحة** مقارنة بالتطبيق الأساسي.
|
|
126
|
+
- في وضع `dynamic`، يصل `use-intl` إلى 119.4 كيلوبايت، لكنه لا يزال يحمل **تسرباً للصفحات بنسبة 89.8%**.
|
|
127
|
+
- يظهر الفارق المعماري بوضوح في **حجم المكونات**: 76-87 كيلوبايت مع `use-intl` مقابل 6-8 كيلوبايت مع Intlayer.
|
|
128
|
+
- **تبديل اللغة** أسرع بمرتين إلى أربع مرات مع Intlayer (3 مللي ثانية مقابل 7-21 مللي ثانية).
|
|
129
|
+
|
|
130
|
+
## لماذا هذا الفارق؟ الكتالوجات المركزية مقابل القواميس المجمعة
|
|
131
|
+
|
|
132
|
+
تتبع `next-intl` النموذج التقليدي: ملف JSON واحد لكل لغة، يُحمّل في `getRequestConfig`، ويُمرر إلى `NextIntlClientProvider`، ويُقرأ عبر `t("namespace.key")`.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
.
|
|
136
|
+
├── messages
|
|
137
|
+
│ ├── en.json
|
|
138
|
+
│ └── fr.json
|
|
139
|
+
└── src
|
|
140
|
+
├── i18n
|
|
141
|
+
│ ├── request.ts
|
|
142
|
+
│ └── routing.ts
|
|
143
|
+
├── middleware.ts
|
|
144
|
+
└── app
|
|
145
|
+
└── [locale]
|
|
146
|
+
├── layout.tsx
|
|
147
|
+
└── about
|
|
148
|
+
└── page.tsx
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
لا يمكن لوقت التشغيل معرفة المفاتيح التي ستستخدمها الصفحة فعلياً، لذا فإن الخيار الآمن هو إرسال الكتالوج بأكمله.
|
|
152
|
+
|
|
153
|
+
بينما تقلب Intlayer هذه المسؤولية؛ حيث يتم الإعلان عن المحتوى بجانب المكون المعني مباشرة:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
.
|
|
157
|
+
├── intlayer.config.ts
|
|
158
|
+
└── src
|
|
159
|
+
├── middleware.ts
|
|
160
|
+
└── app
|
|
161
|
+
└── [locale]
|
|
162
|
+
├── layout.tsx
|
|
163
|
+
└── about
|
|
164
|
+
├── page.tsx
|
|
165
|
+
└── page.content.ts
|
|
166
|
+
└── components
|
|
167
|
+
└── Counter
|
|
168
|
+
├── index.tsx
|
|
169
|
+
└── index.content.ts
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
في وقت البناء، يرى المترجم أي مكون يستورد أي قاموس، ويحزم هذه القواميس فقط للغة النشطة، ويسقط أي محتوى غير مستخدم تلقائياً.
|
|
173
|
+
|
|
174
|
+
> للحصول على أرقام صف `dynamic`، اضبط `dictionary.importMode: 'dynamic'` في `intlayer.config.ts`. راجع [دليل تحسين الحزمة](https://intlayer.org/ar/doc/concept/bundle-optimization).
|
|
175
|
+
|
|
176
|
+
## تجربة المطور
|
|
177
|
+
|
|
178
|
+
### مكون العميل (Client Component)
|
|
179
|
+
|
|
180
|
+
**next-intl**
|
|
181
|
+
|
|
182
|
+
```json fileName="messages/en.json"
|
|
183
|
+
{
|
|
184
|
+
"counter": {
|
|
185
|
+
"label": "Counter",
|
|
186
|
+
"increment": "Increment"
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
```tsx fileName="src/components/Counter.tsx"
|
|
192
|
+
"use client";
|
|
193
|
+
|
|
194
|
+
import { useState } from "react";
|
|
195
|
+
import { useTranslations, useFormatter } from "next-intl";
|
|
196
|
+
|
|
197
|
+
export const Counter = () => {
|
|
198
|
+
const t = useTranslations("counter");
|
|
199
|
+
const format = useFormatter();
|
|
200
|
+
const [count, setCount] = useState(0);
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<div>
|
|
204
|
+
<p>{format.number(count)}</p>
|
|
205
|
+
<button aria-label={t("label")} onClick={() => setCount((c) => c + 1)}>
|
|
206
|
+
{t("increment")}
|
|
207
|
+
</button>
|
|
208
|
+
</div>
|
|
209
|
+
);
|
|
210
|
+
};
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Intlayer**
|
|
214
|
+
|
|
215
|
+
```ts fileName="src/components/Counter/index.content.ts"
|
|
216
|
+
import { t, type Dictionary } from "intlayer";
|
|
217
|
+
|
|
218
|
+
const counterContent = {
|
|
219
|
+
key: "counter",
|
|
220
|
+
content: {
|
|
221
|
+
label: t({ en: "Counter", fr: "Compteur" }),
|
|
222
|
+
increment: t({ en: "Increment", fr: "Incrémenter" }),
|
|
223
|
+
},
|
|
224
|
+
} satisfies Dictionary;
|
|
225
|
+
|
|
226
|
+
export default counterContent;
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
```tsx fileName="src/components/Counter/index.tsx"
|
|
230
|
+
"use client";
|
|
231
|
+
|
|
232
|
+
import { useState } from "react";
|
|
233
|
+
import { useIntlayer } from "next-intlayer";
|
|
234
|
+
import { useNumber } from "next-intlayer/format";
|
|
235
|
+
|
|
236
|
+
export const Counter = () => {
|
|
237
|
+
const { label, increment } = useIntlayer("counter");
|
|
238
|
+
const number = useNumber();
|
|
239
|
+
const [count, setCount] = useState(0);
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<div>
|
|
243
|
+
<p>{number(count)}</p>
|
|
244
|
+
<button aria-label={label} onClick={() => setCount((c) => c + 1)}>
|
|
245
|
+
{increment}
|
|
246
|
+
</button>
|
|
247
|
+
</div>
|
|
248
|
+
);
|
|
249
|
+
};
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### مكونات الخادم المتزامنة (Server Components)
|
|
253
|
+
|
|
254
|
+
غالباً ما تكون عناصر واجهة المستخدم المشتركة (شريط التنقل، التذييل، البطاقات) مكونات خادم تُعرض كأبناء لمكونات العميل، لذا لا يمكن أن تكون غير متزامنة (`async`).
|
|
255
|
+
|
|
256
|
+
**next-intl**
|
|
257
|
+
|
|
258
|
+
```tsx fileName="src/components/ServerCounter.tsx"
|
|
259
|
+
type ServerCounterProps = {
|
|
260
|
+
t: (key: string) => string;
|
|
261
|
+
formattedCount: string;
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
export const ServerCounter = ({ t, formattedCount }: ServerCounterProps) => (
|
|
265
|
+
<div>
|
|
266
|
+
<p>{formattedCount}</p>
|
|
267
|
+
<button aria-label={t("label")}>{t("increment")}</button>
|
|
268
|
+
</div>
|
|
269
|
+
);
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Intlayer**
|
|
273
|
+
|
|
274
|
+
```tsx fileName="src/components/ServerCounter.tsx"
|
|
275
|
+
import { useIntlayer } from "next-intlayer/server";
|
|
276
|
+
import { useNumber } from "next-intlayer/server/format";
|
|
277
|
+
|
|
278
|
+
export const ServerCounter = ({ count }: { count: number }) => {
|
|
279
|
+
const { label, increment } = useIntlayer("counter");
|
|
280
|
+
const number = useNumber();
|
|
281
|
+
|
|
282
|
+
return (
|
|
283
|
+
<div>
|
|
284
|
+
<p>{number(count)}</p>
|
|
285
|
+
<button aria-label={label}>{increment}</button>
|
|
286
|
+
</div>
|
|
287
|
+
);
|
|
288
|
+
};
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### البيانات الوصفية (Metadata)
|
|
292
|
+
|
|
293
|
+
**next-intl**
|
|
294
|
+
|
|
295
|
+
```tsx fileName="src/app/[locale]/about/page.tsx"
|
|
296
|
+
import type { Metadata } from "next";
|
|
297
|
+
import { getTranslations } from "next-intl/server";
|
|
298
|
+
import { routing } from "@/i18n/routing";
|
|
299
|
+
|
|
300
|
+
const localizedPath = (locale: string, path: string) =>
|
|
301
|
+
locale === routing.defaultLocale ? path : `/${locale}${path}`;
|
|
302
|
+
|
|
303
|
+
export const generateMetadata = async ({
|
|
304
|
+
params,
|
|
305
|
+
}: {
|
|
306
|
+
params: Promise<{ locale: string }>;
|
|
307
|
+
}): Promise<Metadata> => {
|
|
308
|
+
const { locale } = await params;
|
|
309
|
+
const t = await getTranslations({ locale, namespace: "about" });
|
|
310
|
+
|
|
311
|
+
const languages = Object.fromEntries(
|
|
312
|
+
routing.locales.map((l) => [l, localizedPath(l, "/about")])
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
title: t("title"),
|
|
317
|
+
description: t("description"),
|
|
318
|
+
alternates: {
|
|
319
|
+
canonical: localizedPath(locale, "/about"),
|
|
320
|
+
languages: { ...languages, "x-default": "/about" },
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
};
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Intlayer**
|
|
327
|
+
|
|
328
|
+
```tsx fileName="src/app/[locale]/about/page.tsx"
|
|
329
|
+
import { getIntlayer, getMultilingualUrls } from "intlayer";
|
|
330
|
+
import type { Metadata } from "next";
|
|
331
|
+
import type { LocalPromiseParams } from "next-intlayer";
|
|
332
|
+
|
|
333
|
+
export const generateMetadata = async ({
|
|
334
|
+
params,
|
|
335
|
+
}: LocalPromiseParams): Promise<Metadata> => {
|
|
336
|
+
const { locale } = await params;
|
|
337
|
+
const metadata = getIntlayer("about-metadata", locale);
|
|
338
|
+
const multilingualUrls = getMultilingualUrls("/about");
|
|
339
|
+
|
|
340
|
+
return {
|
|
341
|
+
...metadata,
|
|
342
|
+
alternates: {
|
|
343
|
+
canonical: multilingualUrls[locale as keyof typeof multilingualUrls],
|
|
344
|
+
languages: { ...multilingualUrls, "x-default": "/about" },
|
|
345
|
+
},
|
|
346
|
+
};
|
|
347
|
+
};
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## الاحتفاظ بـ API الخاص بـ next-intl مع مخرجات Intlayer
|
|
351
|
+
|
|
352
|
+
لا يتعين عليك إعادة كتابة مكوناتك للحصول على أرقام الأداء الموضحة أعلاه. حزمة `@intlayer/next-intl` هي محول متوافق مباشرة: يحتفظ بـ `useTranslations` و`getTranslations` و`useFormatter` و`t.rich()` وصيغ الجمع في ICU، ويقدمها من قواميس Intlayer التي يترجمها مترجم Intlayer.
|
|
353
|
+
|
|
354
|
+
```ts fileName="next.config.ts"
|
|
355
|
+
import type { NextConfig } from "next";
|
|
356
|
+
import { createNextIntlPlugin } from "@intlayer/next-intl/plugin";
|
|
357
|
+
|
|
358
|
+
const withIntlayer = createNextIntlPlugin();
|
|
359
|
+
|
|
360
|
+
const nextConfig: NextConfig = {};
|
|
361
|
+
|
|
362
|
+
export default withIntlayer(nextConfig);
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
في الاختبار، تحسن بناء التوافق لنفس التطبيق من **153.6 كيلوبايت إلى 147.5 كيلوبايت** لكل صفحة، ومن **21.8 كيلوبايت إلى 8.1 كيلوبايت** لكل مكون، ومن **تسرب يقارب 90% إلى 0%**، مع بقاء كود التطبيق دون أي تعديل. ويمكن لملفات `messages/{locale}.json` الحالية أن تظل مصدر الحقيقة عبر [إضافة مزامنة JSON](https://intlayer.org/ar/doc/compatibility/next-intl).
|
|
366
|
+
|
|
367
|
+
راجع [دليل الانتقال من next-intl](https://intlayer.org/ar/doc/migration/next-intl) لاتباع الخطوات التفصيلية.
|
|
368
|
+
|
|
369
|
+
## متى تختار أياً منهما؟
|
|
370
|
+
|
|
371
|
+
- **اختر next-intl** إذا كنت بحاجة إلى معيار مجتمع Next.js الواسع، أو تعتمد بشكل كبير على ICU MessageFormat، أو كان تطبيقك صغيراً إلى متوسط الحجم، أو كنت مدمجاً بالفعل مع منصات ترجمة مركزية (Crowdin، Phrase، Lokalise...).
|
|
372
|
+
- **اختر Intlayer** إذا كنت تريد **محتوى بنطاق المكونات**، و**TypeScript صارماً**، و**أخطاء للمفاتيح المفقودة عند البناء**، و**تقليم الشجرة والتحميل الكسول دون أي جهد**، ومكونات خادم متزامنة، وأدوات تحرير مدمجة (محرر مرئي، CMS، ترجمة بالذكاء الاصطناعي، خادم MCP).
|
|
373
|
+
- **اختر `@intlayer/next-intl`** إذا كنت تستخدم `next-intl` بالفعل وتريد مكاسب الحزمة والأداء دون إعادة كتابة التطبيق.
|
|
374
|
+
|
|
375
|
+
## مقارنات ذات صلة
|
|
376
|
+
|
|
377
|
+
- [i18next مقابل Intlayer](https://intlayer.org/ar/blog/i18next-vs-intlayer) (الاختبار نفسه)
|
|
378
|
+
- [Lingui مقابل Intlayer](https://intlayer.org/ar/blog/lingui-vs-intlayer) (الاختبار نفسه)
|
|
379
|
+
- [vue-i18n مقابل Intlayer](https://intlayer.org/ar/blog/vue-i18n-vs-intlayer-benchmark) (الاختبار نفسه)
|
|
380
|
+
- [next-i18next مقابل next-intl مقابل Intlayer](https://intlayer.org/ar/blog/next-i18next-vs-next-intl-vs-intlayer)
|
|
381
|
+
- [هل أصبحت next-intl قديمة؟](https://intlayer.org/ar/blog/is-next-intl-outdated)
|
|
382
|
+
|
|
383
|
+
## نجوم GitHub
|
|
384
|
+
|
|
385
|
+
تعد نجوم GitHub مؤشراً قوياً على شعبية المشروع وثقة المجتمع وأهميته على المدى الطويل.
|
|
386
|
+
|
|
387
|
+
[](https://star-history.com/#amannn/next-intl&aymericzip/intlayer)
|
|
388
|
+
|
|
389
|
+
## الخاتمة
|
|
390
|
+
|
|
391
|
+
`next-intl` مكتبة قوية ومصانة جيداً، ويؤكد الاختبار أنها خيار جيد على Next.js. لكن نموذج الكتالوج المركزي يضع كل عبء التحسين على عاتق المطور: الإعداد البسيط يسرب نحو 90% من محتوى الصفحات الأخرى، ووقت التشغيل وحده يكلف +12.6 كيلوبايت gzip في كل صفحة.
|
|
392
|
+
|
|
393
|
+
ينقل Intlayer هذا العمل بأكمله إلى المترجم. القواميس لكل مكون، والتحميل الكسول لكل لغة، وتطهير المحتوى غير المستخدم تصبح جميعها مخرجات بناء تلقائية. والنتيجة على نفس التطبيق: **+0.3 كيلوبايت لكل صفحة**، **0% تسرب**، ومكونات **أصغر بـ 3 مرات**، وتبديل لغة **أسرع بمرتين إلى 4 مرات** على TanStack Start.
|
|
394
|
+
|
|
395
|
+
جميع البيانات الأولية والتطبيقات وسيناريوهات الاختبار متاحة في [مستودع Benchmark Bloom](https://github.com/intlayer-org/benchmark-bloom). يمكنك تشغيلها بنفسك.
|
|
396
|
+
|
|
397
|
+
راجع وثيقة ['لماذا Intlayer؟'](https://intlayer.org/ar/doc/why) لمزيد من التفاصيل.
|
|
@@ -128,7 +128,7 @@ author: aymericzip
|
|
|
128
128
|
|
|
129
129
|
نجوم GitHub هي مؤشر قوي على شعبية المشروع وثقة المجتمع وأهميته طويلة الأجل. على الرغم من أنها ليست مقياساً مباشراً للجودة التقنية، إلا أنها تعكس عدد المطورين الذين يجدون المشروع مفيداً ويتابعون تقدمه ويرجح أن يعتمدوه. لتقدير قيمة المشروع، تساعد النجوم في مقارنة الزخم عبر البدائل وتوفر رؤى حول نمو النظام البيئي.
|
|
130
130
|
|
|
131
|
-
[](https://
|
|
131
|
+
[](https://star-history.com/#formatjs/formatjs&i18next/react-i18next&aymericzip/intlayer)
|
|
132
132
|
|
|
133
133
|
## الخلاصة
|
|
134
134
|
|