You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -12,11 +12,19 @@ A full-featured i18n integration for Astro. Handles locale detection, URL routin
12
12
13
13
```bash
14
14
pnpm add @mannisto/astro-i18n
15
+
```
16
+
17
+
```bash
15
18
npm install @mannisto/astro-i18n
19
+
```
20
+
21
+
```bash
16
22
yarn add @mannisto/astro-i18n
17
23
```
18
24
19
-
## Setup
25
+
## Getting started
26
+
27
+
### 1. Configure the integration
20
28
21
29
```typescript
22
30
// astro.config.ts
@@ -40,35 +48,24 @@ export default defineConfig({
40
48
41
49
See the full [Configuration reference](#configuration) below.
42
50
43
-
## Modes
44
-
45
-
### `static`
46
-
47
-
Pages prebuilt at build time, locale detection at the root via a small inline script.
51
+
### 2. Set up your file structure
48
52
49
-
- No server required — works on any CDN
50
-
- First-time visitors may briefly see the unlocalized root URL before being redirected
51
-
- Unprefixed paths like `/about` are not auto-redirected — handle them in `404.astro` with `Locale.redirect(Astro)`
52
-
53
-
### `server`
54
-
55
-
Pages rendered on demand, middleware handles all locale detection and redirects.
56
-
57
-
- Requires a Node adapter
58
-
- No flash on first visit
59
-
- Unprefixed paths (e.g. `/about`) are automatically redirected to their locale-prefixed equivalent
60
-
61
-
### `hybrid`
62
-
63
-
Pages prerendered for performance, with server-side locale handling at the root.
53
+
```
54
+
src/
55
+
├── pages/
56
+
│ ├── [locale]/
57
+
│ │ └── index.astro # your locale pages
58
+
│ └── 404.astro
59
+
└── translations/
60
+
├── en.json
61
+
└── fi.json
62
+
```
64
63
65
-
- Requires a Node adapter
66
-
- No flash on first visit
67
-
- Unprefixed paths like `/about` are not auto-redirected — handle them in `404.astro` with `Locale.redirect(Astro)`
64
+
> **Note:** Do not create a `src/pages/index.astro`. The integration injects its own root route for locale detection — having your own will cause a build error.
68
65
69
-
##Translations
66
+
### 3. Add translations
70
67
71
-
Create a `src/translations/` directory with one JSON file per locale. Files must use flat keys — no nesting.
68
+
Create one JSON file per locale in your translations directory. Files must use flat keys — no nesting.
72
69
73
70
```json
74
71
{
@@ -80,81 +77,81 @@ Create a `src/translations/` directory with one JSON file per locale. Files must
80
77
81
78
All locale files must define the same set of keys.
82
79
83
-
##Usage
80
+
### 4. Set up your layout
84
81
85
-
### Pages
86
-
87
-
In `static` and `hybrid` mode, use `getStaticPaths` to prerender pages for each locale:
82
+
Your layout must sync the current locale to a cookie on every page load. This is how the integration remembers the user's locale across visits and correctly resolves it on 404 pages.
88
83
89
84
```astro
90
85
---
86
+
// src/layouts/Layout.astro
91
87
import { Locale } from "@mannisto/astro-i18n/runtime"
In `server` mode, omit `getStaticPaths` and opt out of prerendering explicitly:
105
+
### 5. Create your locale pages
106
+
107
+
In `static` and `hybrid` mode, use `getStaticPaths` to prerender a page for each locale:
114
108
115
109
```astro
116
110
---
117
-
export const prerender = false
118
-
111
+
// src/pages/[locale]/index.astro
119
112
import { Locale } from "@mannisto/astro-i18n/runtime"
113
+
import Layout from "@layouts/Layout.astro"
114
+
115
+
export const getStaticPaths = () => {
116
+
return Locale.supported.map((code) => ({
117
+
params: { locale: code }
118
+
}))
119
+
}
120
120
121
121
const locale = Locale.from(Astro.url)
122
122
const t = Locale.use(locale)
123
123
---
124
-
```
125
124
126
-
Without `prerender = false`, Astro will treat dynamic routes as static and throw a `GetStaticPathsRequired` error even in server mode.
127
-
128
-
### Layout
125
+
<Layout>
126
+
<h1>{t("nav.home")}</h1>
127
+
</Layout>
128
+
```
129
129
130
-
Your layout should derive the locale from the URL and sync it to a cookie on every page load. This ensures the correct locale is remembered across visits and that 404 pages can detect the locale correctly.
130
+
In `server` mode, omit `getStaticPaths`and opt out of prerendering explicitly:
131
131
132
132
```astro
133
133
---
134
-
// src/layouts/Layout.astro
134
+
export const prerender = false
135
+
135
136
import { Locale } from "@mannisto/astro-i18n/runtime"
Without `prerender = false`, Astro will treat dynamic routes as static and throw a `GetStaticPathsRequired` error even in server mode.
149
+
150
+
### 6. Set up your 404 page
154
151
155
-
Create a `src/pages/404.astro` at the root of your pages directory. How the locale is resolved depends on your mode.
152
+
How you set up `404.astro` depends on your mode.
156
153
157
-
**In `server` mode**, the middleware automatically redirects all unprefixed paths to their locale-prefixed equivalent before the 404 page renders (e.g. `/banana` → `/en/banana`). `Locale.from(Astro.url)` always returns the correct locale.
154
+
**In `server` mode**, the middleware automatically redirects unprefixed paths to their locale-prefixed equivalent before the 404 page renders (e.g. `/banana` → `/en/banana`). `Locale.from(Astro.url)` always returns the correct locale.
**In `static` and `hybrid` mode**, unprefixed paths are not redirected automatically. Use `Locale.redirect(Astro)` at the top of your 404 page — it redirects the visitor to the locale-prefixed equivalent (e.g. `/banana` → `/en/banana`) using the cookie locale, falling back to `defaultLocale`. Locale-prefixed paths like `/en/banana` pass through and render the 404 content directly.
174
+
**In `static` and `hybrid` mode**, unprefixed paths are not redirected automatically. Use `Locale.redirect(Astro)` at the top of your 404 page — it redirects to the locale-prefixed equivalent using the cookie locale, falling back to `defaultLocale`. Locale-prefixed paths like `/en/banana` pass through and render the 404 content directly.
Pages prebuilt at build time. The injected root route runs client-side, reads the locale cookie, and redirects via `window.location`. No server required.
202
+
203
+
- Works on any CDN with no adapter
204
+
- First-time visitors may briefly see the root URL before being redirected
205
+
- Unprefixed paths like `/about` are not auto-redirected — handle them in `404.astro` with `Locale.redirect(Astro)`
206
+
207
+
### `server`
208
+
209
+
Pages rendered on demand. The injected root route and middleware handle all locale detection and redirects server-side.
210
+
211
+
- Requires a Node adapter
212
+
- No flash on first visit
213
+
- Unprefixed paths (e.g. `/about`) are automatically redirected to their locale-prefixed equivalent
214
+
215
+
### `hybrid`
216
+
217
+
Pages prerendered for performance. The injected root route is server-rendered for locale detection, while all other pages are static.
218
+
219
+
- Requires a Node adapter
220
+
- No flash on first visit
221
+
- Unprefixed paths like `/about` are not auto-redirected — handle them in `404.astro` with `Locale.redirect(Astro)`
222
+
223
+
## Language switcher
201
224
202
225
```astro
203
226
---
@@ -224,9 +247,9 @@ const locales = Locale.get()
224
247
</script>
225
248
```
226
249
227
-
###Middleware
250
+
## Middleware
228
251
229
-
The middleware is auto-registered in `server` and `hybrid` mode. It redirects unprefixed URLs (e.g. `/about` → `/en/about`), keeps the locale cookie in sync, and automatically skips prerendered pages to avoid warnings about unavailable request headers.
252
+
The middleware is auto-registered in `server` and `hybrid` mode. It redirects unprefixed URLs (e.g. `/about` → `/en/about`) and keeps the locale cookie in sync.
230
253
231
254
You can also compose it manually with other middleware:
Locale.switch("fi") // sets cookie and navigates to the equivalent page in the new locale
273
-
```
290
+
`Locale.redirect(Astro)` returns a redirect `Response` if the URL has no locale prefix, or `null` if it does. Uses the cookie locale if available, falls back to `defaultLocale`. Invalid cookie values are ignored.
274
291
275
-
### Locale.redirect
292
+
Use it at the top of `404.astro` in `static` and `hybrid` mode:
276
293
277
-
```typescript
278
-
// Returns a redirect Response if the URL has no locale prefix, or null if it does.
279
-
// Use at the top of 404.astro in static and hybrid mode.
294
+
```astro
280
295
const redirect = Locale.redirect(Astro)
281
296
if (redirect) return redirect
282
297
```
283
298
284
-
Uses the locale cookie if available, falls back to `defaultLocale`. Invalid cookie values are ignored.
0 commit comments