Skip to content

Commit cd0e1c0

Browse files
authored
Merge pull request #15 from eremannisto/update-readme
Feature: Update `README`
2 parents 4c4fd96 + db02262 commit cd0e1c0

File tree

2 files changed

+110
-97
lines changed

2 files changed

+110
-97
lines changed

README.md

Lines changed: 109 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,19 @@ A full-featured i18n integration for Astro. Handles locale detection, URL routin
1212

1313
```bash
1414
pnpm add @mannisto/astro-i18n
15+
```
16+
17+
```bash
1518
npm install @mannisto/astro-i18n
19+
```
20+
21+
```bash
1622
yarn add @mannisto/astro-i18n
1723
```
1824

19-
## Setup
25+
## Getting started
26+
27+
### 1. Configure the integration
2028

2129
```typescript
2230
// astro.config.ts
@@ -40,35 +48,24 @@ export default defineConfig({
4048

4149
See the full [Configuration reference](#configuration) below.
4250

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
4852

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+
```
6463

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.
6865
69-
## Translations
66+
### 3. Add translations
7067

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.
7269

7370
```json
7471
{
@@ -80,81 +77,81 @@ Create a `src/translations/` directory with one JSON file per locale. Files must
8077

8178
All locale files must define the same set of keys.
8279

83-
## Usage
80+
### 4. Set up your layout
8481

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.
8883

8984
```astro
9085
---
86+
// src/layouts/Layout.astro
9187
import { Locale } from "@mannisto/astro-i18n/runtime"
9288
93-
export const getStaticPaths = () => {
94-
return Locale.supported.map((code) => ({ params: { locale: code } }))
95-
}
96-
9789
const locale = Locale.from(Astro.url)
98-
const t = Locale.use(locale)
9990
---
10091
10192
<html lang={locale}>
10293
<head>
103-
<meta charset="UTF-8">
104-
<title>{t("nav.home")}</title>
94+
<meta charset="UTF-8" />
95+
<script is:inline define:vars={{ locale }}>
96+
document.cookie = `locale=${locale}; path=/; SameSite=Lax; Max-Age=31536000`
97+
</script>
10598
</head>
10699
<body>
107-
<h1>{t("nav.home")}</h1>
108-
<a href={Locale.url("fi", Astro.url.pathname)}>Suomeksi</a>
100+
<slot />
109101
</body>
110102
</html>
111103
```
112104

113-
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:
114108

115109
```astro
116110
---
117-
export const prerender = false
118-
111+
// src/pages/[locale]/index.astro
119112
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+
}
120120
121121
const locale = Locale.from(Astro.url)
122122
const t = Locale.use(locale)
123123
---
124-
```
125124
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+
```
129129

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:
131131

132132
```astro
133133
---
134-
// src/layouts/Layout.astro
134+
export const prerender = false
135+
135136
import { Locale } from "@mannisto/astro-i18n/runtime"
137+
import Layout from "@layouts/Layout.astro"
136138
137139
const locale = Locale.from(Astro.url)
140+
const t = Locale.use(locale)
138141
---
139142
140-
<html lang={locale}>
141-
<head>
142-
<meta charset="UTF-8" />
143-
<script is:inline define:vars={{ locale }}>
144-
document.cookie = `locale=${locale}; path=/; SameSite=Lax; Max-Age=31536000`
145-
</script>
146-
</head>
147-
<body>
148-
<slot />
149-
</body>
150-
</html>
143+
<Layout>
144+
<h1>{t("nav.home")}</h1>
145+
</Layout>
151146
```
152147

153-
### 404 pages
148+
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
154151

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.
156153

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.
158155

159156
```astro
160157
---
@@ -168,13 +165,13 @@ const locale = Locale.from(Astro.url)
168165
const t = Locale.use(locale)
169166
---
170167
171-
<Layout title={t("error.title")}>
168+
<Layout>
172169
<h1>{t("error.title")}</h1>
173170
<p>{t("error.description")}</p>
174171
</Layout>
175172
```
176173

177-
**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.
178175

179176
```astro
180177
---
@@ -191,13 +188,39 @@ const locale = Locale.from(Astro.url)
191188
const t = Locale.use(locale)
192189
---
193190
194-
<Layout title={t("error.title")}>
191+
<Layout>
195192
<h1>{t("error.title")}</h1>
196193
<p>{t("error.description")}</p>
197194
</Layout>
198195
```
199196

200-
### Language switcher
197+
## Modes
198+
199+
### `static`
200+
201+
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
201224

202225
```astro
203226
---
@@ -224,9 +247,9 @@ const locales = Locale.get()
224247
</script>
225248
```
226249

227-
### Middleware
250+
## Middleware
228251

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.
230253

231254
You can also compose it manually with other middleware:
232255

@@ -243,46 +266,36 @@ export const onRequest = sequence(i18nMiddleware, myMiddleware)
243266

244267
### Locale
245268

246-
```typescript
247-
Locale.supported // ["en", "fi"] — array of all locale codes
248-
Locale.defaultLocale // "en"
249-
Locale.get() // all locale configs
250-
Locale.get("fi") // { code: "fi", name: "Finnish", endonym: "Suomi", ... }
251-
Locale.from(Astro.url) // "fi" — derives current locale from URL
252-
```
253-
254-
### Translations
269+
| Method | Returns | Description |
270+
| --- | --- | --- |
271+
| `Locale.supported` | `["en", "fi"]` | Array of all supported locale codes |
272+
| `Locale.defaultLocale` | `"en"` | The configured default locale |
273+
| `Locale.get()` | `LocaleConfig[]` | All locale configs |
274+
| `Locale.get("fi")` | `LocaleConfig` | Config for a specific locale |
275+
| `Locale.from(Astro.url)` | `"fi"` | Derives the current locale from the URL |
276+
| `Locale.use(locale)` | `t` | Returns a translation function for the given locale — call it as `t("key")` |
277+
| `Locale.switch("fi")` | `void` | Sets the locale cookie and navigates to the equivalent page |
255278

256-
```typescript
257-
const t = Locale.use(locale)
258-
t("nav.home") // "Home"
259-
```
260279

261280
### URL helpers
262281

263-
```typescript
264-
Locale.url("fi") // "/fi/"
265-
Locale.url("fi", "/about") // "/fi/about"
266-
Locale.url("fi", Astro.url.pathname) // "/fi/current-path"
267-
```
282+
| Method | Returns |
283+
| --- | --- |
284+
| `Locale.url("fi")` | `"/fi/"` |
285+
| `Locale.url("fi", "/about")` | `"/fi/about"` |
286+
| `Locale.url("fi", Astro.url.pathname)` | `"/fi/current-path"` |
268287

269-
### Switching locale
288+
### Locale.redirect
270289

271-
```typescript
272-
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.
274291

275-
### Locale.redirect
292+
Use it at the top of `404.astro` in `static` and `hybrid` mode:
276293

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
280295
const redirect = Locale.redirect(Astro)
281296
if (redirect) return redirect
282297
```
283298

284-
Uses the locale cookie if available, falls back to `defaultLocale`. Invalid cookie values are ignored.
285-
286299
## Configuration
287300

288301
```typescript

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@mannisto/astro-i18n",
3-
"version": "1.0.0-rc.1",
3+
"version": "1.0.0-rc.2",
44
"description": "A flexible alternative to Astro's built-in i18n, with locale routing, detection, and translations for static and SSR sites.",
55
"license": "MIT",
66
"type": "module",

0 commit comments

Comments
 (0)