@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,452 @@
|
|
|
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, localized URLs, and SEO-friendly metadata.
|
|
6
|
+
keywords:
|
|
7
|
+
- Internationalization
|
|
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 Internationalizing (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 + dev DX.
|
|
31
|
+
|
|
32
|
+
This guide shows how to wire 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 (config, dictionaries, CLI/transforms).
|
|
53
|
+
- **react-intlayer**: `<IntlayerProvider>` + hooks for React.
|
|
54
|
+
- **vite-intlayer**: Vite plugin, plus optional middleware for locale detection/redirects (works in dev & 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({ en: "Vite logo", fr: "Logo Vite", es: "Logo Vite" }),
|
|
117
|
+
reactLogo: t({ en: "React logo", fr: "Logo React", es: "Logo React" }),
|
|
118
|
+
title: t({
|
|
119
|
+
en: "TanStack Start + React",
|
|
120
|
+
fr: "TanStack Start + React",
|
|
121
|
+
es: "TanStack Start + React",
|
|
122
|
+
}),
|
|
123
|
+
count: t({ en: "count is ", fr: "le compte est ", es: "el recuento es " }),
|
|
124
|
+
edit: t<ReactNode>({
|
|
125
|
+
en: (
|
|
126
|
+
<>
|
|
127
|
+
Edit <code>src/routes/index.tsx</code> and save to test HMR
|
|
128
|
+
</>
|
|
129
|
+
),
|
|
130
|
+
fr: (
|
|
131
|
+
<>
|
|
132
|
+
Éditez <code>src/routes/index.tsx</code> et enregistrez pour tester
|
|
133
|
+
HMR
|
|
134
|
+
</>
|
|
135
|
+
),
|
|
136
|
+
es: (
|
|
137
|
+
<>
|
|
138
|
+
Edita <code>src/routes/index.tsx</code> y guarda para probar HMR
|
|
139
|
+
</>
|
|
140
|
+
),
|
|
141
|
+
}),
|
|
142
|
+
readTheDocs: t({
|
|
143
|
+
en: "Click the logos to learn more",
|
|
144
|
+
fr: "Cliquez sur les logos pour en savoir plus",
|
|
145
|
+
es: "Haz clic en los logotipos para saber más",
|
|
146
|
+
}),
|
|
147
|
+
},
|
|
148
|
+
} satisfies Dictionary;
|
|
149
|
+
|
|
150
|
+
export default appContent;
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
JSON/ESM/CJS variants work the same as in your original doc.
|
|
154
|
+
|
|
155
|
+
> TSX content? Don’t forget `import React from "react"` if your setup needs it.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Step 5: Wrap TanStack Start with Intlayer
|
|
160
|
+
|
|
161
|
+
With TanStack Start, your **root route** is the right place to set providers.
|
|
162
|
+
|
|
163
|
+
```tsx fileName="src/routes/__root.tsx"
|
|
164
|
+
import {
|
|
165
|
+
Outlet,
|
|
166
|
+
createRootRoute,
|
|
167
|
+
Link as RouterLink,
|
|
168
|
+
} from "@tanstack/react-router";
|
|
169
|
+
import { IntlayerProvider, useIntlayer } from "react-intlayer";
|
|
170
|
+
|
|
171
|
+
function AppShell() {
|
|
172
|
+
// Example of using a dictionary at the top level:
|
|
173
|
+
const content = useIntlayer("app");
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<div>
|
|
177
|
+
<nav className="flex gap-3 p-3">
|
|
178
|
+
<RouterLink to="/">Home</RouterLink>
|
|
179
|
+
<RouterLink to="/about">About</RouterLink>
|
|
180
|
+
</nav>
|
|
181
|
+
<main className="p-6">
|
|
182
|
+
<h1>{content.title}</h1>
|
|
183
|
+
<Outlet />
|
|
184
|
+
</main>
|
|
185
|
+
</div>
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export const Route = createRootRoute({
|
|
190
|
+
component: () => (
|
|
191
|
+
<IntlayerProvider>
|
|
192
|
+
<AppShell />
|
|
193
|
+
</IntlayerProvider>
|
|
194
|
+
),
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Then use your content in pages:
|
|
199
|
+
|
|
200
|
+
```tsx fileName="src/routes/index.tsx"
|
|
201
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
202
|
+
import { useIntlayer } from "react-intlayer";
|
|
203
|
+
import reactLogo from "../assets/react.svg";
|
|
204
|
+
|
|
205
|
+
export const Route = createFileRoute("/")({
|
|
206
|
+
component: () => {
|
|
207
|
+
const content = useIntlayer("app");
|
|
208
|
+
return (
|
|
209
|
+
<>
|
|
210
|
+
<button>{content.count}0</button>
|
|
211
|
+
<p>{content.edit}</p>
|
|
212
|
+
<img
|
|
213
|
+
src={reactLogo}
|
|
214
|
+
alt={content.reactLogo.value}
|
|
215
|
+
width={48}
|
|
216
|
+
height={48}
|
|
217
|
+
/>
|
|
218
|
+
<p className="opacity-70">{content.readTheDocs}</p>
|
|
219
|
+
</>
|
|
220
|
+
);
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
> String attributes (`alt`, `title`, `aria-label`, …) need `.value`:
|
|
226
|
+
>
|
|
227
|
+
> ```jsx
|
|
228
|
+
> <img alt={c.reactLogo.value} />
|
|
229
|
+
> ```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## (Optional) Step 6: Locale Switching (Client)
|
|
234
|
+
|
|
235
|
+
```tsx fileName="src/components/LocaleSwitcher.tsx"
|
|
236
|
+
import { Locales } from "intlayer";
|
|
237
|
+
import { useLocale } from "react-intlayer";
|
|
238
|
+
|
|
239
|
+
export function LocaleSwitcher() {
|
|
240
|
+
const { setLocale } = useLocale();
|
|
241
|
+
return (
|
|
242
|
+
<div className="flex gap-2">
|
|
243
|
+
<button onClick={() => setLocale(Locales.ENGLISH)}>English</button>
|
|
244
|
+
<button onClick={() => setLocale(Locales.FRENCH)}>Français</button>
|
|
245
|
+
<button onClick={() => setLocale(Locales.SPANISH)}>Español</button>
|
|
246
|
+
</div>
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## (Optional) Step 7: Localized Routing (SEO-friendly URLs)
|
|
254
|
+
|
|
255
|
+
You have **two good patterns** with TanStack Start. Pick one.
|
|
256
|
+
|
|
257
|
+
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.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## (Optional) Step 8: Update the URL when switching locale
|
|
262
|
+
|
|
263
|
+
With Pattern A (basepath), switching locales means **navigating to a different basepath**:
|
|
264
|
+
|
|
265
|
+
```tsx fileName="src/components/LocaleSwitcherNavigate.tsx"
|
|
266
|
+
import { useRouter } from "@tanstack/react-router";
|
|
267
|
+
import { Locales, getLocalizedUrl } from "intlayer";
|
|
268
|
+
import { useLocale } from "react-intlayer";
|
|
269
|
+
|
|
270
|
+
export function LocaleSwitcherNavigate() {
|
|
271
|
+
const router = useRouter();
|
|
272
|
+
const { locale, setLocale } = useLocale();
|
|
273
|
+
|
|
274
|
+
const change = async (next: Locales) => {
|
|
275
|
+
if (next === locale) return;
|
|
276
|
+
const nextPath = getLocalizedUrl(
|
|
277
|
+
window.location.pathname + window.location.search,
|
|
278
|
+
next
|
|
279
|
+
);
|
|
280
|
+
await router.navigate({ to: nextPath }); // preserves history
|
|
281
|
+
setLocale(next);
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
return (
|
|
285
|
+
<div className="flex gap-2">
|
|
286
|
+
<button onClick={() => change(Locales.ENGLISH)}>English</button>
|
|
287
|
+
<button onClick={() => change(Locales.FRENCH)}>Français</button>
|
|
288
|
+
<button onClick={() => change(Locales.SPANISH)}>Español</button>
|
|
289
|
+
</div>
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## (Optional) Step 9: `<html lang>` and `dir` (TanStack Start Document)
|
|
297
|
+
|
|
298
|
+
TanStack Start exposes a **Document** (root HTML shell) you can customize. Set `lang` and `dir` for accessibility/SEO:
|
|
299
|
+
|
|
300
|
+
```tsx fileName="src/routes/__root.tsx" {4,15}
|
|
301
|
+
import { HeadContent, Scripts, createRootRoute } from "@tanstack/react-router";
|
|
302
|
+
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
|
|
303
|
+
|
|
304
|
+
import Header from "../components/Header";
|
|
305
|
+
|
|
306
|
+
import { IntlayerProvider } from "react-intlayer";
|
|
307
|
+
import appCss from "../styles.css?url";
|
|
308
|
+
|
|
309
|
+
export const Route = createRootRoute({
|
|
310
|
+
head: () => ({
|
|
311
|
+
meta: [
|
|
312
|
+
{
|
|
313
|
+
charSet: "utf-8",
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
name: "viewport",
|
|
317
|
+
content: "width=device-width, initial-scale=1",
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
title: "TanStack Start Starter",
|
|
321
|
+
},
|
|
322
|
+
],
|
|
323
|
+
links: [
|
|
324
|
+
{
|
|
325
|
+
rel: "stylesheet",
|
|
326
|
+
href: appCss,
|
|
327
|
+
},
|
|
328
|
+
],
|
|
329
|
+
}),
|
|
330
|
+
|
|
331
|
+
shellComponent: RootDocument,
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
function RootDocument({ children }: { children: React.ReactNode }) {
|
|
335
|
+
return (
|
|
336
|
+
<IntlayerProvider>
|
|
337
|
+
<html lang="en">
|
|
338
|
+
<head>
|
|
339
|
+
<HeadContent />
|
|
340
|
+
</head>
|
|
341
|
+
<body>
|
|
342
|
+
<Header />
|
|
343
|
+
{children}
|
|
344
|
+
<TanStackRouterDevtools />
|
|
345
|
+
<Scripts />
|
|
346
|
+
</body>
|
|
347
|
+
</html>
|
|
348
|
+
</IntlayerProvider>
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
For client-side correction, you can also keep your small hook:
|
|
354
|
+
|
|
355
|
+
```tsx fileName="src/hooks/useI18nHTMLAttributes.ts"
|
|
356
|
+
import { useEffect } from "react";
|
|
357
|
+
import { useLocale } from "react-intlayer";
|
|
358
|
+
import { getHTMLTextDir } from "intlayer";
|
|
359
|
+
|
|
360
|
+
export const useI18nHTMLAttributes = () => {
|
|
361
|
+
const { locale } = useLocale();
|
|
362
|
+
useEffect(() => {
|
|
363
|
+
document.documentElement.lang = locale;
|
|
364
|
+
document.documentElement.dir = getHTMLTextDir(locale);
|
|
365
|
+
}, [locale]);
|
|
366
|
+
};
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## (Optional) Step 10: Localized Link component
|
|
372
|
+
|
|
373
|
+
TanStack Router provides a `<Link/>`, but if you ever need a plain `<a>` that auto-prefixes internal URLs:
|
|
374
|
+
|
|
375
|
+
```tsx fileName="src/components/Link.tsx"
|
|
376
|
+
import { getLocalizedUrl } from "intlayer";
|
|
377
|
+
import {
|
|
378
|
+
forwardRef,
|
|
379
|
+
type AnchorHTMLAttributes,
|
|
380
|
+
type DetailedHTMLProps,
|
|
381
|
+
} from "react";
|
|
382
|
+
import { useLocale } from "react-intlayer";
|
|
383
|
+
|
|
384
|
+
export interface LinkProps
|
|
385
|
+
extends DetailedHTMLProps<
|
|
386
|
+
AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
387
|
+
HTMLAnchorElement
|
|
388
|
+
> {}
|
|
389
|
+
|
|
390
|
+
const isExternal = (href?: string) => /^https?:\/\//.test(href ?? "");
|
|
391
|
+
|
|
392
|
+
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
|
|
393
|
+
({ href, children, ...props }, ref) => {
|
|
394
|
+
const { locale } = useLocale();
|
|
395
|
+
const hrefI18n =
|
|
396
|
+
href && !isExternal(href) ? getLocalizedUrl(href, locale) : href;
|
|
397
|
+
return (
|
|
398
|
+
<a href={hrefI18n} ref={ref} {...props}>
|
|
399
|
+
{children}
|
|
400
|
+
</a>
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
);
|
|
404
|
+
Link.displayName = "Link";
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
> If you use Pattern A (basepath), TanStack’s `<Link to="/about" />` already resolves to `/fr/about` via `basepath`, so a custom link is optional.
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## TypeScript
|
|
412
|
+
|
|
413
|
+
Include Intlayer’s generated types:
|
|
414
|
+
|
|
415
|
+
```json5 fileName="tsconfig.json"
|
|
416
|
+
{
|
|
417
|
+
"include": ["src", ".intlayer/**/*.ts"],
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## Git
|
|
424
|
+
|
|
425
|
+
Ignore Intlayer’s generated artifacts:
|
|
426
|
+
|
|
427
|
+
```gitignore
|
|
428
|
+
.intlayer
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## VS Code Extension
|
|
434
|
+
|
|
435
|
+
- **Intlayer VS Code Extension** → autocompletion, errors, inline previews, quick actions.
|
|
436
|
+
Marketplace: `intlayer.intlayer-vs-code-extension`
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## Go Further
|
|
441
|
+
|
|
442
|
+
- Visual Editor
|
|
443
|
+
- CMS mode
|
|
444
|
+
- Locale detection on the edge / adapters
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## Doc History
|
|
449
|
+
|
|
450
|
+
| Version | Date | Changes |
|
|
451
|
+
| ------- | ---------- | ------------------------------- |
|
|
452
|
+
| 1.0.0 | 2025-08-11 | TanStack Start adaptation added |
|
|
@@ -279,7 +279,6 @@ The `next-intlayer` package also provides some functions to help you to internat
|
|
|
279
279
|
- [`useIntlayer()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/next-intlayer/useIntlayer.md)
|
|
280
280
|
- [`useDictionary()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/next-intlayer/useDictionary.md)
|
|
281
281
|
- [`useLocale()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/next-intlayer/useLocale.md)
|
|
282
|
-
- [`useIntlayerAsync()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/next-intlayer/useIntlayerAsync.md)
|
|
283
282
|
|
|
284
283
|
## Doc History
|
|
285
284
|
|
|
@@ -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/packages/react-intlayer/useIntlayer.md)
|
|
274
274
|
- [`useDictionary()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/react-intlayer/useDictionary.md)
|
|
275
275
|
- [`useLocale()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/react-intlayer/useLocale.md)
|
|
276
|
-
- [`useIntlayerAsync()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/react-intlayer/useIntlayerAsync.md)
|
|
277
276
|
|
|
278
277
|
## Doc History
|
|
279
278
|
|
package/docs/en-GB/CI_CD.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2025-05-20
|
|
3
|
-
updatedAt: 2025-
|
|
3
|
+
updatedAt: 2025-08-13
|
|
4
4
|
title: CI/CD Integration
|
|
5
5
|
description: Learn how to integrate Intlayer into your CI/CD pipeline for automated content management and deployment.
|
|
6
6
|
keywords:
|
|
@@ -8,7 +8,7 @@ keywords:
|
|
|
8
8
|
- Continuous Integration
|
|
9
9
|
- Continuous Deployment
|
|
10
10
|
- Automation
|
|
11
|
-
-
|
|
11
|
+
- Internationalisation
|
|
12
12
|
- Documentation
|
|
13
13
|
- Intlayer
|
|
14
14
|
slugs:
|
|
@@ -64,7 +64,7 @@ You can integrate translation generation into your local Git workflow using [Hus
|
|
|
64
64
|
import { Locales, type IntlayerConfig } from "intlayer";
|
|
65
65
|
|
|
66
66
|
const config: IntlayerConfig = {
|
|
67
|
-
|
|
67
|
+
internationalisation: {
|
|
68
68
|
locales: [Locales.ENGLISH, Locales.SPANISH, Locales.FRENCH],
|
|
69
69
|
requiredLocales: [Locales.ENGLISH], // Optional locales are handled remotely
|
|
70
70
|
defaultLocale: Locales.ENGLISH,
|
|
@@ -109,64 +109,90 @@ Intlayer provides a CLI command to autofill and review dictionary content. This
|
|
|
109
109
|
|
|
110
110
|
```yaml fileName=".github/workflows/intlayer-translate.yml"
|
|
111
111
|
name: Intlayer Auto-Fill
|
|
112
|
+
# Trigger conditions for this workflow
|
|
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
|
+
# Step 1: Get the latest code from the repository
|
|
136
137
|
- name: ⬇️ Checkout repository
|
|
137
|
-
uses: actions/checkout@
|
|
138
|
+
uses: actions/checkout@v4
|
|
138
139
|
with:
|
|
139
|
-
persist-credentials: true
|
|
140
|
+
persist-credentials: true # Keep credentials for creating PRs
|
|
141
|
+
fetch-depth: 0 # Get full git history for diff analysis
|
|
140
142
|
|
|
143
|
+
# Step 2: Set up Node.js environment
|
|
141
144
|
- name: 🟢 Set up Node.js
|
|
142
|
-
uses: actions/setup-node@
|
|
145
|
+
uses: actions/setup-node@v4
|
|
143
146
|
with:
|
|
144
|
-
node-version: 20
|
|
147
|
+
node-version: 20 # Use Node.js 20 LTS for stability
|
|
145
148
|
|
|
149
|
+
# Step 3: Install project dependencies
|
|
146
150
|
- name: 📦 Install dependencies
|
|
147
|
-
run: npm
|
|
151
|
+
run: npm install
|
|
152
|
+
|
|
153
|
+
# Step 4: Install Intlayer CLI globally for translation management
|
|
154
|
+
- name: 📦 Install Intlayer
|
|
155
|
+
run: npm install -g intlayer-cli
|
|
148
156
|
|
|
157
|
+
# Step 5: Build the Intlayer project to generate translation files
|
|
149
158
|
- name: ⚙️ Build Intlayer project
|
|
150
159
|
run: npx intlayer build
|
|
151
160
|
|
|
161
|
+
# Step 6: Use AI to automatically fill missing translations
|
|
152
162
|
- name: 🤖 Auto-fill missing translations
|
|
153
|
-
run: npx intlayer fill --git-diff --mode fill
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
run: npx intlayer fill --git-diff --mode fill --provider $AI_PROVIDER --model $AI_MODEL --api-key $AI_API_KEY
|
|
164
|
+
|
|
165
|
+
# Step 7: Check if there are changes and commit them
|
|
166
|
+
- name: � Check for changes
|
|
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
|
+
# Step 8: Commit and push changes if any exist
|
|
176
|
+
- name: 📤 Commit and push changes
|
|
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
|
+
To set up the environment variables, go to GitHub → Settings → Secrets and variables → Actions and add the secret .
|
|
187
|
+
|
|
188
|
+
> Same as for Husky, in the case of a monorepo, you can use the `--base-dir` argument to sequentially process each app.
|
|
165
189
|
|
|
166
|
-
> By default, the `--git-diff` argument filters dictionaries that include changes from base (default `origin/main`) to current branch (default: `HEAD`).
|
|
190
|
+
> By default, the `--git-diff` argument filters dictionaries that include changes from the base (default `origin/main`) to the current branch (default: `HEAD`).
|
|
167
191
|
|
|
168
192
|
> For more information about Intlayer CLI commands and their usage, refer to the [CLI documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/intlayer_cli.md).
|
|
169
193
|
|
|
170
194
|
## Doc History
|
|
171
195
|
|
|
172
|
-
|
|
196
|
+
| Version | Date | Changes |
|
|
197
|
+
| ------- | ---------- | --------------- |
|
|
198
|
+
| 5.5.10 | 2025-06-29 | Initial history |
|