@intlayer/docs 7.3.14 → 7.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/blog/ar/intlayer_with_i18next.md +3 -0
- package/blog/ar/intlayer_with_next-i18next.md +3 -0
- package/blog/ar/intlayer_with_next-intl.md +3 -0
- package/blog/ar/intlayer_with_react-i18next.md +3 -0
- package/blog/ar/intlayer_with_react-intl.md +3 -0
- package/blog/ar/intlayer_with_vue-i18n.md +3 -0
- package/blog/de/intlayer_with_i18next.md +3 -0
- package/blog/de/intlayer_with_next-i18next.md +3 -0
- package/blog/de/intlayer_with_next-intl.md +3 -0
- package/blog/de/intlayer_with_react-i18next.md +3 -0
- package/blog/de/intlayer_with_react-intl.md +3 -0
- package/blog/de/intlayer_with_vue-i18n.md +3 -0
- package/blog/en/intlayer_with_i18next.md +7 -0
- package/blog/en/intlayer_with_next-i18next.md +3 -0
- package/blog/en/intlayer_with_next-intl.md +7 -0
- package/blog/en/intlayer_with_react-i18next.md +3 -0
- package/blog/en/intlayer_with_react-intl.md +3 -0
- package/blog/en/intlayer_with_vue-i18n.md +3 -0
- package/blog/en-GB/intlayer_with_i18next.md +3 -0
- package/blog/en-GB/intlayer_with_next-i18next.md +3 -0
- package/blog/en-GB/intlayer_with_next-intl.md +3 -0
- package/blog/en-GB/intlayer_with_react-i18next.md +3 -0
- package/blog/en-GB/intlayer_with_react-intl.md +3 -0
- package/blog/en-GB/intlayer_with_vue-i18n.md +3 -0
- package/blog/es/intlayer_with_i18next.md +3 -0
- package/blog/es/intlayer_with_next-i18next.md +3 -0
- package/blog/es/intlayer_with_next-intl.md +3 -0
- package/blog/es/intlayer_with_react-i18next.md +3 -0
- package/blog/es/intlayer_with_react-intl.md +3 -0
- package/blog/es/intlayer_with_vue-i18n.md +3 -0
- package/blog/fr/intlayer_with_i18next.md +3 -0
- package/blog/fr/intlayer_with_next-i18next.md +3 -0
- package/blog/fr/intlayer_with_next-intl.md +3 -0
- package/blog/fr/intlayer_with_react-i18next.md +3 -0
- package/blog/fr/intlayer_with_react-intl.md +3 -0
- package/blog/fr/intlayer_with_vue-i18n.md +3 -0
- package/blog/hi/intlayer_with_i18next.md +3 -0
- package/blog/hi/intlayer_with_next-i18next.md +3 -0
- package/blog/hi/intlayer_with_next-intl.md +3 -0
- package/blog/hi/intlayer_with_react-i18next.md +3 -0
- package/blog/hi/intlayer_with_react-intl.md +3 -0
- package/blog/hi/intlayer_with_vue-i18n.md +3 -0
- package/blog/id/intlayer_with_i18next.md +3 -0
- package/blog/id/intlayer_with_next-i18next.md +3 -0
- package/blog/id/intlayer_with_next-intl.md +3 -0
- package/blog/id/intlayer_with_react-i18next.md +3 -0
- package/blog/id/intlayer_with_react-intl.md +3 -0
- package/blog/id/intlayer_with_vue-i18n.md +3 -0
- package/blog/it/intlayer_with_i18next.md +3 -0
- package/blog/it/intlayer_with_next-i18next.md +3 -0
- package/blog/it/intlayer_with_next-intl.md +3 -0
- package/blog/it/intlayer_with_react-i18next.md +3 -0
- package/blog/it/intlayer_with_react-intl.md +3 -0
- package/blog/it/intlayer_with_vue-i18n.md +3 -0
- package/blog/ja/intlayer_with_i18next.md +3 -0
- package/blog/ja/intlayer_with_next-i18next.md +3 -0
- package/blog/ja/intlayer_with_next-intl.md +3 -0
- package/blog/ja/intlayer_with_react-i18next.md +3 -0
- package/blog/ja/intlayer_with_react-intl.md +3 -0
- package/blog/ja/intlayer_with_vue-i18n.md +3 -0
- package/blog/ko/intlayer_with_i18next.md +3 -0
- package/blog/ko/intlayer_with_next-i18next.md +3 -0
- package/blog/ko/intlayer_with_next-intl.md +3 -0
- package/blog/ko/intlayer_with_react-i18next.md +3 -0
- package/blog/ko/intlayer_with_react-intl.md +3 -0
- package/blog/ko/intlayer_with_vue-i18n.md +3 -0
- package/blog/pl/intlayer_with_i18next.md +3 -0
- package/blog/pl/intlayer_with_next-i18next.md +3 -0
- package/blog/pl/intlayer_with_next-intl.md +3 -0
- package/blog/pl/intlayer_with_react-i18next.md +3 -0
- package/blog/pl/intlayer_with_react-intl.md +3 -0
- package/blog/pl/intlayer_with_vue-i18n.md +3 -0
- package/blog/pt/intlayer_with_i18next.md +3 -0
- package/blog/pt/intlayer_with_next-i18next.md +3 -0
- package/blog/pt/intlayer_with_next-intl.md +3 -0
- package/blog/pt/intlayer_with_react-i18next.md +3 -0
- package/blog/pt/intlayer_with_react-intl.md +3 -0
- package/blog/pt/intlayer_with_vue-i18n.md +3 -0
- package/blog/ru/intlayer_with_i18next.md +3 -0
- package/blog/ru/intlayer_with_next-i18next.md +3 -0
- package/blog/ru/intlayer_with_next-intl.md +3 -0
- package/blog/ru/intlayer_with_react-i18next.md +3 -0
- package/blog/ru/intlayer_with_react-intl.md +3 -0
- package/blog/ru/intlayer_with_vue-i18n.md +3 -0
- package/blog/tr/intlayer_with_i18next.md +3 -0
- package/blog/tr/intlayer_with_next-i18next.md +3 -0
- package/blog/tr/intlayer_with_next-intl.md +3 -0
- package/blog/tr/intlayer_with_react-i18next.md +3 -0
- package/blog/tr/intlayer_with_vue-i18n.md +3 -0
- package/blog/vi/intlayer_with_i18next.md +3 -0
- package/blog/vi/intlayer_with_next-i18next.md +3 -0
- package/blog/vi/intlayer_with_next-intl.md +3 -0
- package/blog/vi/intlayer_with_react-i18next.md +3 -0
- package/blog/vi/intlayer_with_react-intl.md +3 -0
- package/blog/vi/intlayer_with_vue-i18n.md +3 -0
- package/blog/zh/intlayer_with_i18next.md +3 -0
- package/blog/zh/intlayer_with_next-i18next.md +3 -0
- package/blog/zh/intlayer_with_next-intl.md +3 -0
- package/blog/zh/intlayer_with_react-i18next.md +3 -0
- package/blog/zh/intlayer_with_react-intl.md +3 -0
- package/blog/zh/intlayer_with_vue-i18n.md +3 -0
- package/docs/ar/intlayer_with_lynx+react.md +1 -1
- package/docs/ar/intlayer_with_tanstack.md +132 -2
- package/docs/ar/intlayer_with_vite+react.md +99 -331
- package/docs/ar/plugins/sync-json.md +3 -0
- package/docs/de/intlayer_with_lynx+react.md +1 -1
- package/docs/de/intlayer_with_tanstack.md +132 -2
- package/docs/de/intlayer_with_vite+react.md +116 -380
- package/docs/de/plugins/sync-json.md +3 -0
- package/docs/en/intlayer_with_tanstack.md +131 -1
- package/docs/en/intlayer_with_vite+react.md +6 -10
- package/docs/en/plugins/sync-json.md +3 -0
- package/docs/en-GB/intlayer_with_tanstack.md +131 -1
- package/docs/en-GB/intlayer_with_vite+react.md +62 -74
- package/docs/en-GB/plugins/sync-json.md +3 -0
- package/docs/es/intlayer_with_tanstack.md +132 -2
- package/docs/es/intlayer_with_vite+react.md +101 -333
- package/docs/es/plugins/sync-json.md +3 -0
- package/docs/fr/intlayer_with_tanstack.md +132 -2
- package/docs/fr/intlayer_with_vite+react.md +101 -357
- package/docs/fr/plugins/sync-json.md +3 -0
- package/docs/hi/intlayer_with_tanstack.md +132 -2
- package/docs/hi/intlayer_with_vite+react.md +120 -333
- package/docs/hi/plugins/sync-json.md +3 -0
- package/docs/id/intlayer_with_tanstack.md +132 -2
- package/docs/id/intlayer_with_vite+react.md +7 -13
- package/docs/id/plugins/sync-json.md +3 -0
- package/docs/it/intlayer_with_lynx+react.md +1 -1
- package/docs/it/intlayer_with_tanstack.md +132 -2
- package/docs/it/intlayer_with_vite+react.md +121 -393
- package/docs/it/plugins/sync-json.md +3 -0
- package/docs/ja/intlayer_with_tanstack.md +132 -2
- package/docs/ja/intlayer_with_vite+react.md +106 -378
- package/docs/ja/plugins/sync-json.md +3 -0
- package/docs/ko/intlayer_with_lynx+react.md +1 -1
- package/docs/ko/intlayer_with_tanstack.md +132 -2
- package/docs/ko/intlayer_with_vite+react.md +90 -322
- package/docs/ko/plugins/sync-json.md +3 -0
- package/docs/pl/intlayer_with_tanstack.md +132 -2
- package/docs/pl/intlayer_with_vite+react.md +25 -21
- package/docs/pl/plugins/sync-json.md +3 -0
- package/docs/pt/intlayer_with_tanstack.md +132 -2
- package/docs/pt/intlayer_with_vite+react.md +96 -328
- package/docs/pt/plugins/sync-json.md +3 -0
- package/docs/ru/intlayer_with_lynx+react.md +1 -1
- package/docs/ru/intlayer_with_tanstack.md +132 -2
- package/docs/ru/intlayer_with_vite+react.md +109 -362
- package/docs/ru/plugins/sync-json.md +3 -0
- package/docs/tr/intlayer_with_tanstack.md +132 -2
- package/docs/tr/intlayer_with_vite+react.md +132 -366
- package/docs/tr/plugins/sync-json.md +3 -0
- package/docs/vi/intlayer_with_tanstack.md +132 -2
- package/docs/vi/intlayer_with_vite+react.md +16 -19
- package/docs/vi/plugins/sync-json.md +3 -0
- package/docs/zh/intlayer_with_tanstack.md +133 -3
- package/docs/zh/intlayer_with_vite+react.md +91 -374
- package/docs/zh/plugins/sync-json.md +3 -0
- package/frequent_questions/ar/customized_locale_list.md +1 -1
- package/frequent_questions/de/customized_locale_list.md +1 -1
- package/frequent_questions/en/customized_locale_list.md +1 -1
- package/frequent_questions/en-GB/customized_locale_list.md +1 -1
- package/frequent_questions/es/customized_locale_list.md +1 -1
- package/frequent_questions/fr/customized_locale_list.md +1 -1
- package/frequent_questions/hi/customized_locale_list.md +1 -1
- package/frequent_questions/id/customized_locale_list.md +1 -1
- package/frequent_questions/it/customized_locale_list.md +1 -1
- package/frequent_questions/ja/customized_locale_list.md +1 -1
- package/frequent_questions/ko/customized_locale_list.md +1 -1
- package/frequent_questions/pl/customized_locale_list.md +1 -1
- package/frequent_questions/pt/customized_locale_list.md +1 -1
- package/frequent_questions/ru/customized_locale_list.md +1 -1
- package/frequent_questions/tr/customized_locale_list.md +1 -1
- package/frequent_questions/vi/customized_locale_list.md +1 -1
- package/frequent_questions/zh/customized_locale_list.md +1 -1
- package/package.json +6 -6
|
@@ -22,6 +22,7 @@ slugs:
|
|
|
22
22
|
- doc
|
|
23
23
|
- plugin
|
|
24
24
|
- sync-json
|
|
25
|
+
youtubeVideo: https://www.youtube.com/watch?v=MpGMxniDHNg
|
|
25
26
|
history:
|
|
26
27
|
- version: 6.1.6
|
|
27
28
|
date: 2025-10-05
|
|
@@ -30,6 +31,8 @@ history:
|
|
|
30
31
|
|
|
31
32
|
# JSON Senkronizasyonu (i18n köprüleri)
|
|
32
33
|
|
|
34
|
+
<iframe title="JSON çevirilerinizi Intlayer ile nasıl senkronize tutarsınız" class="m-auto aspect-[16/9] w-full overflow-hidden rounded-lg border-0" allow="autoplay; gyroscope;" loading="lazy" width="1080" height="auto" src="https://www.youtube.com/embed/MpGMxniDHNg?autoplay=0&origin=http://intlayer.org&controls=0&rel=1"/>
|
|
35
|
+
|
|
33
36
|
Intlayer'ı mevcut i18n yapınıza bir eklenti olarak kullanın. Bu eklenti, JSON mesajlarınızı Intlayer sözlükleriyle senkronize tutar, böylece:
|
|
34
37
|
|
|
35
38
|
- i18next, next-intl, react-intl, vue-i18n, next-translate, nuxt-i18n, Solid-i18next, svelte-i18n vb. kullanmaya devam edebilirsiniz.
|
|
@@ -19,9 +19,12 @@ slugs:
|
|
|
19
19
|
applicationTemplate: https://github.com/aymericzip/intlayer-tanstack-start-template
|
|
20
20
|
youtubeVideo: https://www.youtube.com/watch?v=_XTdKVWaeqg
|
|
21
21
|
history:
|
|
22
|
+
- version: 7.4.0
|
|
23
|
+
date: 2025-12-11
|
|
24
|
+
changes: Giới thiệu validatePrefix và thêm bước 14: Xử lý trang 404 với các tuyến đường được bản địa hóa.
|
|
22
25
|
- version: 7.3.9
|
|
23
26
|
date: 2025-12-05
|
|
24
|
-
changes:
|
|
27
|
+
changes: Thêm bước 13: Lấy locale trong server actions của bạn (Tùy chọn)
|
|
25
28
|
- version: 6.5.2
|
|
26
29
|
date: 2025-10-03
|
|
27
30
|
changes: Cập nhật tài liệu
|
|
@@ -600,7 +603,134 @@ export const getLocaleServer = createServerFn().handler(async () => {
|
|
|
600
603
|
|
|
601
604
|
---
|
|
602
605
|
|
|
603
|
-
### Bước 14:
|
|
606
|
+
### Bước 14: Quản lý trang không tìm thấy (Tùy chọn)
|
|
607
|
+
|
|
608
|
+
Khi người dùng truy cập một trang không tồn tại, bạn có thể hiển thị một trang không tìm thấy tùy chỉnh và tiền tố locale có thể ảnh hưởng đến cách trang không tìm thấy được kích hoạt.
|
|
609
|
+
|
|
610
|
+
#### Hiểu về xử lý 404 của TanStack Router với tiền tố locale
|
|
611
|
+
|
|
612
|
+
Trong TanStack Router, xử lý các trang 404 với các route đã được bản địa hóa yêu cầu một cách tiếp cận nhiều lớp:
|
|
613
|
+
|
|
614
|
+
1. **Route 404 chuyên dụng**: Một route cụ thể để hiển thị giao diện 404
|
|
615
|
+
2. **Xác thực cấp route**: Xác thực các tiền tố locale và chuyển hướng các tiền tố không hợp lệ đến 404
|
|
616
|
+
3. **Route catch-all**: Bắt tất cả các đường dẫn không khớp trong phân đoạn locale
|
|
617
|
+
|
|
618
|
+
```tsx fileName="src/routes/{-$locale}/404.tsx"
|
|
619
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
620
|
+
|
|
621
|
+
// Điều này tạo một tuyến đường /[locale]/404 chuyên dụng
|
|
622
|
+
// Nó được sử dụng cả như một tuyến đường trực tiếp và được nhập như một thành phần trong các tệp khác
|
|
623
|
+
export const Route = createFileRoute("/{-$locale}/404")({
|
|
624
|
+
component: NotFoundComponent,
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
// Xuất riêng để có thể tái sử dụng trong notFoundComponent và các tuyến catch-all
|
|
628
|
+
export function NotFoundComponent() {
|
|
629
|
+
return (
|
|
630
|
+
<div>
|
|
631
|
+
<h1>404</h1>
|
|
632
|
+
</div>
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
```tsx fileName="src/routes/__root.tsx"
|
|
638
|
+
import { createRootRoute } from "@tanstack/react-router";
|
|
639
|
+
|
|
640
|
+
// Tuyến đường gốc phục vụ như bố cục cấp cao nhất
|
|
641
|
+
// Nó không xử lý 404 trực tiếp - điều đó được ủy quyền cho các tuyến đường con
|
|
642
|
+
// Điều này giữ cho gốc đơn giản và cho phép các tuyến đường nhận biết locale quản lý logic 404 của riêng chúng
|
|
643
|
+
export const Route = createRootRoute({
|
|
644
|
+
component: Outlet,
|
|
645
|
+
});
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
```tsx fileName="src/routes/{-$locale}/route.tsx"
|
|
649
|
+
import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";
|
|
650
|
+
import { validatePrefix } from "intlayer";
|
|
651
|
+
import { IntlayerProvider, useLocale } from "react-intlayer";
|
|
652
|
+
|
|
653
|
+
import { LocaleSwitcher } from "@/components/locale-switcher";
|
|
654
|
+
import { NotFoundComponent } from "./404";
|
|
655
|
+
|
|
656
|
+
export const Route = createFileRoute("/{-$locale}")({
|
|
657
|
+
// beforeLoad chạy trước khi tuyến đường được kết xuất (trên cả máy chủ và máy khách)
|
|
658
|
+
// Đây là nơi lý tưởng để xác thực tiền tố locale
|
|
659
|
+
beforeLoad: ({ params }) => {
|
|
660
|
+
// Lấy locale từ tham số tuyến đường (không phải từ tiêu đề máy chủ, vì beforeLoad chạy trên cả máy khách và máy chủ)
|
|
661
|
+
const localeParam = params.locale;
|
|
662
|
+
|
|
663
|
+
// validatePrefix kiểm tra xem locale có hợp lệ theo cấu hình intlayer của bạn không
|
|
664
|
+
// Trả về: { isValid: boolean, localePrefix: string }
|
|
665
|
+
// - isValid: true nếu tiền tố khớp với locale đã cấu hình (hoặc trống khi tiền tố là tùy chọn)
|
|
666
|
+
// - localePrefix: tiền tố đã được xác thực hoặc tiền tố locale mặc định để chuyển hướng
|
|
667
|
+
const { isValid, localePrefix } = validatePrefix(localeParam);
|
|
668
|
+
|
|
669
|
+
if (isValid) {
|
|
670
|
+
// Locale hợp lệ, cho phép tuyến đường kết xuất bình thường
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// Tiền tố locale không hợp lệ (ví dụ: /xyz/about trong đó "xyz" không phải là locale hợp lệ)
|
|
675
|
+
// Chuyển hướng đến trang 404 với tiền tố locale hợp lệ
|
|
676
|
+
// Điều này đảm bảo trang 404 vẫn được bản địa hóa đúng cách
|
|
677
|
+
throw redirect({
|
|
678
|
+
to: "/{-$locale}/404",
|
|
679
|
+
params: { locale: localePrefix },
|
|
680
|
+
});
|
|
681
|
+
},
|
|
682
|
+
component: RouteComponent,
|
|
683
|
+
// notFoundComponent được gọi khi một tuyến đường con không tồn tại
|
|
684
|
+
// ví dụ: /en/trang-khong-ton-tai kích hoạt điều này trong bố cục /en
|
|
685
|
+
notFoundComponent: NotFoundLayout,
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
function RouteComponent() {
|
|
689
|
+
const { defaultLocale } = useLocale();
|
|
690
|
+
const { locale } = Route.useParams();
|
|
691
|
+
|
|
692
|
+
return (
|
|
693
|
+
// Bọc toàn bộ phân đoạn locale bằng IntlayerProvider
|
|
694
|
+
// Quay lại defaultLocale khi tham số locale là undefined (chế độ tiền tố tùy chọn)
|
|
695
|
+
<IntlayerProvider locale={locale ?? defaultLocale}>
|
|
696
|
+
<Outlet />
|
|
697
|
+
</IntlayerProvider>
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// NotFoundLayout bọc thành phần 404 bằng IntlayerProvider
|
|
702
|
+
// Điều này đảm bảo bản dịch vẫn hoạt động trên trang 404
|
|
703
|
+
function NotFoundLayout() {
|
|
704
|
+
const { defaultLocale } = useLocale();
|
|
705
|
+
const { locale } = Route.useParams();
|
|
706
|
+
|
|
707
|
+
return (
|
|
708
|
+
<IntlayerProvider locale={locale ?? defaultLocale}>
|
|
709
|
+
<NotFoundComponent />
|
|
710
|
+
{/* Bao gồm LocaleSwitcher để người dùng có thể thay đổi ngôn ngữ ngay cả trên 404 */}
|
|
711
|
+
<LocaleSwitcher />
|
|
712
|
+
</IntlayerProvider>
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
```tsx fileName="src/routes/{-$locale}/$.tsx"
|
|
718
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
719
|
+
|
|
720
|
+
import { NotFoundComponent } from "./404";
|
|
721
|
+
|
|
722
|
+
// Tuyến đường $ (splat/catch-all) khớp với bất kỳ đường dẫn nào không khớp với các tuyến đường khác
|
|
723
|
+
// ví dụ: /en/mot/duong/dan/sau/long/khong-hop-le
|
|
724
|
+
// Điều này đảm bảo TẤT CẢ các đường dẫn không khớp trong một locale hiển thị trang 404
|
|
725
|
+
// Nếu không có điều này, các đường dẫn sâu không khớp có thể hiển thị trang trống hoặc lỗi
|
|
726
|
+
export const Route = createFileRoute("/{-$locale}/$")({
|
|
727
|
+
component: NotFoundComponent,
|
|
728
|
+
});
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
---
|
|
732
|
+
|
|
733
|
+
### Bước 15: Cấu hình TypeScript (Tùy chọn)
|
|
604
734
|
|
|
605
735
|
Intlayer sử dụng module augmentation để tận dụng các lợi ích của TypeScript và làm cho codebase của bạn mạnh mẽ hơn.
|
|
606
736
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2024-03-07
|
|
3
|
-
updatedAt:
|
|
3
|
+
updatedAt: 2025-12-10
|
|
4
4
|
title: Cách dịch ứng dụng Vite và React của bạn – Hướng dẫn i18n 2025
|
|
5
5
|
description: Tìm hiểu cách thêm quốc tế hóa (i18n) vào ứng dụng Vite và React của bạn bằng cách sử dụng Intlayer. Theo dõi hướng dẫn này để làm cho ứng dụng của bạn đa ngôn ngữ.
|
|
6
6
|
keywords:
|
|
@@ -86,7 +86,7 @@ yarn add vite-intlayer --save-dev
|
|
|
86
86
|
|
|
87
87
|
- **intlayer**
|
|
88
88
|
|
|
89
|
-
Gói cốt lõi cung cấp các công cụ quốc tế hóa cho quản lý cấu hình, dịch thuật, [khai báo nội dung](https://github.com/aymericzip/intlayer/blob/main/docs/docs/
|
|
89
|
+
Gói cốt lõi cung cấp các công cụ quốc tế hóa cho quản lý cấu hình, dịch thuật, [khai báo nội dung](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dictionary/content_file.md), biên dịch lại, và [các lệnh CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/cli/index.md).
|
|
90
90
|
|
|
91
91
|
- **react-intlayer**
|
|
92
92
|
Gói tích hợp Intlayer với ứng dụng React. Nó cung cấp các context provider và hook cho việc quốc tế hóa trong React.
|
|
@@ -154,7 +154,7 @@ const config = {
|
|
|
154
154
|
module.exports = config;
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
-
> Thông qua tệp cấu hình này, bạn có thể thiết lập URL theo ngôn ngữ, chuyển hướng middleware, tên cookie, vị trí và phần mở rộng của các khai báo nội dung, tắt các log của Intlayer trên console, và nhiều hơn nữa. Để xem danh sách đầy đủ các tham số có sẵn, hãy tham khảo [tài liệu cấu hình](https://github.com/aymericzip/intlayer/blob/main/docs/docs/
|
|
157
|
+
> Thông qua tệp cấu hình này, bạn có thể thiết lập URL theo ngôn ngữ, chuyển hướng middleware, tên cookie, vị trí và phần mở rộng của các khai báo nội dung, tắt các log của Intlayer trên console, và nhiều hơn nữa. Để xem danh sách đầy đủ các tham số có sẵn, hãy tham khảo [tài liệu cấu hình](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/configuration.md).
|
|
158
158
|
|
|
159
159
|
### Bước 3: Tích hợp Intlayer vào cấu hình Vite của bạn
|
|
160
160
|
|
|
@@ -441,7 +441,7 @@ module.exports = appContent;
|
|
|
441
441
|
|
|
442
442
|
> Các khai báo nội dung của bạn có thể được định nghĩa ở bất kỳ đâu trong ứng dụng của bạn miễn là chúng được bao gồm trong thư mục `contentDir` (mặc định là `./src`). Và phù hợp với phần mở rộng tệp khai báo nội dung (mặc định là `.content.{json,ts,tsx,js,jsx,mjs,mjx,cjs,cjx}`).
|
|
443
443
|
|
|
444
|
-
> Để biết thêm chi tiết, hãy tham khảo [tài liệu khai báo nội dung](https://github.com/aymericzip/intlayer/blob/main/docs/docs/
|
|
444
|
+
> Để biết thêm chi tiết, hãy tham khảo [tài liệu khai báo nội dung](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dictionary/content_file.md).
|
|
445
445
|
|
|
446
446
|
> Nếu tệp nội dung của bạn bao gồm mã TSX, bạn nên xem xét việc import `import React from "react";` trong tệp nội dung của bạn.
|
|
447
447
|
|
|
@@ -596,7 +596,7 @@ module.exports = App;
|
|
|
596
596
|
> <img src={content.image.src.value} alt={content.image.value} />
|
|
597
597
|
> ```
|
|
598
598
|
|
|
599
|
-
> Để tìm hiểu thêm về hook `useIntlayer`, hãy tham khảo [tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/
|
|
599
|
+
> Để tìm hiểu thêm về hook `useIntlayer`, hãy tham khảo [tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/react-intlayer/useIntlayer.md).
|
|
600
600
|
|
|
601
601
|
### (Tùy chọn) Bước 6: Thay đổi ngôn ngữ cho nội dung của bạn
|
|
602
602
|
|
|
@@ -648,7 +648,7 @@ const LocaleSwitcher = () => {
|
|
|
648
648
|
};
|
|
649
649
|
```
|
|
650
650
|
|
|
651
|
-
> Để tìm hiểu thêm về hook `useLocale`, hãy tham khảo [tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/
|
|
651
|
+
> Để tìm hiểu thêm về hook `useLocale`, hãy tham khảo [tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/react-intlayer/useLocale.md).
|
|
652
652
|
|
|
653
653
|
### (Tùy chọn) Bước 7: Thêm định tuyến theo ngôn ngữ vào ứng dụng của bạn
|
|
654
654
|
|
|
@@ -661,7 +661,7 @@ Ví dụ:
|
|
|
661
661
|
- https://example.com/fr/about
|
|
662
662
|
```
|
|
663
663
|
|
|
664
|
-
> Theo mặc định, các tuyến đường không được thêm tiền tố cho ngôn ngữ mặc định. Nếu bạn muốn thêm tiền tố cho ngôn ngữ mặc định, bạn có thể đặt tùy chọn `middleware.prefixDefault` thành `true` trong cấu hình của bạn. Xem thêm tại [tài liệu cấu hình](https://github.com/aymericzip/intlayer/blob/main/docs/docs/
|
|
664
|
+
> Theo mặc định, các tuyến đường không được thêm tiền tố cho ngôn ngữ mặc định. Nếu bạn muốn thêm tiền tố cho ngôn ngữ mặc định, bạn có thể đặt tùy chọn `middleware.prefixDefault` thành `true` trong cấu hình của bạn. Xem thêm tại [tài liệu cấu hình](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/configuration.md) để biết thêm thông tin.
|
|
665
665
|
|
|
666
666
|
Để thêm định tuyến theo ngôn ngữ vào ứng dụng của bạn, bạn có thể tạo một thành phần `LocaleRouter` bao bọc các tuyến đường của ứng dụng và xử lý định tuyến dựa trên ngôn ngữ. Dưới đây là ví dụ sử dụng [React Router](https://reactrouter.com/home):
|
|
667
667
|
|
|
@@ -1025,10 +1025,10 @@ const LocaleSwitcher = () => {
|
|
|
1025
1025
|
|
|
1026
1026
|
> Tham khảo tài liệu:
|
|
1027
1027
|
>
|
|
1028
|
-
> - [`useLocale` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/
|
|
1029
|
-
> - [`getLocaleName` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/
|
|
1030
|
-
> - [`getLocalizedUrl` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/
|
|
1031
|
-
> - [`getHTMLTextDir` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/
|
|
1028
|
+
> - [`useLocale` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/react-intlayer/useLocale.md)
|
|
1029
|
+
> - [`getLocaleName` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/intlayer/getLocaleName.md)
|
|
1030
|
+
> - [`getLocalizedUrl` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/intlayer/getLocalizedUrl.md)
|
|
1031
|
+
> - [`getHTMLTextDir` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/intlayer/getHTMLTextDir.md)
|
|
1032
1032
|
> - [`hrefLang` attribute](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=fr)
|
|
1033
1033
|
> - [`lang` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang)
|
|
1034
1034
|
> - [`dir` attribute`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir)
|
|
@@ -1225,11 +1225,10 @@ import {
|
|
|
1225
1225
|
} from "react";
|
|
1226
1226
|
import { useLocale } from "react-intlayer";
|
|
1227
1227
|
|
|
1228
|
-
export interface LinkProps
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
> {}
|
|
1228
|
+
export interface LinkProps extends DetailedHTMLProps<
|
|
1229
|
+
AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
1230
|
+
HTMLAnchorElement
|
|
1231
|
+
> {}
|
|
1233
1232
|
|
|
1234
1233
|
/**
|
|
1235
1234
|
* Hàm tiện ích để kiểm tra xem một URL có phải là liên kết ngoài không.
|
|
@@ -1402,6 +1401,4 @@ Tiện ích mở rộng này cung cấp:
|
|
|
1402
1401
|
|
|
1403
1402
|
### Tiến xa hơn
|
|
1404
1403
|
|
|
1405
|
-
Để tiến xa hơn, bạn có thể triển khai [trình soạn thảo trực quan](https://github.com/aymericzip/intlayer/blob/main/docs/docs/
|
|
1406
|
-
|
|
1407
|
-
---
|
|
1404
|
+
Để tiến xa hơn, bạn có thể triển khai [trình soạn thảo trực quan](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_visual_editor.md) hoặc tách nội dung của bạn ra ngoài bằng cách sử dụng [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_CMS.md).
|
|
@@ -22,6 +22,7 @@ slugs:
|
|
|
22
22
|
- doc
|
|
23
23
|
- plugin
|
|
24
24
|
- sync-json
|
|
25
|
+
youtubeVideo: https://www.youtube.com/watch?v=MpGMxniDHNg
|
|
25
26
|
history:
|
|
26
27
|
- version: 6.1.6
|
|
27
28
|
date: 2025-10-05
|
|
@@ -30,6 +31,8 @@ history:
|
|
|
30
31
|
|
|
31
32
|
# Đồng bộ JSON (cầu nối i18n)
|
|
32
33
|
|
|
34
|
+
<iframe title="Cách giữ bản dịch JSON của bạn đồng bộ với Intlayer" class="m-auto aspect-[16/9] w-full overflow-hidden rounded-lg border-0" allow="autoplay; gyroscope;" loading="lazy" width="1080" height="auto" src="https://www.youtube.com/embed/MpGMxniDHNg?autoplay=0&origin=http://intlayer.org&controls=0&rel=1"/>
|
|
35
|
+
|
|
33
36
|
Sử dụng Intlayer như một tiện ích bổ sung cho bộ công cụ i18n hiện có của bạn. Plugin này giữ cho các thông điệp JSON của bạn đồng bộ với từ điển Intlayer để bạn có thể:
|
|
34
37
|
|
|
35
38
|
- Giữ nguyên i18next, next-intl, react-intl, vue-i18n, next-translate, nuxt-i18n, Solid-i18next, svelte-i18n, v.v.
|
|
@@ -19,9 +19,12 @@ slugs:
|
|
|
19
19
|
applicationTemplate: https://github.com/aymericzip/intlayer-tanstack-start-template
|
|
20
20
|
youtubeVideo: https://www.youtube.com/watch?v=_XTdKVWaeqg
|
|
21
21
|
history:
|
|
22
|
+
- version: 7.4.0
|
|
23
|
+
date: 2025-12-11
|
|
24
|
+
changes: 引入 validatePrefix 并添加步骤 14: 处理带有本地化路由的 404 页面。
|
|
22
25
|
- version: 7.3.9
|
|
23
26
|
date: 2025-12-05
|
|
24
|
-
changes:
|
|
27
|
+
changes: 添加步骤 13: 在您的 server actions 中获取 locale (可选)
|
|
25
28
|
- version: 5.8.1
|
|
26
29
|
date: 2025-09-09
|
|
27
30
|
changes: 为 Tanstack Start 添加支持
|
|
@@ -237,7 +240,7 @@ export default appContent;
|
|
|
237
240
|
import type { FC } from "react";
|
|
238
241
|
|
|
239
242
|
import { Link, type LinkComponentProps } from "@tanstack/react-router";
|
|
240
|
-
import { useLocale } from "intlayer";
|
|
243
|
+
import { useLocale } from "react-intlayer";
|
|
241
244
|
|
|
242
245
|
export const LOCALE_ROUTE = "{-$locale}" as const;
|
|
243
246
|
|
|
@@ -591,7 +594,134 @@ export const getLocaleServer = createServerFn().handler(async () => {
|
|
|
591
594
|
|
|
592
595
|
---
|
|
593
596
|
|
|
594
|
-
### 第14
|
|
597
|
+
### 第14步:管理未找到的页面(可选)
|
|
598
|
+
|
|
599
|
+
当用户访问不存在的页面时,您可以显示自定义的未找到页面,并且区域设置前缀可能会影响未找到页面的触发方式。
|
|
600
|
+
|
|
601
|
+
#### 了解 TanStack Router 使用区域设置前缀的 404 处理
|
|
602
|
+
|
|
603
|
+
在 TanStack Router 中,使用本地化路由处理 404 页面需要采用多层方法:
|
|
604
|
+
|
|
605
|
+
1. **专用 404 路由**:用于显示 404 UI 的特定路由
|
|
606
|
+
2. **路由级验证**:验证区域设置前缀并将无效的前缀重定向到 404
|
|
607
|
+
3. **捕获所有路由**:捕获区域设置段内任何不匹配的路径
|
|
608
|
+
|
|
609
|
+
```tsx fileName="src/routes/{-$locale}/404.tsx"
|
|
610
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
611
|
+
|
|
612
|
+
// 这将创建一个专用的 /[locale]/404 路由
|
|
613
|
+
// 它既作为直接路由使用,也可以在其他文件中作为组件导入
|
|
614
|
+
export const Route = createFileRoute("/{-$locale}/404")({
|
|
615
|
+
component: NotFoundComponent,
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
// 单独导出,以便可以在 notFoundComponent 和 catch-all 路由中重用
|
|
619
|
+
export function NotFoundComponent() {
|
|
620
|
+
return (
|
|
621
|
+
<div>
|
|
622
|
+
<h1>404</h1>
|
|
623
|
+
</div>
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
```tsx fileName="src/routes/__root.tsx"
|
|
629
|
+
import { createRootRoute } from "@tanstack/react-router";
|
|
630
|
+
|
|
631
|
+
// 根路由作为顶级布局
|
|
632
|
+
// 它不直接处理 404 - 这被委托给子路由
|
|
633
|
+
// 这使根路由保持简单,并让区域设置感知的路由管理自己的 404 逻辑
|
|
634
|
+
export const Route = createRootRoute({
|
|
635
|
+
component: Outlet,
|
|
636
|
+
});
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
```tsx fileName="src/routes/{-$locale}/route.tsx"
|
|
640
|
+
import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";
|
|
641
|
+
import { validatePrefix } from "intlayer";
|
|
642
|
+
import { IntlayerProvider, useLocale } from "react-intlayer";
|
|
643
|
+
|
|
644
|
+
import { LocaleSwitcher } from "@/components/locale-switcher";
|
|
645
|
+
import { NotFoundComponent } from "./404";
|
|
646
|
+
|
|
647
|
+
export const Route = createFileRoute("/{-$locale}")({
|
|
648
|
+
// beforeLoad 在路由渲染之前运行(在服务器和客户端上)
|
|
649
|
+
// 这是验证区域设置前缀的理想位置
|
|
650
|
+
beforeLoad: ({ params }) => {
|
|
651
|
+
// 从路由参数获取区域设置(不是从服务器标头,因为 beforeLoad 在客户端和服务器上都会运行)
|
|
652
|
+
const localeParam = params.locale;
|
|
653
|
+
|
|
654
|
+
// validatePrefix 检查区域设置是否根据您的 intlayer 配置有效
|
|
655
|
+
// 返回: { isValid: boolean, localePrefix: string }
|
|
656
|
+
// - isValid: 如果前缀匹配配置的区域设置(或当前缀可选时为空),则为 true
|
|
657
|
+
// - localePrefix: 已验证的前缀或用于重定向的默认区域设置前缀
|
|
658
|
+
const { isValid, localePrefix } = validatePrefix(localeParam);
|
|
659
|
+
|
|
660
|
+
if (isValid) {
|
|
661
|
+
// 区域设置有效,允许路由正常渲染
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// 无效的区域设置前缀(例如,/xyz/about 其中 "xyz" 不是有效的区域设置)
|
|
666
|
+
// 重定向到具有有效区域设置前缀的 404 页面
|
|
667
|
+
// 这确保 404 页面仍然正确本地化
|
|
668
|
+
throw redirect({
|
|
669
|
+
to: "/{-$locale}/404",
|
|
670
|
+
params: { locale: localePrefix },
|
|
671
|
+
});
|
|
672
|
+
},
|
|
673
|
+
component: RouteComponent,
|
|
674
|
+
// notFoundComponent 在子路由不存在时被调用
|
|
675
|
+
// 例如,/en/不存在的页面 在 /en 布局内触发此操作
|
|
676
|
+
notFoundComponent: NotFoundLayout,
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
function RouteComponent() {
|
|
680
|
+
const { defaultLocale } = useLocale();
|
|
681
|
+
const { locale } = Route.useParams();
|
|
682
|
+
|
|
683
|
+
return (
|
|
684
|
+
// 用 IntlayerProvider 包装整个区域设置段
|
|
685
|
+
// 当区域设置参数为 undefined 时回退到 defaultLocale(可选前缀模式)
|
|
686
|
+
<IntlayerProvider locale={locale ?? defaultLocale}>
|
|
687
|
+
<Outlet />
|
|
688
|
+
</IntlayerProvider>
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// NotFoundLayout 用 IntlayerProvider 包装 404 组件
|
|
693
|
+
// 这确保翻译在 404 页面上仍然有效
|
|
694
|
+
function NotFoundLayout() {
|
|
695
|
+
const { defaultLocale } = useLocale();
|
|
696
|
+
const { locale } = Route.useParams();
|
|
697
|
+
|
|
698
|
+
return (
|
|
699
|
+
<IntlayerProvider locale={locale ?? defaultLocale}>
|
|
700
|
+
<NotFoundComponent />
|
|
701
|
+
{/* 包含 LocaleSwitcher,以便用户即使在 404 页面上也可以更改语言 */}
|
|
702
|
+
<LocaleSwitcher />
|
|
703
|
+
</IntlayerProvider>
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
```tsx fileName="src/routes/{-$locale}/$.tsx"
|
|
709
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
710
|
+
|
|
711
|
+
import { NotFoundComponent } from "./404";
|
|
712
|
+
|
|
713
|
+
// $ (splat/catch-all) 路由匹配任何与其他路由不匹配的路径
|
|
714
|
+
// 例如,/en/某个/深度/嵌套/无效/路径
|
|
715
|
+
// 这确保区域设置内所有不匹配的路径都显示 404 页面
|
|
716
|
+
// 没有这个,不匹配的深层路径可能会显示空白页面或错误
|
|
717
|
+
export const Route = createFileRoute("/{-$locale}/$")({
|
|
718
|
+
component: NotFoundComponent,
|
|
719
|
+
});
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
### 第15步:配置 TypeScript(可选)
|
|
595
725
|
|
|
596
726
|
Intlayer 使用模块增强来利用 TypeScript 的优势,使您的代码库更健壮。
|
|
597
727
|
|