@intlayer/docs 5.7.6 → 5.7.8
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/generated/docs.entry.cjs +44 -238
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +44 -238
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/types/generated/docs.entry.d.ts +1 -2
- package/dist/types/generated/docs.entry.d.ts.map +1 -1
- package/docs/ar/CI_CD.md +67 -41
- package/docs/ar/intlayer_with_tanstack.md +457 -0
- package/docs/ar/packages/next-intlayer/index.md +0 -1
- package/docs/ar/packages/react-intlayer/index.md +0 -1
- package/docs/de/CI_CD.md +63 -37
- package/docs/de/intlayer_with_tanstack.md +458 -0
- package/docs/de/packages/next-intlayer/index.md +0 -1
- package/docs/de/packages/react-intlayer/index.md +0 -1
- package/docs/en/CI_CD.md +51 -27
- package/docs/en/intlayer_with_tanstack.md +452 -0
- package/docs/en/packages/next-intlayer/index.md +0 -1
- package/docs/en/packages/react-intlayer/index.md +0 -1
- package/docs/en-GB/CI_CD.md +58 -32
- package/docs/en-GB/intlayer_with_tanstack.md +457 -0
- package/docs/en-GB/packages/next-intlayer/index.md +0 -1
- package/docs/en-GB/packages/react-intlayer/index.md +0 -1
- package/docs/es/CI_CD.md +68 -42
- package/docs/es/intlayer_with_tanstack.md +435 -0
- package/docs/es/packages/next-intlayer/index.md +0 -1
- package/docs/es/packages/react-intlayer/index.md +0 -1
- package/docs/fr/intlayer_with_tanstack.md +435 -0
- package/docs/fr/packages/next-intlayer/index.md +0 -1
- package/docs/fr/packages/react-intlayer/index.md +0 -1
- package/docs/hi/CI_CD.md +69 -44
- package/docs/hi/intlayer_with_tanstack.md +438 -0
- package/docs/hi/packages/next-intlayer/index.md +0 -1
- package/docs/hi/packages/react-intlayer/index.md +0 -1
- package/docs/it/CI_CD.md +67 -41
- package/docs/it/intlayer_with_tanstack.md +457 -0
- package/docs/it/packages/next-intlayer/index.md +0 -1
- package/docs/it/packages/react-intlayer/index.md +0 -1
- package/docs/ja/CI_CD.md +67 -41
- package/docs/ja/intlayer_with_tanstack.md +457 -0
- package/docs/ja/packages/next-intlayer/index.md +0 -1
- package/docs/ja/packages/react-intlayer/index.md +0 -1
- package/docs/ko/CI_CD.md +63 -37
- package/docs/ko/intlayer_with_tanstack.md +457 -0
- package/docs/ko/packages/next-intlayer/index.md +0 -1
- package/docs/ko/packages/react-intlayer/index.md +0 -1
- package/docs/pt/CI_CD.md +67 -41
- package/docs/pt/intlayer_with_tanstack.md +457 -0
- package/docs/pt/packages/next-intlayer/index.md +0 -1
- package/docs/pt/packages/react-intlayer/index.md +0 -1
- package/docs/ru/CI_CD.md +70 -44
- package/docs/ru/intlayer_with_tanstack.md +458 -0
- package/docs/ru/packages/next-intlayer/index.md +0 -1
- package/docs/ru/packages/react-intlayer/index.md +0 -1
- package/docs/zh/CI_CD.md +62 -36
- package/docs/zh/intlayer_with_tanstack.md +435 -0
- package/docs/zh/packages/next-intlayer/index.md +0 -1
- package/docs/zh/packages/react-intlayer/index.md +0 -1
- package/package.json +9 -9
- package/src/generated/docs.entry.ts +44 -238
- package/docs/ar/packages/next-intlayer/useIntlayerAsync.md +0 -237
- package/docs/ar/packages/react-intlayer/useIntlayerAsync.md +0 -252
- package/docs/de/packages/next-intlayer/useIntlayerAsync.md +0 -262
- package/docs/de/packages/react-intlayer/useIntlayerAsync.md +0 -256
- package/docs/en/packages/next-intlayer/useIntlayerAsync.md +0 -239
- package/docs/en/packages/react-intlayer/useIntlayerAsync.md +0 -254
- package/docs/en-GB/packages/next-intlayer/useIntlayerAsync.md +0 -237
- package/docs/en-GB/packages/react-intlayer/useIntlayerAsync.md +0 -257
- package/docs/es/packages/next-intlayer/useIntlayerAsync.md +0 -240
- package/docs/es/packages/react-intlayer/useIntlayerAsync.md +0 -276
- package/docs/fr/packages/next-intlayer/useIntlayerAsync.md +0 -238
- package/docs/fr/packages/react-intlayer/useIntlayerAsync.md +0 -252
- package/docs/hi/packages/next-intlayer/useIntlayerAsync.md +0 -237
- package/docs/hi/packages/react-intlayer/useIntlayerAsync.md +0 -252
- package/docs/it/packages/next-intlayer/useIntlayerAsync.md +0 -237
- package/docs/it/packages/react-intlayer/useIntlayerAsync.md +0 -252
- package/docs/ja/packages/next-intlayer/useIntlayerAsync.md +0 -237
- package/docs/ja/packages/react-intlayer/useIntlayerAsync.md +0 -268
- package/docs/ko/packages/next-intlayer/useIntlayerAsync.md +0 -260
- package/docs/ko/packages/react-intlayer/useIntlayerAsync.md +0 -271
- package/docs/pt/packages/next-intlayer/useIntlayerAsync.md +0 -238
- package/docs/pt/packages/react-intlayer/useIntlayerAsync.md +0 -252
- package/docs/ru/packages/next-intlayer/useIntlayerAsync.md +0 -237
- package/docs/ru/packages/react-intlayer/useIntlayerAsync.md +0 -252
- package/docs/zh/packages/next-intlayer/useIntlayerAsync.md +0 -239
- package/docs/zh/packages/react-intlayer/useIntlayerAsync.md +0 -257
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2025-08-11
|
|
3
|
+
updatedAt: 2025-08-11
|
|
4
|
+
title: Getting Started with Intlayer in TanStack Start (React)
|
|
5
|
+
description: Add i18n to your TanStack Start app using Intlayer—component-level dictionaries, localised URLs, and SEO-friendly metadata.
|
|
6
|
+
keywords:
|
|
7
|
+
- Internationalisation
|
|
8
|
+
- Documentation
|
|
9
|
+
- Intlayer
|
|
10
|
+
- TanStack Start
|
|
11
|
+
- TanStack Router
|
|
12
|
+
- React
|
|
13
|
+
- i18n
|
|
14
|
+
- JavaScript
|
|
15
|
+
slugs:
|
|
16
|
+
- doc
|
|
17
|
+
- environment
|
|
18
|
+
- tanstack-start
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Getting Started Internationalising (i18n) with Intlayer and TanStack Start (React)
|
|
22
|
+
|
|
23
|
+
## What is Intlayer?
|
|
24
|
+
|
|
25
|
+
**Intlayer** is an open-source i18n toolkit for React apps. It gives you:
|
|
26
|
+
|
|
27
|
+
- **Component-local dictionaries** with TypeScript safety.
|
|
28
|
+
- **Dynamic metadata & routes** (SEO-ready).
|
|
29
|
+
- **Runtime locale switching** (and helpers to detect/persist locales).
|
|
30
|
+
- **Vite plugin** for build-time transforms + developer experience (DX).
|
|
31
|
+
|
|
32
|
+
This guide shows how to integrate Intlayer into a **TanStack Start** project (which uses Vite under the hood and TanStack Router for routing/SSR).
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Step 1: Install Dependencies
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# npm
|
|
40
|
+
npm i intlayer react-intlayer
|
|
41
|
+
npm i -D vite-intlayer
|
|
42
|
+
|
|
43
|
+
# pnpm
|
|
44
|
+
pnpm add intlayer react-intlayer
|
|
45
|
+
pnpm add -D vite-intlayer
|
|
46
|
+
|
|
47
|
+
# yarn
|
|
48
|
+
yarn add intlayer react-intlayer
|
|
49
|
+
yarn add -D vite-intlayer
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- **intlayer**: core (configuration, dictionaries, CLI/transforms).
|
|
53
|
+
- **react-intlayer**: `<IntlayerProvider>` + hooks for React.
|
|
54
|
+
- **vite-intlayer**: Vite plugin, plus optional middleware for locale detection/redirects (works in development & SSR/preview; move to `dependencies` for production SSR).
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Step 2: Configure Intlayer
|
|
59
|
+
|
|
60
|
+
Create `intlayer.config.ts` at your project root:
|
|
61
|
+
|
|
62
|
+
```ts fileName="intlayer.config.ts"
|
|
63
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
64
|
+
|
|
65
|
+
const config: IntlayerConfig = {
|
|
66
|
+
internationalization: {
|
|
67
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
68
|
+
defaultLocale: Locales.ENGLISH,
|
|
69
|
+
},
|
|
70
|
+
// You can also tweak: contentDir, contentFileExtensions, middleware options, etc.
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default config;
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
CommonJS/ESM variants are identical to your original doc if you prefer `cjs`/`mjs`.
|
|
77
|
+
|
|
78
|
+
> Full config reference: see Intlayer’s configuration docs.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Step 3: Add the Vite Plugin (and optional middleware)
|
|
83
|
+
|
|
84
|
+
**TanStack Start uses Vite**, so add Intlayer’s plugin(s) to your `vite.config.ts`:
|
|
85
|
+
|
|
86
|
+
```ts fileName="vite.config.ts"
|
|
87
|
+
import { defineConfig } from "vite";
|
|
88
|
+
import react from "@vitejs/plugin-react-swc";
|
|
89
|
+
import { intlayerPlugin, intLayerMiddlewarePlugin } from "vite-intlayer";
|
|
90
|
+
|
|
91
|
+
export default defineConfig({
|
|
92
|
+
plugins: [
|
|
93
|
+
react(),
|
|
94
|
+
intlayerPlugin(),
|
|
95
|
+
// Optional but recommended for locale detection, cookies & redirects:
|
|
96
|
+
intLayerMiddlewarePlugin(),
|
|
97
|
+
],
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
> If you deploy SSR, move `vite-intlayer` to `dependencies` so the middleware runs in production.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Step 4: Declare Your Content
|
|
106
|
+
|
|
107
|
+
Place your dictionaries anywhere under `./src` (default `contentDir`). Example:
|
|
108
|
+
|
|
109
|
+
```tsx fileName="src/app.content.tsx"
|
|
110
|
+
import { t, type Dictionary } from "intlayer";
|
|
111
|
+
import type { ReactNode } from "react";
|
|
112
|
+
|
|
113
|
+
const appContent = {
|
|
114
|
+
key: "app",
|
|
115
|
+
content: {
|
|
116
|
+
viteLogo: t({
|
|
117
|
+
"en-GB": "Vite logo",
|
|
118
|
+
en: "Vite logo",
|
|
119
|
+
fr: "Logo Vite",
|
|
120
|
+
es: "Logo Vite",
|
|
121
|
+
}),
|
|
122
|
+
reactLogo: t({
|
|
123
|
+
"en-GB": "React logo",
|
|
124
|
+
en: "React logo",
|
|
125
|
+
fr: "Logo React",
|
|
126
|
+
es: "Logo React",
|
|
127
|
+
}),
|
|
128
|
+
title: t({
|
|
129
|
+
"en-GB": "TanStack Start + React",
|
|
130
|
+
en: "TanStack Start + React",
|
|
131
|
+
fr: "TanStack Start + React",
|
|
132
|
+
es: "TanStack Start + React",
|
|
133
|
+
}),
|
|
134
|
+
count: t({
|
|
135
|
+
"en-GB": "count is ",
|
|
136
|
+
en: "count is ",
|
|
137
|
+
fr: "le compte est ",
|
|
138
|
+
es: "el recuento es ",
|
|
139
|
+
}),
|
|
140
|
+
edit: t<ReactNode>({
|
|
141
|
+
"en-GB": (
|
|
142
|
+
<>
|
|
143
|
+
Edit <code>src/routes/index.tsx</code> and save to test HMR
|
|
144
|
+
</>
|
|
145
|
+
),
|
|
146
|
+
en: (
|
|
147
|
+
<>
|
|
148
|
+
Edit <code>src/routes/index.tsx</code> and save to test HMR
|
|
149
|
+
</>
|
|
150
|
+
),
|
|
151
|
+
fr: (
|
|
152
|
+
<>
|
|
153
|
+
Éditez <code>src/routes/index.tsx</code> et enregistrez pour tester
|
|
154
|
+
HMR
|
|
155
|
+
</>
|
|
156
|
+
),
|
|
157
|
+
es: (
|
|
158
|
+
<>
|
|
159
|
+
Edita <code>src/routes/index.tsx</code> y guarda para probar HMR
|
|
160
|
+
</>
|
|
161
|
+
),
|
|
162
|
+
}),
|
|
163
|
+
readTheDocs: t({
|
|
164
|
+
"en-GB": "Click the logos to learn more",
|
|
165
|
+
en: "Click the logos to learn more",
|
|
166
|
+
fr: "Cliquez sur les logos pour en savoir plus",
|
|
167
|
+
es: "Haz clic en los logotipos para saber más",
|
|
168
|
+
}),
|
|
169
|
+
},
|
|
170
|
+
} satisfies Dictionary;
|
|
171
|
+
|
|
172
|
+
export default appContent;
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
JSON/ESM/CJS variants work the same as in your original doc.
|
|
176
|
+
|
|
177
|
+
> TSX content? Don’t forget `import React from "react"` if your setup needs it.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Step 5: Wrap TanStack Start with Intlayer
|
|
182
|
+
|
|
183
|
+
With TanStack Start, your **root route** is the right place to set providers.
|
|
184
|
+
|
|
185
|
+
```tsx fileName="src/routes/__root.tsx"
|
|
186
|
+
import {
|
|
187
|
+
Outlet,
|
|
188
|
+
createRootRoute,
|
|
189
|
+
Link as RouterLink,
|
|
190
|
+
} from "@tanstack/react-router";
|
|
191
|
+
import { IntlayerProvider, useIntlayer } from "react-intlayer";
|
|
192
|
+
|
|
193
|
+
function AppShell() {
|
|
194
|
+
// Example of using a dictionary at the top level:
|
|
195
|
+
const content = useIntlayer("app");
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<div>
|
|
199
|
+
<nav className="flex gap-3 p-3">
|
|
200
|
+
<RouterLink to="/">Home</RouterLink>
|
|
201
|
+
<RouterLink to="/about">About</RouterLink>
|
|
202
|
+
</nav>
|
|
203
|
+
<main className="p-6">
|
|
204
|
+
<h1>{content.title}</h1>
|
|
205
|
+
<Outlet />
|
|
206
|
+
</main>
|
|
207
|
+
</div>
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export const Route = createRootRoute({
|
|
212
|
+
component: () => (
|
|
213
|
+
<IntlayerProvider>
|
|
214
|
+
<AppShell />
|
|
215
|
+
</IntlayerProvider>
|
|
216
|
+
),
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Then use your content in pages:
|
|
221
|
+
|
|
222
|
+
```tsx fileName="src/routes/index.tsx"
|
|
223
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
224
|
+
import { useIntlayer } from "react-intlayer";
|
|
225
|
+
import reactLogo from "../assets/react.svg";
|
|
226
|
+
|
|
227
|
+
export const Route = createFileRoute("/")({
|
|
228
|
+
component: () => {
|
|
229
|
+
const content = useIntlayer("app");
|
|
230
|
+
return (
|
|
231
|
+
<>
|
|
232
|
+
<button>{content.count}0</button>
|
|
233
|
+
<p>{content.edit}</p>
|
|
234
|
+
<img
|
|
235
|
+
src={reactLogo}
|
|
236
|
+
alt={content.reactLogo.value}
|
|
237
|
+
width={48}
|
|
238
|
+
height={48}
|
|
239
|
+
/>
|
|
240
|
+
<p className="opacity-70">{content.readTheDocs}</p>
|
|
241
|
+
</>
|
|
242
|
+
);
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
> String attributes (`alt`, `title`, `aria-label`, …) require `.value`:
|
|
248
|
+
>
|
|
249
|
+
> ```jsx
|
|
250
|
+
> <img alt={c.reactLogo.value} />
|
|
251
|
+
> ```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## (Optional) Step 6: Locale Switching (Client)
|
|
256
|
+
|
|
257
|
+
```tsx fileName="src/components/LocaleSwitcher.tsx"
|
|
258
|
+
import { Locales } from "intlayer";
|
|
259
|
+
import { useLocale } from "react-intlayer";
|
|
260
|
+
|
|
261
|
+
export function LocaleSwitcher() {
|
|
262
|
+
const { setLocale } = useLocale();
|
|
263
|
+
return (
|
|
264
|
+
<div className="flex gap-2">
|
|
265
|
+
<button onClick={() => setLocale(Locales.ENGLISH)}>English</button>
|
|
266
|
+
<button onClick={() => setLocale(Locales.FRENCH)}>Français</button>
|
|
267
|
+
<button onClick={() => setLocale(Locales.SPANISH)}>Español</button>
|
|
268
|
+
</div>
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## (Optional) Step 7: Localised Routing (SEO-friendly URLs)
|
|
276
|
+
|
|
277
|
+
You have **two good patterns** with TanStack Start. Pick one.
|
|
278
|
+
|
|
279
|
+
Create a dynamic segment folder `src/routes/$locale/` so your URLs are `/:locale/...`. In the `$locale` layout, validate the `params.locale`, set `<IntlayerProvider locale=...>`, and render an `<Outlet />`. This approach is straightforward, but you’ll mount the rest of your routes beneath `$locale`, and you’ll need an extra non-prefixed tree if you _don’t_ want the default locale prefixed.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## (Optional) Step 8: Update the URL when switching locale
|
|
284
|
+
|
|
285
|
+
With Pattern A (basepath), switching locales means **navigating to a different basepath**:
|
|
286
|
+
|
|
287
|
+
```tsx fileName="src/components/LocaleSwitcherNavigate.tsx"
|
|
288
|
+
import { useRouter } from "@tanstack/react-router";
|
|
289
|
+
import { Locales, getLocalizedUrl } from "intlayer";
|
|
290
|
+
import { useLocale } from "react-intlayer";
|
|
291
|
+
|
|
292
|
+
export function LocaleSwitcherNavigate() {
|
|
293
|
+
const router = useRouter();
|
|
294
|
+
const { locale, setLocale } = useLocale();
|
|
295
|
+
|
|
296
|
+
const change = async (next: Locales) => {
|
|
297
|
+
if (next === locale) return;
|
|
298
|
+
const nextPath = getLocalizedUrl(
|
|
299
|
+
window.location.pathname + window.location.search,
|
|
300
|
+
next
|
|
301
|
+
);
|
|
302
|
+
await router.navigate({ to: nextPath }); // preserves history
|
|
303
|
+
setLocale(next);
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
return (
|
|
307
|
+
<div className="flex gap-2">
|
|
308
|
+
<button onClick={() => change(Locales.ENGLISH)}>English</button>
|
|
309
|
+
<button onClick={() => change(Locales.FRENCH)}>Français</button>
|
|
310
|
+
<button onClick={() => change(Locales.SPANISH)}>Español</button>
|
|
311
|
+
</div>
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## (Optional) Step 9: `<html lang>` and `dir` (TanStack Start Document)
|
|
319
|
+
|
|
320
|
+
TanStack Start exposes a **Document** (root HTML shell) you can customise. Set `lang` and `dir` for accessibility/SEO:
|
|
321
|
+
|
|
322
|
+
```tsx fileName="src/routes/__root.tsx" {4,15}
|
|
323
|
+
import { Outlet, createRootRoute } from "@tanstack/react-router";
|
|
324
|
+
import { IntlayerProvider } from "react-intlayer";
|
|
325
|
+
import { getHTMLTextDir } from "intlayer";
|
|
326
|
+
|
|
327
|
+
function Document({
|
|
328
|
+
locale,
|
|
329
|
+
children,
|
|
330
|
+
}: {
|
|
331
|
+
locale: string;
|
|
332
|
+
children: React.ReactNode;
|
|
333
|
+
}) {
|
|
334
|
+
return (
|
|
335
|
+
<html lang={locale} dir={getHTMLTextDir(locale)}>
|
|
336
|
+
<head>
|
|
337
|
+
<meta charSet="utf-8" />
|
|
338
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
339
|
+
{/* ... */}
|
|
340
|
+
</head>
|
|
341
|
+
<body>{children}</body>
|
|
342
|
+
</html>
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export const Route = createRootRoute({
|
|
347
|
+
component: () => (
|
|
348
|
+
<IntlayerProvider>
|
|
349
|
+
{/* If you compute locale on server, pass it into Document; otherwise client will correct post-hydration */}
|
|
350
|
+
<Document locale={document?.documentElement?.lang || "en-GB"}>
|
|
351
|
+
<Outlet />
|
|
352
|
+
</Document>
|
|
353
|
+
</IntlayerProvider>
|
|
354
|
+
),
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
For client-side correction, you can also keep your small hook:
|
|
359
|
+
|
|
360
|
+
```tsx fileName="src/hooks/useI18nHTMLAttributes.tsx"
|
|
361
|
+
import { useEffect } from "react";
|
|
362
|
+
import { useLocale } from "react-intlayer";
|
|
363
|
+
import { getHTMLTextDir } from "intlayer";
|
|
364
|
+
|
|
365
|
+
export const useI18nHTMLAttributes = () => {
|
|
366
|
+
const { locale } = useLocale();
|
|
367
|
+
useEffect(() => {
|
|
368
|
+
document.documentElement.lang = locale;
|
|
369
|
+
document.documentElement.dir = getHTMLTextDir(locale);
|
|
370
|
+
}, [locale]);
|
|
371
|
+
};
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## (Optional) Step 10: Localised Link component
|
|
377
|
+
|
|
378
|
+
TanStack Router provides a `<Link/>`, but if you ever need a plain `<a>` that auto-prefixes internal URLs:
|
|
379
|
+
|
|
380
|
+
```tsx fileName="src/components/Link.tsx"
|
|
381
|
+
import { getLocalizedUrl } from "intlayer";
|
|
382
|
+
import {
|
|
383
|
+
forwardRef,
|
|
384
|
+
type AnchorHTMLAttributes,
|
|
385
|
+
type DetailedHTMLProps,
|
|
386
|
+
} from "react";
|
|
387
|
+
import { useLocale } from "react-intlayer";
|
|
388
|
+
|
|
389
|
+
export interface LinkProps
|
|
390
|
+
extends DetailedHTMLProps<
|
|
391
|
+
AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
392
|
+
HTMLAnchorElement
|
|
393
|
+
> {}
|
|
394
|
+
|
|
395
|
+
const isExternal = (href?: string) => /^https?:\/\//.test(href ?? "");
|
|
396
|
+
|
|
397
|
+
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
|
|
398
|
+
({ href, children, ...props }, ref) => {
|
|
399
|
+
const { locale } = useLocale();
|
|
400
|
+
const hrefI18n =
|
|
401
|
+
href && !isExternal(href) ? getLocalizedUrl(href, locale) : href;
|
|
402
|
+
return (
|
|
403
|
+
<a href={hrefI18n} ref={ref} {...props}>
|
|
404
|
+
{children}
|
|
405
|
+
</a>
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
);
|
|
409
|
+
Link.displayName = "Link";
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
> If you use Pattern A (basepath), TanStack’s `<Link to="/about" />` already resolves to `/fr/about` via `basepath`, so a custom link is optional.
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## TypeScript
|
|
417
|
+
|
|
418
|
+
Include Intlayer’s generated types:
|
|
419
|
+
|
|
420
|
+
```json5 fileName="tsconfig.json"
|
|
421
|
+
{
|
|
422
|
+
"include": ["src", ".intlayer/**/*.ts"],
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## Git
|
|
429
|
+
|
|
430
|
+
Ignore Intlayer’s generated artefacts:
|
|
431
|
+
|
|
432
|
+
```gitignore
|
|
433
|
+
.intlayer
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## VS Code Extension
|
|
439
|
+
|
|
440
|
+
- **Intlayer VS Code Extension** → autocompletion, errors, inline previews, quick actions.
|
|
441
|
+
Marketplace: `intlayer.intlayer-vs-code-extension`
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## Go Further
|
|
446
|
+
|
|
447
|
+
- Visual Editor
|
|
448
|
+
- CMS mode
|
|
449
|
+
- Locale detection on the edge / adapters
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## Doc History
|
|
454
|
+
|
|
455
|
+
| Version | Date | Changes |
|
|
456
|
+
| ------- | ---------- | ------------------------------- |
|
|
457
|
+
| 1.0.0 | 2025-08-11 | TanStack Start adaptation added |
|
|
@@ -308,7 +308,6 @@ The `next-intlayer` package also provides some functions to help you to internat
|
|
|
308
308
|
- [`useIntlayer()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/next-intlayer/useIntlayer.md)
|
|
309
309
|
- [`useDictionary()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/next-intlayer/useDictionary.md)
|
|
310
310
|
- [`useLocale()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/next-intlayer/useLocale.md)
|
|
311
|
-
- [`useIntlayerAsync()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/next-intlayer/useIntlayerAsync.md)
|
|
312
311
|
|
|
313
312
|
## Doc History
|
|
314
313
|
|
|
@@ -273,7 +273,6 @@ The `react-intlayer` package also provides some functions to help you to interna
|
|
|
273
273
|
- [`useIntlayer()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/packages/react-intlayer/useIntlayer.md)
|
|
274
274
|
- [`useDictionary()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/packages/react-intlayer/useDictionary.md)
|
|
275
275
|
- [`useLocale()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/packages/react-intlayer/useLocale.md)
|
|
276
|
-
- [`useIntlayerAsync()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/packages/react-intlayer/useIntlayerAsync.md)
|
|
277
276
|
|
|
278
277
|
## Doc History
|
|
279
278
|
|
package/docs/es/CI_CD.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2025-05-20
|
|
3
|
-
updatedAt: 2025-
|
|
3
|
+
updatedAt: 2025-08-13
|
|
4
4
|
title: Integración CI/CD
|
|
5
|
-
description: Aprende cómo integrar Intlayer en tu pipeline
|
|
5
|
+
description: Aprende cómo integrar Intlayer en tu pipeline CI/CD para la gestión y despliegue automatizado de contenido.
|
|
6
6
|
keywords:
|
|
7
7
|
- CI/CD
|
|
8
8
|
- Integración Continua
|
|
@@ -19,13 +19,13 @@ slugs:
|
|
|
19
19
|
|
|
20
20
|
# Generación Automática de Traducciones en un Pipeline CI/CD
|
|
21
21
|
|
|
22
|
-
Intlayer permite la generación automática de traducciones para tus archivos de declaración de contenido. Existen
|
|
22
|
+
Intlayer permite la generación automática de traducciones para tus archivos de declaración de contenido. Existen múltiples formas de lograr esto dependiendo de tu flujo de trabajo.
|
|
23
23
|
|
|
24
24
|
## Uso del CMS
|
|
25
25
|
|
|
26
|
-
Con Intlayer, puedes adoptar un flujo de trabajo donde solo se declara un único locale localmente, mientras que todas las traducciones se gestionan de forma remota a través del CMS. Esto permite que el contenido y las traducciones estén completamente desacoplados
|
|
26
|
+
Con Intlayer, puedes adoptar un flujo de trabajo donde solo se declara un único locale localmente, mientras que todas las traducciones se gestionan de forma remota a través del CMS. Esto permite que el contenido y las traducciones estén completamente desacoplados del código base, ofreciendo más flexibilidad para los editores de contenido y habilitando la recarga en caliente del contenido (no es necesario reconstruir la aplicación para aplicar cambios).
|
|
27
27
|
|
|
28
|
-
### Configuración de
|
|
28
|
+
### Configuración de Ejemplo
|
|
29
29
|
|
|
30
30
|
```ts fileName="intlayer.config.ts"
|
|
31
31
|
import { Locales, type IntlayerConfig } from "intlayer";
|
|
@@ -45,7 +45,7 @@ const config: IntlayerConfig = {
|
|
|
45
45
|
clientSecret: process.env.INTLAYER_CLIENT_SECRET,
|
|
46
46
|
},
|
|
47
47
|
ai: {
|
|
48
|
-
applicationContext: "
|
|
48
|
+
applicationContext: "Esta es una aplicación de prueba", // Ayuda a asegurar una generación consistente de traducciones
|
|
49
49
|
},
|
|
50
50
|
};
|
|
51
51
|
|
|
@@ -58,7 +58,7 @@ Para aprender más sobre el CMS, consulta la [documentación oficial](https://gi
|
|
|
58
58
|
|
|
59
59
|
Puedes integrar la generación de traducciones en tu flujo de trabajo local de Git usando [Husky](https://typicode.github.io/husky/).
|
|
60
60
|
|
|
61
|
-
### Configuración de
|
|
61
|
+
### Configuración de Ejemplo
|
|
62
62
|
|
|
63
63
|
```ts fileName="intlayer.config.ts"
|
|
64
64
|
import { Locales, type IntlayerConfig } from "intlayer";
|
|
@@ -66,7 +66,7 @@ import { Locales, type IntlayerConfig } from "intlayer";
|
|
|
66
66
|
const config: IntlayerConfig = {
|
|
67
67
|
internationalization: {
|
|
68
68
|
locales: [Locales.ENGLISH, Locales.SPANISH, Locales.FRENCH],
|
|
69
|
-
requiredLocales: [Locales.ENGLISH], // Los locales opcionales se
|
|
69
|
+
requiredLocales: [Locales.ENGLISH], // Los locales opcionales se manejan de forma remota
|
|
70
70
|
defaultLocale: Locales.ENGLISH,
|
|
71
71
|
},
|
|
72
72
|
editor: {
|
|
@@ -77,7 +77,7 @@ const config: IntlayerConfig = {
|
|
|
77
77
|
provider: "openai",
|
|
78
78
|
apiKey: process.env.OPENAI_API_KEY, // Usa tu propia clave API
|
|
79
79
|
|
|
80
|
-
applicationContext: "
|
|
80
|
+
applicationContext: "Esta es una aplicación de prueba", // Ayuda a asegurar una generación consistente de traducciones
|
|
81
81
|
},
|
|
82
82
|
};
|
|
83
83
|
|
|
@@ -91,7 +91,7 @@ npx intlayer fill --unpushed --mode fill # Solo rellena el contenido faltante
|
|
|
91
91
|
|
|
92
92
|
> Para más información sobre los comandos CLI de Intlayer y su uso, consulta la [documentación CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/es/intlayer_cli.md).
|
|
93
93
|
|
|
94
|
-
> Si tienes múltiples aplicaciones en tu repositorio usando instancias separadas de Intlayer, puedes usar el argumento `--base-dir`
|
|
94
|
+
> Si tienes múltiples aplicaciones en tu repositorio usando instancias separadas de Intlayer, puedes usar el argumento `--base-dir` de esta manera:
|
|
95
95
|
|
|
96
96
|
```bash fileName=".husky/pre-push"
|
|
97
97
|
# App 1
|
|
@@ -105,68 +105,94 @@ npx intlayer fill --base-dir ./app2 --unpushed --mode fill
|
|
|
105
105
|
|
|
106
106
|
## Uso de GitHub Actions
|
|
107
107
|
|
|
108
|
-
Intlayer proporciona un comando CLI para
|
|
108
|
+
Intlayer proporciona un comando CLI para rellenar automáticamente y revisar el contenido del diccionario. Esto se puede integrar en tu flujo de trabajo CI/CD usando GitHub Actions.
|
|
109
109
|
|
|
110
110
|
```yaml fileName=".github/workflows/intlayer-translate.yml"
|
|
111
|
-
name:
|
|
111
|
+
name: Relleno Automático de Intlayer
|
|
112
|
+
# Condiciones para activar este flujo de trabajo
|
|
112
113
|
on:
|
|
113
|
-
push:
|
|
114
|
-
branches: [ main ]
|
|
115
|
-
paths:
|
|
116
|
-
- 'src/**'
|
|
117
114
|
pull_request:
|
|
118
|
-
branches:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
115
|
+
branches:
|
|
116
|
+
- "main"
|
|
117
|
+
|
|
118
|
+
permissions:
|
|
119
|
+
contents: write
|
|
120
|
+
pull-requests: write
|
|
122
121
|
|
|
123
122
|
concurrency:
|
|
124
|
-
group:
|
|
123
|
+
group: "autofill-${{ github.ref }}"
|
|
125
124
|
cancel-in-progress: true
|
|
126
125
|
|
|
127
126
|
jobs:
|
|
128
127
|
autofill:
|
|
129
128
|
runs-on: ubuntu-latest
|
|
130
129
|
env:
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
# OpenAI
|
|
131
|
+
AI_MODEL: openai
|
|
132
|
+
AI_PROVIDER: gpt-5-mini
|
|
133
|
+
AI_API_KEY: ${{ secrets.AI_API_KEY }}
|
|
134
134
|
|
|
135
135
|
steps:
|
|
136
|
+
# Paso 1: Obtener el código más reciente del repositorio
|
|
136
137
|
- name: ⬇️ Clonar repositorio
|
|
137
|
-
uses: actions/checkout@
|
|
138
|
+
uses: actions/checkout@v4
|
|
138
139
|
with:
|
|
139
|
-
persist-credentials: true
|
|
140
|
+
persist-credentials: true # Mantener credenciales para crear PRs
|
|
141
|
+
fetch-depth: 0 # Obtener todo el historial git para análisis de diferencias
|
|
140
142
|
|
|
143
|
+
# Paso 2: Configurar el entorno de Node.js
|
|
141
144
|
- name: 🟢 Configurar Node.js
|
|
142
|
-
uses: actions/setup-node@
|
|
145
|
+
uses: actions/setup-node@v4
|
|
143
146
|
with:
|
|
144
|
-
node-version: 20
|
|
147
|
+
node-version: 20 # Usar Node.js 20 LTS para estabilidad
|
|
145
148
|
|
|
149
|
+
# Paso 3: Instalar dependencias del proyecto
|
|
146
150
|
- name: 📦 Instalar dependencias
|
|
147
|
-
run: npm
|
|
151
|
+
run: npm install
|
|
152
|
+
|
|
153
|
+
# Paso 4: Instalar Intlayer CLI globalmente para gestión de traducciones
|
|
154
|
+
- name: 📦 Instalar Intlayer
|
|
155
|
+
run: npm install -g intlayer-cli
|
|
148
156
|
|
|
157
|
+
# Paso 5: Construir el proyecto Intlayer para generar archivos de traducción
|
|
149
158
|
- name: ⚙️ Construir proyecto Intlayer
|
|
150
159
|
run: npx intlayer build
|
|
151
160
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
161
|
+
# Paso 6: Usar IA para rellenar automáticamente las traducciones faltantes
|
|
162
|
+
- name: 🤖 Rellenar automáticamente las traducciones faltantes
|
|
163
|
+
run: npx intlayer fill --git-diff --mode fill --provider $AI_PROVIDER --model $AI_MODEL --api-key $AI_API_KEY
|
|
164
|
+
|
|
165
|
+
# Paso 7: Verificar si hay cambios y confirmarlos
|
|
166
|
+
- name: � Verificar cambios
|
|
167
|
+
id: check-changes
|
|
168
|
+
run: |
|
|
169
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
170
|
+
echo "has-changes=true" >> $GITHUB_OUTPUT
|
|
171
|
+
else
|
|
172
|
+
echo "has-changes=false" >> $GITHUB_OUTPUT
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# Paso 8: Confirmar y enviar cambios si existen
|
|
176
|
+
- name: 📤 Confirmar y enviar cambios
|
|
177
|
+
if: steps.check-changes.outputs.has-changes == 'true'
|
|
178
|
+
run: |
|
|
179
|
+
git config --local user.email "action@github.com"
|
|
180
|
+
git config --local user.name "GitHub Action"
|
|
181
|
+
git add .
|
|
182
|
+
git commit -m "chore: auto-fill missing translations [skip ci]"
|
|
183
|
+
git push origin HEAD:${{ github.head_ref }}
|
|
162
184
|
```
|
|
163
185
|
|
|
164
|
-
|
|
186
|
+
Para configurar las variables de entorno, vaya a GitHub → Configuración → Secrets and variables → Actions y agregue el secreto .
|
|
187
|
+
|
|
188
|
+
> Al igual que con Husky, en el caso de un monorepo, puede usar el argumento `--base-dir` para tratar secuencialmente cada aplicación.
|
|
165
189
|
|
|
166
190
|
> Por defecto, el argumento `--git-diff` filtra los diccionarios que incluyen cambios desde la base (por defecto `origin/main`) hasta la rama actual (por defecto: `HEAD`).
|
|
167
191
|
|
|
168
|
-
> Para más información sobre los comandos de
|
|
192
|
+
> Para más información sobre los comandos de Intlayer CLI y su uso, consulte la [documentación del CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/es/intlayer_cli.md).
|
|
169
193
|
|
|
170
194
|
## Historial del documento
|
|
171
195
|
|
|
172
|
-
|
|
196
|
+
| Versión | Fecha | Cambios |
|
|
197
|
+
| ------- | ---------- | ----------------- |
|
|
198
|
+
| 5.5.10 | 2025-06-29 | Historial inicial |
|