@sveltekit-i18n/base 3.1.2 → 3.3.0
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/README.md +24 -23
- package/dist/I18n.svelte.d.ts +45 -2
- package/dist/I18n.svelte.js +404 -109
- package/dist/kit/define.svelte.js +140 -38
- package/dist/kit/internal.d.ts +8 -0
- package/dist/kit/server.browser.js +1 -1
- package/dist/kit/server.d.ts +1 -1
- package/dist/kit/server.js +17 -2
- package/dist/types.d.ts +39 -7
- package/dist/utils.d.ts +8 -13
- package/dist/utils.js +91 -62
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -34,9 +34,9 @@ Core i18n functionality for SvelteKit with support for custom message parsers. T
|
|
|
34
34
|
|
|
35
35
|
Svelte 5 or newer, and one of Node 22+, Bun 1.2+ or Deno 2+. The package is
|
|
36
36
|
ESM-only and imports no `node:` module, so every runtime that runs your
|
|
37
|
-
SvelteKit build runs it. The [`/kit`](#sveltekit) subpath needs SvelteKit 2
|
|
38
|
-
the SvelteKit behaviour the docs describe is checked against 2.70 and
|
|
39
|
-
|
|
37
|
+
SvelteKit build runs it. The [`/kit`](#sveltekit) subpath needs SvelteKit 2
|
|
38
|
+
or 3; the SvelteKit behaviour the docs describe is checked against 2.70 and
|
|
39
|
+
3.0.
|
|
40
40
|
|
|
41
41
|
## Installation
|
|
42
42
|
|
|
@@ -122,8 +122,8 @@ export { load } from '$lib/i18n';
|
|
|
122
122
|
The server picks the visitor's locale from the `Accept-Language` header (or
|
|
123
123
|
from a cookie, with `preferredLocale`), loads it per request and hands it to
|
|
124
124
|
the browser, so nothing loads twice and no visitor sees another's locale. See
|
|
125
|
-
[SvelteKit](https://github.com/sveltekit-i18n/base/blob/3.
|
|
126
|
-
[Server-Side Rendering](https://github.com/sveltekit-i18n/base/blob/3.
|
|
125
|
+
[SvelteKit](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#sveltekit) for the details and
|
|
126
|
+
[Server-Side Rendering](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#server-side-rendering) for wiring it
|
|
127
127
|
by hand.
|
|
128
128
|
|
|
129
129
|
### 4. Use in components
|
|
@@ -232,11 +232,11 @@ A named capture group in a `RegExp` route is a load parameter: its match reaches
|
|
|
232
232
|
}
|
|
233
233
|
```
|
|
234
234
|
|
|
235
|
-
`API_ORIGIN` stands for an origin such as `https://api.example.com`: a loader runs on the server too, where `fetch` takes only an absolute URL. See [route params](https://github.com/sveltekit-i18n/base/blob/3.
|
|
235
|
+
`API_ORIGIN` stands for an origin such as `https://api.example.com`: a loader runs on the server too, where `fetch` takes only an absolute URL. See [route params](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#route-params) for the rules.
|
|
236
236
|
|
|
237
|
-
A loader whose source does the caching itself — a SvelteKit remote `query`, an SWR layer, an HTTP cache — sets `cache: false`. It then runs on every load trigger that selects it, and `config.cache` does not apply to it; only a hydrated snapshot holds it back, for the locale and route it was rendered for. See [the loader's `cache`](https://github.com/sveltekit-i18n/base/blob/3.
|
|
237
|
+
A loader whose source does the caching itself — a SvelteKit remote `query`, an SWR layer, an HTTP cache — sets `cache: false`. It then runs on every load trigger that selects it, sharing a fetch of it already in flight for the same params and route, and `config.cache` does not apply to it; only a hydrated snapshot holds it back, for the locale and route it was rendered for, until another locale or route is requested or a `preload()` runs, and a call handed a [`preload()`](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#preloadlocale-route) token shows what that preload fetched instead of running it again. See [the loader's `cache`](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#cache-optional).
|
|
238
238
|
|
|
239
|
-
A loader that throws is logged, and the rest of the load lands without its data; it runs again on the next load trigger. SvelteKit's `redirect()` and an `error()` below 500 (told by their shape: an own `status` with a `location` or a `body`, on a value that is not an `Error`) are logged too, but they also reject the load, so a SvelteKit `load` awaiting the call hands them to SvelteKit; the rejected call is undone — what it replaced goes back — unless a later call that has not failed came in the meantime. See [the loader](https://github.com/sveltekit-i18n/base/blob/3.
|
|
239
|
+
A loader that throws is logged, and the rest of the load lands without its data; it runs again on the next load trigger. SvelteKit's `redirect()` and an `error()` below 500 (told by their shape: an own `status` with a `location` or a `body`, on a value that is not an `Error`) are logged too, but they also reject the load, so a SvelteKit `load` awaiting the call hands them to SvelteKit; the rejected call is undone — what it replaced goes back — unless a later call that has not failed came in the meantime. See [the loader](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#loader-required).
|
|
240
240
|
|
|
241
241
|
Both `loaders` and a loader's `routes` accept readonly arrays, so a whole-config `as const` is fine.
|
|
242
242
|
|
|
@@ -251,11 +251,11 @@ import { PUBLIC_BASE_PATH } from '$env/static/public';
|
|
|
251
251
|
basePath: PUBLIC_BASE_PATH
|
|
252
252
|
```
|
|
253
253
|
|
|
254
|
-
See [`basePath`](https://github.com/sveltekit-i18n/base/blob/3.
|
|
254
|
+
See [`basePath`](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#basepath).
|
|
255
255
|
|
|
256
256
|
### `translations`
|
|
257
257
|
|
|
258
|
-
Synchronous translations, available immediately. They seed the tables: the loaders of a namespace they name still run and merge into it. Hand a server's state over with [`hydrate()`](https://github.com/sveltekit-i18n/base/blob/3.
|
|
258
|
+
Synchronous translations, available immediately. They seed the tables: the loaders of a namespace they name still run and merge into it. Hand a server's state over with [`hydrate()`](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#hydrateenvelope) instead:
|
|
259
259
|
|
|
260
260
|
```javascript
|
|
261
261
|
translations: {
|
|
@@ -267,13 +267,13 @@ translations: {
|
|
|
267
267
|
|
|
268
268
|
### `initLocale`
|
|
269
269
|
|
|
270
|
-
|
|
270
|
+
The initial locale, used when nothing else decides:
|
|
271
271
|
|
|
272
272
|
```javascript
|
|
273
273
|
initLocale: 'en'
|
|
274
274
|
```
|
|
275
275
|
|
|
276
|
-
With [`defineI18n()`](#sveltekit) it
|
|
276
|
+
With [`defineI18n()`](#sveltekit) it is the locale a visitor gets when nothing they prefer is served, and it loads only when negotiation picks it ([Which locale](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#which-locale)). With `new I18n(config)` the constructor loads it right away, so leave it out of a config whose instance you [`hydrate()`](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#hydrateenvelope) by hand — its load starts before the hand-off can be applied.
|
|
277
277
|
|
|
278
278
|
### `fallbackLocale`
|
|
279
279
|
|
|
@@ -295,7 +295,7 @@ fallbackValue: '...' // Default: returns the key itself
|
|
|
295
295
|
|
|
296
296
|
### `sanitizeLocales`
|
|
297
297
|
|
|
298
|
-
How locale identifiers are normalized before they key anything: `true` (default) resolves them to their ISO form through `Intl` (`'en-us'` is `'en-US'`), `false` keeps them as authored, and a function normalizes them your way. See [`sanitizeLocales`](https://github.com/sveltekit-i18n/base/blob/3.
|
|
298
|
+
How locale identifiers are normalized before they key anything: `true` (default) resolves them to their ISO form through `Intl` (`'en-us'` is `'en-US'`), `false` keeps them as authored, and a function normalizes them your way. See [`sanitizeLocales`](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#sanitizelocales).
|
|
299
299
|
|
|
300
300
|
### `preprocess`
|
|
301
301
|
|
|
@@ -334,11 +334,11 @@ Or state it per instance — only its type is read, so the value can stay empty
|
|
|
334
334
|
const i18n = new I18n({ ...config, schema: {} as TranslationSchema });
|
|
335
335
|
```
|
|
336
336
|
|
|
337
|
-
Hand-write it for a small set of messages, or generate it — [@sveltekit-i18n/typegen](https://github.com/sveltekit-i18n/typegen), a separate package, generates one. A schema whose keys are not a closed set (`schema: {}`) types nothing and keeps the registry out, so keys stay plain strings. A library never registers. The registry needs base 3.1 or newer. See [`schema`](https://github.com/sveltekit-i18n/base/blob/3.
|
|
337
|
+
Hand-write it for a small set of messages, or generate it — [@sveltekit-i18n/typegen](https://github.com/sveltekit-i18n/typegen), a separate package, generates one. A schema whose keys are not a closed set (`schema: {}`) types nothing and keeps the registry out, so keys stay plain strings. A library never registers. The registry needs base 3.1 or newer. See [`schema`](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#schema) for the full rules.
|
|
338
338
|
|
|
339
339
|
### `cache`
|
|
340
340
|
|
|
341
|
-
Time in milliseconds the loaded translations stay fresh for. By default, loaded translations never expire — each loader (but one with [`cache: false`](https://github.com/sveltekit-i18n/base/blob/3.
|
|
341
|
+
Time in milliseconds the loaded translations stay fresh for. By default, loaded translations never expire — each loader (but one with [`cache: false`](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#cache-optional)) runs once per locale and [route params](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#route-params) (a loader's `routes` decide whether a load trigger considers it, and the params their named groups capture decide when it runs again).
|
|
342
342
|
|
|
343
343
|
Set a finite value when your loaders fetch from a source that can change at runtime (e.g. a CMS):
|
|
344
344
|
|
|
@@ -346,7 +346,7 @@ Set a finite value when your loaders fetch from a source that can change at runt
|
|
|
346
346
|
cache: 3600000 // Translations older than 1 hour refetch on the next activating load
|
|
347
347
|
```
|
|
348
348
|
|
|
349
|
-
Expiry is evaluated by the next activating load trigger (`setLocale`, `setRoute`, `loadTranslations`)
|
|
349
|
+
Expiry is evaluated by the next activating load trigger (`setLocale`, `setRoute`, `loadTranslations`) or `preload()`; a warm load — `loadTranslations(…, { activate: false })` or `loadNamespace()` — fills the tables without evaluating it, and a call handed a `preload()` token leaves it to that preload. Set to `0` to treat translations as always stale (refetch on every activating load trigger). A loader with `cache: false` is outside the window. You can also drop the loaded state manually at any time with [`invalidate()`](#methods).
|
|
350
350
|
|
|
351
351
|
### `extensions`
|
|
352
352
|
|
|
@@ -405,14 +405,15 @@ log: {
|
|
|
405
405
|
|
|
406
406
|
Load-triggering methods return the promise of the matching load — concurrent duplicate triggers from one route share one in-flight load (and its promise) instead of fetching twice.
|
|
407
407
|
|
|
408
|
-
- `loadTranslations(locale, route?, options?)` – load translations for locale and route; `route` defaults to the current one,
|
|
408
|
+
- `loadTranslations(locale, route?, options?)` – load translations for locale and route; `route` defaults to the current one, `{ activate: false }` only fills the tables without switching to them, and `{ preloaded }` takes a `preload()` token
|
|
409
|
+
- `preload(locale, route?)` – the request of a navigation that may never commit (a router's `load`, a hover's included): it judges freshness and runs `cache: false` loaders as an activating call would, shows nothing, and resolves to a token the commit's `loadTranslations()` or `setRoute()` takes as `{ preloaded }` to show what it fetched instead of fetching it again
|
|
409
410
|
- `loadNamespace(namespace, locale?)` – load one namespace on demand, whatever its loaders' routes, without switching to it; it stays loaded across routes
|
|
410
411
|
- `setLocale(locale)` – request a locale; loads once a route is known
|
|
411
|
-
- `setRoute(route)` – update the current route
|
|
412
|
+
- `setRoute(route, options?)` – update the current route; `{ preloaded }` takes a `preload()` token
|
|
412
413
|
- `loadConfig(config)` – (re)configure the instance
|
|
413
414
|
- `addTranslations(translations)` – seed synchronous translations; the loaders of their namespaces still run and merge into them
|
|
414
415
|
- `snapshot(options?)` – serialize what the active locale (and the fallback) holds; `{ records: true }` returns the envelope `hydrate()` restores, with the loaders that delivered, the active locale and the route, and no argument returns the data alone, shaped like `config.translations`, for a plain `hydrate({ translations })`
|
|
415
|
-
- `hydrate(envelope?)` – restore a server's snapshot: its data, its load records (so those loaders do not run again — one with `cache: false` only for the locale and route it was rendered for), its locale and its route; an envelope without records keeps the loaders of the namespaces its data names from running
|
|
416
|
+
- `hydrate(envelope?)` – restore a server's snapshot: its data, its load records (so those loaders do not run again — one with `cache: false` only for the locale and route it was rendered for, until a `preload()` runs or `invalidate()` covers it), its locale and its route; an envelope without records keeps the loaders of the namespaces its data names from running
|
|
416
417
|
- `invalidate(locale?, namespace?)` – mark loaded translations stale (one locale or all, one namespace or all); loaders run again on the next load trigger, and a loader still in flight for what was invalidated settles with whatever it returns or throws discarded — an activating trigger fetches it again before it activates, unless another loader of its load threw SvelteKit's control flow
|
|
417
418
|
- `destroy()` – detach a per-request or per-component instance: in-flight loads settle discarded, further load and mutation calls are ignored, reads keep working
|
|
418
419
|
|
|
@@ -443,12 +444,12 @@ export const { handle, load, use, get } = defineI18n(config, { preferredLocale }
|
|
|
443
444
|
- `use(() => data)` – called once in the root `+layout.svelte`; provides the instance, follows every navigation and keeps `<html lang>` and `<html dir>` in sync
|
|
444
445
|
- `get()` – the instance, in any component below the root layout
|
|
445
446
|
|
|
446
|
-
Full API documentation: [docs/README.md](https://github.com/sveltekit-i18n/base/blob/3.
|
|
447
|
+
Full API documentation: [docs/README.md](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md)
|
|
447
448
|
|
|
448
449
|
## Documentation
|
|
449
450
|
|
|
450
451
|
- 🌐 [sveltekit-i18n.github.io](https://sveltekit-i18n.github.io) – The documentation site, with a live playground
|
|
451
|
-
- 📖 [Full API Documentation](https://github.com/sveltekit-i18n/base/blob/3.
|
|
452
|
+
- 📖 [Full API Documentation](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md) – Complete reference
|
|
452
453
|
- 📚 [Main Library Docs](https://github.com/sveltekit-i18n/lib/tree/master/docs/INDEX.md) – Guides, tutorials, and best practices
|
|
453
454
|
- 🎨 [Parsers](https://github.com/sveltekit-i18n/parsers) – Available parsers and how to create your own
|
|
454
455
|
- 💡 [Examples](https://github.com/sveltekit-i18n/lib/tree/master/examples) – Real-world usage examples
|
|
@@ -470,7 +471,7 @@ const config: Config.T<Params> = {
|
|
|
470
471
|
};
|
|
471
472
|
```
|
|
472
473
|
|
|
473
|
-
Two more things are inferred from the config itself. [`schema`](#schema) types the keys and payloads of `t`/`l`, and every locale the config names — loader locales, `initLocale`, `fallbackLocale` and the keys of `translations` — completes the locale arguments and reads (`setLocale`, `loadTranslations`, `loadNamespace`, `invalidate`, `l`, `locale`, `locales`):
|
|
474
|
+
Two more things are inferred from the config itself. [`schema`](#schema) types the keys and payloads of `t`/`l`, and every locale the config names — loader locales, `initLocale`, `fallbackLocale` and the keys of `translations` — completes the locale arguments and reads (`setLocale`, `loadTranslations`, `loadNamespace`, `preload`, `invalidate`, `l`, `locale`, `locales`):
|
|
474
475
|
|
|
475
476
|
```typescript
|
|
476
477
|
const i18n = new I18n({ parser: parser({ onReport: null }), initLocale: 'en', fallbackLocale: 'de' });
|
|
@@ -479,7 +480,7 @@ i18n.setLocale('en'); // 'en' | 'de' autocomplete here
|
|
|
479
480
|
i18n.setLocale('sv'); // still accepted — the union is a hint, not a constraint
|
|
480
481
|
```
|
|
481
482
|
|
|
482
|
-
The locales survive only when the config reaches the constructor as a literal — inline, as above, or a separate object with `as const`. An annotated or separately widened config, and any config with one dynamic locale source (`loaders: locales.map(...)`), leaves them plain `string`. See [TypeScript](https://github.com/sveltekit-i18n/base/blob/3.
|
|
483
|
+
The locales survive only when the config reaches the constructor as a literal — inline, as above, or a separate object with `as const`. An annotated or separately widened config, and any config with one dynamic locale source (`loaders: locales.map(...)`), leaves them plain `string`. See [TypeScript](https://github.com/sveltekit-i18n/base/blob/3.3.0/docs/README.md#typescript) for both.
|
|
483
484
|
|
|
484
485
|
## Related Packages
|
|
485
486
|
|
package/dist/I18n.svelte.d.ts
CHANGED
|
@@ -35,7 +35,14 @@ declare class I18nCore<ParserParams extends Parser.Params = any, ParserOutput =
|
|
|
35
35
|
*/
|
|
36
36
|
loadConfig: (config: Config.T<ParserParams, ParserOutput>) => Promise<void>;
|
|
37
37
|
setLocale: (locale?: Config.LocaleInput<LocaleUnion>) => Promise<void>;
|
|
38
|
-
|
|
38
|
+
/**
|
|
39
|
+
* With `{ preloaded }`, the token of a `preload()` for the requested locale
|
|
40
|
+
* and this route, it shows what that preload fetched — see
|
|
41
|
+
* `loadTranslations()`.
|
|
42
|
+
*/
|
|
43
|
+
setRoute: (input: string, options?: {
|
|
44
|
+
preloaded?: Loader.Preloaded | undefined;
|
|
45
|
+
}) => Promise<void>;
|
|
39
46
|
/**
|
|
40
47
|
* `{ activate: false }` only fills the tables: it leaves the requested
|
|
41
48
|
* locale, the route and `locale` untouched and does not count towards
|
|
@@ -45,10 +52,46 @@ declare class I18nCore<ParserParams extends Parser.Params = any, ParserOutput =
|
|
|
45
52
|
* it. It
|
|
46
53
|
* leaves `cache` expiry to the next activating trigger. A loader's
|
|
47
54
|
* `redirect()` or `error()` below 500 rejects it all the same.
|
|
55
|
+
*
|
|
56
|
+
* `{ preloaded }` hands an activating call the token of a `preload()` for
|
|
57
|
+
* the same locale and route. The call then evaluates no `cache` window — the
|
|
58
|
+
* preload did — and shows what the preload fetched instead of fetching it
|
|
59
|
+
* again, at once when nothing else is left to fetch, and otherwise with the
|
|
60
|
+
* rest, in one go. It fetches what the preload did not deliver, and what it
|
|
61
|
+
* delivered to a loader that shows something else since — a seed or
|
|
62
|
+
* another delivery replaced what it showed — wherever the call has that
|
|
63
|
+
* loader to load anyway (one with `cache: false`, or one whose record an
|
|
64
|
+
* expiry dropped, say). A token serves one call: the first activating call
|
|
65
|
+
* that reads it spends it, whether or not it serves that call, even with
|
|
66
|
+
* nothing left to fetch; a call left without a locale to show — handed an
|
|
67
|
+
* empty one or one nothing serves, say — reads none. Another instance's,
|
|
68
|
+
* one of another locale or route, one spent already and one older than a
|
|
69
|
+
* `loadConfig()` or an `invalidate()` are ignored, as is any with
|
|
70
|
+
* `{ activate: false }`, which leaves it unspent. A window a later request
|
|
71
|
+
* found elapsed does not void it: the preload judged the window at its own
|
|
72
|
+
* request.
|
|
48
73
|
*/
|
|
49
|
-
loadTranslations: (locale: Config.LocaleInput<LocaleUnion>, route?: string, { activate }?: {
|
|
74
|
+
loadTranslations: (locale: Config.LocaleInput<LocaleUnion>, route?: string, { activate, preloaded }?: {
|
|
50
75
|
activate?: boolean;
|
|
76
|
+
preloaded?: Loader.Preloaded | undefined;
|
|
51
77
|
}) => Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* A request for `locale` on `route` (the current route by default) that
|
|
80
|
+
* shows nothing new by itself: what a router's `load` runs ahead of a
|
|
81
|
+
* navigation, a hover's included. Like an activating call it evaluates the
|
|
82
|
+
* `cache` window, ends the pass a hand-off serves, and runs a loader with
|
|
83
|
+
* `cache: false` — sharing a fetch of it for the same params and route
|
|
84
|
+
* already in flight. Like `{ activate: false }` it writes neither the locale
|
|
85
|
+
* nor the route, does not count towards `loading`, and lands what it fetched
|
|
86
|
+
* as a warm load does. It resolves to a token for the next activating call of
|
|
87
|
+
* that locale and route, which shows what it fetched (see
|
|
88
|
+
* `loadTranslations()`), and to `undefined` once the instance was destroyed
|
|
89
|
+
* or when nothing serves the locale. A loader's `redirect()` or `error()`
|
|
90
|
+
* below 500 rejects it, unless it shares its load with an activating call,
|
|
91
|
+
* whose outcome it then gets; one nobody awaits never becomes an unhandled
|
|
92
|
+
* rejection.
|
|
93
|
+
*/
|
|
94
|
+
preload: (locale: Config.LocaleInput<LocaleUnion>, route?: string) => Promise<Loader.Preloaded | undefined>;
|
|
52
95
|
/**
|
|
53
96
|
* Loads one namespace for the active locale (or `locale`), whatever the
|
|
54
97
|
* routes of its loaders say — for what an interaction needs rather than a
|