@intlayer/docs 8.6.0 → 8.6.10
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/dist/cjs/doc.cjs.map +1 -1
- package/dist/cjs/generated/docs.entry.cjs +60 -0
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/esm/doc.mjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +60 -0
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/types/doc.d.ts.map +1 -1
- package/dist/types/generated/docs.entry.d.ts +3 -0
- package/dist/types/generated/docs.entry.d.ts.map +1 -1
- package/docs/ar/cli/index.md +54 -42
- package/docs/ar/cli/init.md +32 -20
- package/docs/ar/cli/standalone.md +91 -0
- package/docs/ar/configuration.md +39 -7
- package/docs/ar/custom_domains.md +250 -0
- package/docs/ar/intlayer_with_tanstack+solid.md +14 -33
- package/docs/ar/intlayer_with_tanstack.md +25 -16
- package/docs/ar/intlayer_with_vanilla.md +506 -0
- package/docs/bn/cli/index.md +195 -0
- package/docs/bn/cli/init.md +96 -0
- package/docs/bn/cli/standalone.md +91 -0
- package/docs/bn/configuration.md +46 -14
- package/docs/bn/custom_domains.md +250 -0
- package/docs/bn/intlayer_with_vanilla.md +506 -0
- package/docs/cs/cli/index.md +195 -0
- package/docs/cs/cli/init.md +96 -0
- package/docs/cs/cli/standalone.md +91 -0
- package/docs/cs/configuration.md +46 -7
- package/docs/cs/custom_domains.md +250 -0
- package/docs/cs/intlayer_with_vanilla.md +506 -0
- package/docs/de/cli/index.md +53 -41
- package/docs/de/cli/standalone.md +91 -0
- package/docs/de/configuration.md +46 -7
- package/docs/de/custom_domains.md +250 -0
- package/docs/de/intlayer_with_tanstack+solid.md +15 -36
- package/docs/de/intlayer_with_tanstack.md +25 -16
- package/docs/de/intlayer_with_vanilla.md +506 -0
- package/docs/en/bundle_optimization.md +288 -23
- package/docs/en/cli/index.md +6 -1
- package/docs/en/cli/init.md +13 -1
- package/docs/en/cli/standalone.md +91 -0
- package/docs/en/configuration.md +46 -7
- package/docs/en/custom_domains.md +245 -0
- package/docs/en/intlayer_with_tanstack+solid.md +15 -36
- package/docs/en/intlayer_with_tanstack.md +25 -16
- package/docs/en/intlayer_with_vanilla.md +506 -0
- package/docs/en-GB/cli/index.md +56 -44
- package/docs/en-GB/cli/init.md +28 -21
- package/docs/en-GB/cli/standalone.md +91 -0
- package/docs/en-GB/configuration.md +53 -14
- package/docs/en-GB/custom_domains.md +250 -0
- package/docs/en-GB/intlayer_with_tanstack+solid.md +15 -36
- package/docs/en-GB/intlayer_with_tanstack.md +25 -16
- package/docs/en-GB/intlayer_with_vanilla.md +506 -0
- package/docs/es/cli/index.md +65 -53
- package/docs/es/cli/init.md +33 -21
- package/docs/es/cli/standalone.md +91 -0
- package/docs/es/configuration.md +39 -1
- package/docs/es/custom_domains.md +250 -0
- package/docs/es/intlayer_with_tanstack+solid.md +15 -36
- package/docs/es/intlayer_with_tanstack.md +25 -16
- package/docs/es/intlayer_with_vanilla.md +506 -0
- package/docs/fr/cli/index.md +43 -31
- package/docs/fr/cli/init.md +37 -25
- package/docs/fr/cli/standalone.md +91 -0
- package/docs/fr/configuration.md +46 -7
- package/docs/fr/custom_domains.md +250 -0
- package/docs/fr/intlayer_with_tanstack+solid.md +15 -36
- package/docs/fr/intlayer_with_tanstack.md +25 -16
- package/docs/fr/intlayer_with_vanilla.md +506 -0
- package/docs/hi/cli/index.md +71 -59
- package/docs/hi/cli/init.md +37 -33
- package/docs/hi/cli/standalone.md +91 -0
- package/docs/hi/configuration.md +39 -7
- package/docs/hi/custom_domains.md +250 -0
- package/docs/hi/intlayer_with_tanstack+solid.md +14 -33
- package/docs/hi/intlayer_with_tanstack.md +25 -16
- package/docs/hi/intlayer_with_vanilla.md +506 -0
- package/docs/id/cli/index.md +59 -47
- package/docs/id/cli/init.md +32 -25
- package/docs/id/cli/standalone.md +91 -0
- package/docs/id/configuration.md +46 -7
- package/docs/id/custom_domains.md +250 -0
- package/docs/id/intlayer_with_tanstack+solid.md +14 -33
- package/docs/id/intlayer_with_tanstack.md +25 -16
- package/docs/id/intlayer_with_vanilla.md +506 -0
- package/docs/it/cli/index.md +58 -41
- package/docs/it/cli/init.md +37 -38
- package/docs/it/cli/standalone.md +91 -0
- package/docs/it/configuration.md +46 -7
- package/docs/it/custom_domains.md +250 -0
- package/docs/it/intlayer_with_tanstack+solid.md +15 -36
- package/docs/it/intlayer_with_tanstack.md +25 -16
- package/docs/it/intlayer_with_vanilla.md +506 -0
- package/docs/ja/cli/index.md +59 -47
- package/docs/ja/cli/init.md +36 -24
- package/docs/ja/cli/standalone.md +91 -0
- package/docs/ja/configuration.md +46 -7
- package/docs/ja/custom_domains.md +250 -0
- package/docs/ja/intlayer_with_tanstack+solid.md +15 -36
- package/docs/ja/intlayer_with_tanstack.md +25 -16
- package/docs/ja/intlayer_with_vanilla.md +506 -0
- package/docs/ko/cli/index.md +58 -46
- package/docs/ko/cli/init.md +39 -35
- package/docs/ko/cli/standalone.md +91 -0
- package/docs/ko/configuration.md +47 -8
- package/docs/ko/custom_domains.md +250 -0
- package/docs/ko/intlayer_with_tanstack+solid.md +15 -36
- package/docs/ko/intlayer_with_tanstack.md +25 -16
- package/docs/ko/intlayer_with_vanilla.md +506 -0
- package/docs/nl/cli/index.md +195 -0
- package/docs/nl/cli/init.md +96 -0
- package/docs/nl/cli/standalone.md +91 -0
- package/docs/nl/configuration.md +46 -7
- package/docs/nl/custom_domains.md +250 -0
- package/docs/nl/intlayer_with_vanilla.md +506 -0
- package/docs/pl/cli/index.md +56 -44
- package/docs/pl/cli/init.md +36 -32
- package/docs/pl/cli/standalone.md +91 -0
- package/docs/pl/configuration.md +46 -7
- package/docs/pl/custom_domains.md +250 -0
- package/docs/pl/intlayer_with_tanstack+solid.md +14 -33
- package/docs/pl/intlayer_with_tanstack.md +25 -16
- package/docs/pl/intlayer_with_vanilla.md +506 -0
- package/docs/pt/cli/index.md +64 -52
- package/docs/pt/cli/init.md +35 -31
- package/docs/pt/cli/standalone.md +91 -0
- package/docs/pt/configuration.md +46 -7
- package/docs/pt/custom_domains.md +250 -0
- package/docs/pt/intlayer_with_tanstack+solid.md +15 -36
- package/docs/pt/intlayer_with_tanstack.md +25 -16
- package/docs/pt/intlayer_with_vanilla.md +506 -0
- package/docs/ru/cli/index.md +54 -42
- package/docs/ru/cli/init.md +31 -27
- package/docs/ru/cli/standalone.md +91 -0
- package/docs/ru/configuration.md +46 -7
- package/docs/ru/custom_domains.md +250 -0
- package/docs/ru/intlayer_with_tanstack+solid.md +15 -36
- package/docs/ru/intlayer_with_tanstack.md +25 -16
- package/docs/ru/intlayer_with_vanilla.md +506 -0
- package/docs/tr/cli/index.md +64 -52
- package/docs/tr/cli/init.md +37 -30
- package/docs/tr/cli/standalone.md +91 -0
- package/docs/tr/configuration.md +46 -7
- package/docs/tr/custom_domains.md +250 -0
- package/docs/tr/intlayer_with_tanstack+solid.md +14 -33
- package/docs/tr/intlayer_with_tanstack.md +25 -16
- package/docs/tr/intlayer_with_vanilla.md +506 -0
- package/docs/uk/cli/index.md +60 -55
- package/docs/uk/cli/init.md +32 -20
- package/docs/uk/cli/standalone.md +91 -0
- package/docs/uk/configuration.md +46 -7
- package/docs/uk/custom_domains.md +250 -0
- package/docs/uk/intlayer_with_tanstack+solid.md +14 -33
- package/docs/uk/intlayer_with_tanstack.md +25 -16
- package/docs/uk/intlayer_with_vanilla.md +506 -0
- package/docs/ur/cli/index.md +195 -0
- package/docs/ur/cli/init.md +96 -0
- package/docs/ur/cli/standalone.md +91 -0
- package/docs/ur/configuration.md +46 -7
- package/docs/ur/custom_domains.md +250 -0
- package/docs/ur/intlayer_with_vanilla.md +506 -0
- package/docs/vi/cli/index.md +72 -61
- package/docs/vi/cli/init.md +33 -21
- package/docs/vi/cli/standalone.md +91 -0
- package/docs/vi/configuration.md +46 -7
- package/docs/vi/custom_domains.md +250 -0
- package/docs/vi/intlayer_with_tanstack+solid.md +14 -33
- package/docs/vi/intlayer_with_tanstack.md +25 -16
- package/docs/vi/intlayer_with_vanilla.md +506 -0
- package/docs/zh/cli/index.md +56 -49
- package/docs/zh/cli/init.md +30 -18
- package/docs/zh/cli/standalone.md +91 -0
- package/docs/zh/configuration.md +46 -7
- package/docs/zh/custom_domains.md +250 -0
- package/docs/zh/intlayer_with_tanstack+solid.md +15 -36
- package/docs/zh/intlayer_with_tanstack.md +25 -16
- package/docs/zh/intlayer_with_vanilla.md +506 -0
- package/package.json +8 -8
- package/src/doc.ts +4 -1
- package/src/generated/docs.entry.ts +60 -0
- package/docs/ar/bundle_optimization.md +0 -185
- package/docs/de/bundle_optimization.md +0 -195
- package/docs/en-GB/bundle_optimization.md +0 -184
- package/docs/es/bundle_optimization.md +0 -194
- package/docs/fr/bundle_optimization.md +0 -184
- package/docs/hi/bundle_optimization.md +0 -185
- package/docs/id/bundle_optimization.md +0 -185
- package/docs/it/bundle_optimization.md +0 -185
- package/docs/ja/bundle_optimization.md +0 -185
- package/docs/ko/bundle_optimization.md +0 -185
- package/docs/pl/bundle_optimization.md +0 -185
- package/docs/pt/bundle_optimization.md +0 -184
- package/docs/ru/bundle_optimization.md +0 -185
- package/docs/tr/bundle_optimization.md +0 -184
- package/docs/uk/bundle_optimization.md +0 -186
- package/docs/vi/bundle_optimization.md +0 -185
- package/docs/zh/bundle_optimization.md +0 -185
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-04-02
|
|
3
|
+
updatedAt: 2026-04-02
|
|
4
|
+
title: 自定义域名
|
|
5
|
+
description: 了解如何在 Intlayer 中配置基于域名的语言路由,以便从专用主机名提供不同的语言版本。
|
|
6
|
+
keywords:
|
|
7
|
+
- 自定义域名
|
|
8
|
+
- 域名路由
|
|
9
|
+
- 路由
|
|
10
|
+
- 国际化
|
|
11
|
+
- i18n
|
|
12
|
+
slugs:
|
|
13
|
+
- doc
|
|
14
|
+
- concept
|
|
15
|
+
- custom_domains
|
|
16
|
+
history:
|
|
17
|
+
- version: 8.5.0
|
|
18
|
+
date: 2026-04-02
|
|
19
|
+
changes: "通过 routing.domains 配置添加基于域名的语言路由。"
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# 自定义域名
|
|
23
|
+
|
|
24
|
+
Intlayer 支持基于域名的语言路由,允许您从专用主机名提供特定语言。例如,可以将中国访问者引导至 `intlayer.zh` 而不是 `intlayer.org/zh`。
|
|
25
|
+
|
|
26
|
+
## 工作原理
|
|
27
|
+
|
|
28
|
+
`routing` 中的 `domains` 映射将每种语言与一个主机名关联。Intlayer 在两个地方使用此映射:
|
|
29
|
+
|
|
30
|
+
1. **URL 生成** (`getLocalizedUrl`):当目标语言位于与当前页面 _不同_ 的域名上时,返回绝对 URL(例如 `https://intlayer.zh/about`)。当两个域名匹配时,返回相对 URL(例如 `/fr/about`)。
|
|
31
|
+
2. **服务器代理** (Next.js & Vite):进入的请求根据到达到达的域名进行重定向或重写。
|
|
32
|
+
|
|
33
|
+
### 专用域名 vs 共享域名
|
|
34
|
+
|
|
35
|
+
关键区别在于 **专用性**:
|
|
36
|
+
|
|
37
|
+
- **专用域名** — 只有一种语言映射到该主机名(例如 `zh → intlayer.zh`)。域名本身标识了语言,因此路径中不添加语言前缀。`https://intlayer.zh/about` 提供中文内容。
|
|
38
|
+
- **共享域名** — 多种语言映射到同一个主机名(例如 `en` 和 `fr` 都映射到 `intlayer.org`)。应用正规的基于前缀的路由。`intlayer.org/fr/about` 提供法语内容。
|
|
39
|
+
|
|
40
|
+
## 配置
|
|
41
|
+
|
|
42
|
+
```typescript fileName="intlayer.config.ts"
|
|
43
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
44
|
+
|
|
45
|
+
const config: IntlayerConfig = {
|
|
46
|
+
internationalization: {
|
|
47
|
+
locales: [
|
|
48
|
+
Locales.ENGLISH,
|
|
49
|
+
Locales.FRENCH,
|
|
50
|
+
Locales.SPANISH,
|
|
51
|
+
Locales.CHINESE,
|
|
52
|
+
],
|
|
53
|
+
defaultLocale: Locales.ENGLISH,
|
|
54
|
+
},
|
|
55
|
+
routing: {
|
|
56
|
+
mode: "prefix-no-default",
|
|
57
|
+
domains: {
|
|
58
|
+
// 共享域名 — en 和 fr 在 intlayer.org 上使用前缀路由
|
|
59
|
+
en: "intlayer.org",
|
|
60
|
+
// 专用域名 — zh 有其自己的主机名,不需要 /zh/ 前缀
|
|
61
|
+
zh: "intlayer.zh",
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default config;
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
末在 `domains` 中列出的语言将继续使用标准前缀路由,没有任何域名覆盖。
|
|
70
|
+
|
|
71
|
+
## URL 生成
|
|
72
|
+
|
|
73
|
+
`getLocalizedUrl` 根据调用上下文自动产生正确的 URL 类型。
|
|
74
|
+
|
|
75
|
+
### 同域名语言(相对 URL)
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
// 当前页面: intlayer.org/about
|
|
79
|
+
getLocalizedUrl("/about", "fr", { currentDomain: "intlayer.org" });
|
|
80
|
+
// → "/fr/about"
|
|
81
|
+
|
|
82
|
+
getLocalizedUrl("/about", "en", { currentDomain: "intlayer.org" });
|
|
83
|
+
// → "/about" (默认语言,无前缀)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 跨域名语言(绝对 URL)
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
// 当前页面: intlayer.org/about
|
|
90
|
+
getLocalizedUrl("/about", "zh", { currentDomain: "intlayer.org" });
|
|
91
|
+
// → "https://intlayer.zh/about" (专用域名,无 /zh/ 前缀)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 从语言自己的域名提供服务
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
// 当前页面: intlayer.zh/about
|
|
98
|
+
getLocalizedUrl("/about", "zh", { currentDomain: "intlayer.zh" });
|
|
99
|
+
// → "/about" (已在正确的域名上 — 相对 URL)
|
|
100
|
+
|
|
101
|
+
getLocalizedUrl("/about", "fr", { currentDomain: "intlayer.zh" });
|
|
102
|
+
// → "https://intlayer.org/fr/about" (跨域名链接回到 intlayer.org)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 当前域名自动检测
|
|
106
|
+
|
|
107
|
+
`currentDomain` 是可选的。省略时,`getLocalizedUrl` 按此顺序解析:
|
|
108
|
+
|
|
109
|
+
1. 绝对输入 URL 的主机名(例如 `https://intlayer.org/about` → `intlayer.org`)。
|
|
110
|
+
2. 浏览器环境中的 `window.location.hostname`。
|
|
111
|
+
3. 如果两者均不可用(不带显式选项的 SSR),则为同域名语言返回相对 URL,并且不生成绝对 URL — 这是安全的回退方案。
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
// 浏览器 — window.location.hostname === 'intlayer.org'
|
|
115
|
+
getLocalizedUrl("/about", "zh");
|
|
116
|
+
// → "https://intlayer.zh/about" (从 window 自动检测)
|
|
117
|
+
|
|
118
|
+
// 从绝对 URL — 自动检测域名
|
|
119
|
+
getLocalizedUrl("https://intlayer.org/about", "zh");
|
|
120
|
+
// → "https://intlayer.zh/about"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 带有域名的 `getMultilingualUrls`
|
|
124
|
+
|
|
125
|
+
`getMultilingualUrls` 为每种语言调用 `getLocalizedUrl`,因此它根据调用者的域名产生相对和绝对 URL 的混合:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
// currentDomain: 'intlayer.org'
|
|
129
|
+
getMultilingualUrls("/about", { currentDomain: "intlayer.org" });
|
|
130
|
+
// {
|
|
131
|
+
// en: "/about",
|
|
132
|
+
// fr: "/fr/about",
|
|
133
|
+
// es: "/es/about",
|
|
134
|
+
// zh: "https://intlayer.zh/about",
|
|
135
|
+
// }
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
这些绝对 URL 已准备好用于 SEO 的 `<link rel="alternate" hreflang="...">` 标签。
|
|
139
|
+
|
|
140
|
+
## 代理行为
|
|
141
|
+
|
|
142
|
+
### Next.js
|
|
143
|
+
|
|
144
|
+
`intlayerProxy` 中间件自动处理域名路由。将其添加到您的 `middleware.ts` 中:
|
|
145
|
+
|
|
146
|
+
```typescript fileName="middleware.ts"
|
|
147
|
+
export { intlayerProxy as default } from "next-intlayer/proxy";
|
|
148
|
+
|
|
149
|
+
export const config = {
|
|
150
|
+
matcher: "/((?!api|static|assets|robots|sitemap|.*\\..*|_next).*)",
|
|
151
|
+
};
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**重定向** — 请求到达了给定语言前缀的错误域名:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
GET intlayer.org/zh/about
|
|
158
|
+
→ 301 https://intlayer.zh/about
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**重写** — 请求到达了语言的专用域名且没有前缀:
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
GET intlayer.zh/about
|
|
165
|
+
→ 重写至 /zh/about (仅 Next.js 内部路由,URL 保持简洁)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Vite
|
|
169
|
+
|
|
170
|
+
`intlayerProxy` Vite 插件在开发期间应用相同的逻辑:
|
|
171
|
+
|
|
172
|
+
```typescript fileName="vite.config.ts"
|
|
173
|
+
import { defineConfig } from "vite";
|
|
174
|
+
import { intlayerProxy } from "vite-intlayer";
|
|
175
|
+
|
|
176
|
+
export default defineConfig({
|
|
177
|
+
plugins: [intlayerProxy()],
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
> **注意**: 在本地开发中,您通常位于 `localhost`,因此跨域名重定向将指向实时域名,而不是另一个本地端口。如果需要在本地测试多域名路由,请使用 hosts 文件覆盖(例如 `127.0.0.1 intlayer.zh`)或反向代理。
|
|
182
|
+
|
|
183
|
+
## 语言切换器
|
|
184
|
+
|
|
185
|
+
来自 `next-intlayer` 的 `useLocale` hook 自动处理域名感知的导航。当用户切换到不同域名上的语言时,该 hook 会执行全页面导航 (`window.location.href`) 而不是客户端路由推送,因为 Next.js 路由无法跨越源 (origins)。
|
|
186
|
+
|
|
187
|
+
```tsx fileName="components/LocaleSwitcher.tsx"
|
|
188
|
+
"use client";
|
|
189
|
+
|
|
190
|
+
import { useLocale } from "next-intlayer";
|
|
191
|
+
|
|
192
|
+
export const LocaleSwitcher = () => {
|
|
193
|
+
const { availableLocales, locale, setLocale } = useLocale();
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<ul>
|
|
197
|
+
{availableLocales.map((localeEl) => (
|
|
198
|
+
<li key={localeEl}>
|
|
199
|
+
<button
|
|
200
|
+
onClick={() => setLocale(localeEl)}
|
|
201
|
+
aria-current={localeEl === locale ? "true" : undefined}
|
|
202
|
+
>
|
|
203
|
+
{l.toUpperCase()}
|
|
204
|
+
</button>
|
|
205
|
+
</li>
|
|
206
|
+
))}
|
|
207
|
+
</ul>
|
|
208
|
+
);
|
|
209
|
+
};
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
无需额外配置 — `useLocale` 内部检测 `window.location.hostname` 并决定是进行 `router.replace`(同域名)还是 `window.location.href`(跨域名)。
|
|
213
|
+
|
|
214
|
+
## SEO: `hreflang` 备用链接
|
|
215
|
+
|
|
216
|
+
基于域名的路由通常与 `hreflang` 一起使用,以告诉搜索引擎为每种语言索引哪个 URL。使用 `getMultilingualUrls` 生成全套备用 URL:
|
|
217
|
+
|
|
218
|
+
```tsx fileName="app/[locale]/layout.tsx"
|
|
219
|
+
import { getMultilingualUrls } from "intlayer";
|
|
220
|
+
import type { Metadata } from "next";
|
|
221
|
+
|
|
222
|
+
export const generateMetadata = (): Metadata => {
|
|
223
|
+
const alternates = getMultilingualUrls("/", {
|
|
224
|
+
currentDomain: process.env.NEXT_PUBLIC_DOMAIN, // 例如 "intlayer.org"
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
alternates: {
|
|
229
|
+
languages: alternates,
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
这会产生:
|
|
236
|
+
|
|
237
|
+
```html
|
|
238
|
+
<link rel="alternate" hreflang="en" href="https://intlayer.org/" />
|
|
239
|
+
<link rel="alternate" hreflang="fr" href="https://intlayer.org/fr/" />
|
|
240
|
+
<link rel="alternate" hreflang="es" href="https://intlayer.org/es/" />
|
|
241
|
+
<link rel="alternate" hreflang="zh" href="https://intlayer.zh/" />
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## 核心实用程序
|
|
245
|
+
|
|
246
|
+
| 实用程序 | 描述 |
|
|
247
|
+
| ------------------------------------------------- | ----------------------------------------------------------- |
|
|
248
|
+
| `getLocalizedUrl(url, locale, { currentDomain })` | 返回相对或绝对 URL,取决于目标语言是否在当前域名上。 |
|
|
249
|
+
| `getMultilingualUrls(url, { currentDomain })` | 返回语言键控的本地化 URL 映射,根据需要混合相对和绝对 URL。 |
|
|
250
|
+
| `getPrefix(locale, { domains })` | 为专用域名语言返回空前缀,否则返回普通前缀。 |
|
|
@@ -17,6 +17,7 @@ slugs:
|
|
|
17
17
|
- doc
|
|
18
18
|
- environment
|
|
19
19
|
- tanstack-start
|
|
20
|
+
- solid
|
|
20
21
|
applicationTemplate: https://github.com/aymericzip/intlayer-tanstack-start-solid-template
|
|
21
22
|
youtubeVideo: https://www.youtube.com/watch?v=_XTdKVWaeqg
|
|
22
23
|
history:
|
|
@@ -163,59 +164,45 @@ export default defineConfig({
|
|
|
163
164
|
|
|
164
165
|
### 第 5 步:创建根布局 (Root Layout)
|
|
165
166
|
|
|
166
|
-
配置您的根布局以支持国际化,使用 `
|
|
167
|
+
配置您的根布局以支持国际化,使用 `useParams` 检测当前语言,并在 `html` 标签上设置 `lang` 和 `dir` 属性。
|
|
167
168
|
|
|
168
169
|
```tsx fileName="src/routes/__root.tsx"
|
|
169
170
|
import {
|
|
170
171
|
HeadContent,
|
|
171
|
-
Outlet,
|
|
172
172
|
Scripts,
|
|
173
173
|
createRootRouteWithContext,
|
|
174
|
-
useMatches,
|
|
175
174
|
} from "@tanstack/solid-router";
|
|
176
|
-
import { TanStackRouterDevtools } from "@tanstack/solid-router-devtools";
|
|
177
175
|
import { HydrationScript } from "solid-js/web";
|
|
178
|
-
import { Suspense } from "solid-js";
|
|
176
|
+
import { Suspense, type ParentComponent } from "solid-js";
|
|
179
177
|
import { IntlayerProvider } from "solid-intlayer";
|
|
180
|
-
import { defaultLocale, getHTMLTextDir
|
|
178
|
+
import { defaultLocale, getHTMLTextDir } from "intlayer";
|
|
179
|
+
import { Route as LocaleRoute } from "./{-$locale}/route";
|
|
181
180
|
|
|
182
181
|
export const Route = createRootRouteWithContext()({
|
|
183
182
|
shellComponent: RootComponent,
|
|
184
183
|
});
|
|
185
184
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
function RootComponent() {
|
|
191
|
-
const matches = useMatches();
|
|
192
|
-
|
|
193
|
-
// 尝试在任何活动匹配的参数中查找语言
|
|
194
|
-
// 这假设您在路由树中使用了动态段 "/{-$locale}"
|
|
195
|
-
const locale =
|
|
196
|
-
(
|
|
197
|
-
matches().find((match) => match.routeId === "/{-$locale}/")
|
|
198
|
-
?.params as Params
|
|
199
|
-
)?.locale ?? defaultLocale;
|
|
185
|
+
const RootComponent: ParentComponent = (props) => {
|
|
186
|
+
const params = LocaleRoute.useParams();
|
|
187
|
+
const locale = params()?.locale ?? defaultLocale;
|
|
200
188
|
|
|
201
189
|
return (
|
|
202
190
|
<html dir={getHTMLTextDir(locale)} lang={locale}>
|
|
203
191
|
<head>
|
|
204
192
|
<HydrationScript />
|
|
193
|
+
<HeadContent />
|
|
205
194
|
</head>
|
|
206
195
|
<body>
|
|
207
|
-
<HeadContent />
|
|
208
196
|
<IntlayerProvider locale={locale}>
|
|
209
197
|
<Suspense>
|
|
210
|
-
|
|
211
|
-
<TanStackRouterDevtools />
|
|
198
|
+
{props.children}
|
|
212
199
|
</Suspense>
|
|
213
200
|
</IntlayerProvider>
|
|
214
201
|
<Scripts />
|
|
215
202
|
</body>
|
|
216
203
|
</html>
|
|
217
204
|
);
|
|
218
|
-
}
|
|
205
|
+
};
|
|
219
206
|
```
|
|
220
207
|
|
|
221
208
|
### 第 6 步:创建语言布局 (可选)
|
|
@@ -459,18 +446,12 @@ export default LocaleSwitcher;
|
|
|
459
446
|
|
|
460
447
|
### 第 11 步:管理 HTML 属性
|
|
461
448
|
|
|
462
|
-
正如第 5 步所示,您可以在根组件中使用 `
|
|
449
|
+
正如第 5 步所示,您可以在根组件中使用 `useParams` 来管理 `html` 标签的 `lang` 和 `dir` 属性。这确保了在服务器端和客户端都设置了正确的属性。
|
|
463
450
|
|
|
464
451
|
```tsx fileName="src/routes/__root.tsx"
|
|
465
452
|
const RootComponent: ParentComponent = (props) => {
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
// 尝试在任何活动匹配的参数中查找语言
|
|
469
|
-
const locale =
|
|
470
|
-
(
|
|
471
|
-
matches().find((match) => match.routeId === "/{-$locale}/")
|
|
472
|
-
?.params as Params
|
|
473
|
-
)?.locale ?? defaultLocale;
|
|
453
|
+
const params = LocaleRoute.useParams();
|
|
454
|
+
const locale = params()?.locale ?? defaultLocale;
|
|
474
455
|
|
|
475
456
|
return (
|
|
476
457
|
<html dir={getHTMLTextDir(locale)} lang={locale}>
|
|
@@ -879,9 +860,7 @@ export default defineConfig({
|
|
|
879
860
|
import { createFileRoute } from "@tanstack/solid-router";
|
|
880
861
|
import { generateSitemap } from "intlayer";
|
|
881
862
|
|
|
882
|
-
const SITE_URL =
|
|
883
|
-
import.meta.env.VITE_SITE_URL ?? "http://localhost:3000"
|
|
884
|
-
).replace(/\/$/, "");
|
|
863
|
+
const SITE_URL = "http://localhost:3000";
|
|
885
864
|
|
|
886
865
|
export const Route = createFileRoute("/sitemap.xml")({
|
|
887
866
|
server: {
|
|
@@ -183,31 +183,41 @@ export default config;
|
|
|
183
183
|
|
|
184
184
|
### 第五步:创建根布局
|
|
185
185
|
|
|
186
|
-
配置您的根布局以支持国际化,使用 `
|
|
186
|
+
配置您的根布局以支持国际化,使用 `useParams` 检测当前 locale 并在 `html` 标签上设置 `lang` 和 `dir` 属性。
|
|
187
187
|
|
|
188
188
|
```tsx fileName="src/routes/__root.tsx"
|
|
189
189
|
import {
|
|
190
190
|
createRootRouteWithContext,
|
|
191
191
|
HeadContent,
|
|
192
|
-
Outlet,
|
|
193
192
|
Scripts,
|
|
194
|
-
useMatches,
|
|
195
193
|
} from "@tanstack/react-router";
|
|
196
194
|
import { defaultLocale, getHTMLTextDir } from "intlayer";
|
|
197
195
|
import { type ReactNode } from "react";
|
|
198
196
|
import { IntlayerProvider } from "react-intlayer";
|
|
197
|
+
import { Route as LocaleRoute } from "./{-$locale}/route";
|
|
199
198
|
|
|
200
199
|
export const Route = createRootRouteWithContext<{}>()({
|
|
200
|
+
head: () => ({
|
|
201
|
+
meta: [
|
|
202
|
+
{
|
|
203
|
+
charSet: "utf-8",
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
content: "width=device-width, initial-scale=1",
|
|
207
|
+
name: "viewport",
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
title: "TanStack Start Starter",
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
}),
|
|
214
|
+
|
|
201
215
|
shellComponent: RootDocument,
|
|
202
216
|
});
|
|
203
217
|
|
|
204
218
|
function RootDocument({ children }: { children: ReactNode }) {
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
// 尝试在任何活动匹配的参数中找到 locale
|
|
208
|
-
// 这假设您在路由树中使用动态段 "/{-$locale}"
|
|
209
|
-
const localeRoute = matches.find((match) => match.routeId === "/{-$locale}");
|
|
210
|
-
const locale = localeRoute?.params?.locale ?? defaultLocale;
|
|
219
|
+
const params = LocaleRoute.useParams();
|
|
220
|
+
const locale = params?.locale ?? defaultLocale;
|
|
211
221
|
|
|
212
222
|
return (
|
|
213
223
|
<html dir={getHTMLTextDir(locale)} lang={locale}>
|
|
@@ -215,7 +225,9 @@ function RootDocument({ children }: { children: ReactNode }) {
|
|
|
215
225
|
<HeadContent />
|
|
216
226
|
</head>
|
|
217
227
|
<body>
|
|
218
|
-
<IntlayerProvider locale={locale}>
|
|
228
|
+
<IntlayerProvider locale={locale}>
|
|
229
|
+
{children}
|
|
230
|
+
</IntlayerProvider>
|
|
219
231
|
<Scripts />
|
|
220
232
|
</body>
|
|
221
233
|
</html>
|
|
@@ -562,15 +574,12 @@ export const LocaleSwitcher: FC = () => {
|
|
|
562
574
|
|
|
563
575
|
### 第十一步:HTML 属性管理
|
|
564
576
|
|
|
565
|
-
如第5步所示,您可以在根组件中使用 `
|
|
577
|
+
如第5步所示,您可以在根组件中使用 `useParams` 管理 `html` 标签的 `lang` 和 `dir` 属性。这确保在服务器和客户端上正确设置属性。
|
|
566
578
|
|
|
567
579
|
```tsx fileName="src/routes/__root.tsx"
|
|
568
580
|
function RootDocument({ children }: { children: ReactNode }) {
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
// 尝试在任何活动匹配的参数中找到 locale
|
|
572
|
-
const localeRoute = matches.find((match) => match.routeId === "/{-$locale}");
|
|
573
|
-
const locale = localeRoute?.params?.locale ?? defaultLocale;
|
|
581
|
+
const params = LocaleRoute.useParams();
|
|
582
|
+
const locale = params?.locale ?? defaultLocale;
|
|
574
583
|
|
|
575
584
|
return (
|
|
576
585
|
<html dir={getHTMLTextDir(locale)} lang={locale}>
|