@sveltekit-i18n/base 3.3.1 → 3.3.2
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 +25 -15
- package/dist/kit/backend.browser.d.ts +2 -0
- package/dist/kit/define.svelte.js +1 -0
- package/dist/kit/internal.d.ts +4 -2
- package/dist/kit/types.d.ts +28 -16
- package/package.json +3 -3
- package/dist/kit/server.browser.d.ts +0 -2
- /package/dist/kit/{server.browser.js → backend.browser.js} +0 -0
- /package/dist/kit/{server.d.ts → backend.d.ts} +0 -0
- /package/dist/kit/{server.js → backend.js} +0 -0
package/README.md
CHANGED
|
@@ -128,8 +128,8 @@ export { load } from '#lib/i18n.js';
|
|
|
128
128
|
The server picks the visitor's locale from the `Accept-Language` header (or
|
|
129
129
|
from a cookie, with `preferredLocale`), loads it per request and hands it to
|
|
130
130
|
the browser, so nothing loads twice and no visitor sees another's locale. See
|
|
131
|
-
[SvelteKit](https://github.com/sveltekit-i18n/base/blob/3.3.
|
|
132
|
-
[Server-Side Rendering](https://github.com/sveltekit-i18n/base/blob/3.3.
|
|
131
|
+
[SvelteKit](https://github.com/sveltekit-i18n/base/blob/3.3.2/docs/README.md#sveltekit) for the details and
|
|
132
|
+
[Server-Side Rendering](https://github.com/sveltekit-i18n/base/blob/3.3.2/docs/README.md#server-side-rendering) for wiring it
|
|
133
133
|
by hand.
|
|
134
134
|
|
|
135
135
|
### 4. Use in components
|
|
@@ -238,11 +238,11 @@ A named capture group in a `RegExp` route is a load parameter: its match reaches
|
|
|
238
238
|
}
|
|
239
239
|
```
|
|
240
240
|
|
|
241
|
-
`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.
|
|
241
|
+
`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.2/docs/README.md#route-params) for the rules.
|
|
242
242
|
|
|
243
|
-
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.
|
|
243
|
+
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.2/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.2/docs/README.md#cache-optional).
|
|
244
244
|
|
|
245
|
-
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.
|
|
245
|
+
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.2/docs/README.md#loader-required).
|
|
246
246
|
|
|
247
247
|
Both `loaders` and a loader's `routes` accept readonly arrays, so a whole-config `as const` is fine.
|
|
248
248
|
|
|
@@ -256,11 +256,11 @@ The path the app is served under — SvelteKit's `paths.base`. Every route hande
|
|
|
256
256
|
basePath: import.meta.env.VITE_BASE_PATH
|
|
257
257
|
```
|
|
258
258
|
|
|
259
|
-
See [`basePath`](https://github.com/sveltekit-i18n/base/blob/3.3.
|
|
259
|
+
See [`basePath`](https://github.com/sveltekit-i18n/base/blob/3.3.2/docs/README.md#basepath).
|
|
260
260
|
|
|
261
261
|
### `translations`
|
|
262
262
|
|
|
263
|
-
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.
|
|
263
|
+
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.2/docs/README.md#hydrateenvelope) instead:
|
|
264
264
|
|
|
265
265
|
```javascript
|
|
266
266
|
translations: {
|
|
@@ -278,7 +278,7 @@ The initial locale, used when nothing else decides:
|
|
|
278
278
|
initLocale: 'en'
|
|
279
279
|
```
|
|
280
280
|
|
|
281
|
-
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.
|
|
281
|
+
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.2/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.2/docs/README.md#hydrateenvelope) by hand — its load starts before the hand-off can be applied.
|
|
282
282
|
|
|
283
283
|
### `fallbackLocale`
|
|
284
284
|
|
|
@@ -300,7 +300,7 @@ fallbackValue: '...' // Default: returns the key itself
|
|
|
300
300
|
|
|
301
301
|
### `sanitizeLocales`
|
|
302
302
|
|
|
303
|
-
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.
|
|
303
|
+
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.2/docs/README.md#sanitizelocales).
|
|
304
304
|
|
|
305
305
|
### `preprocess`
|
|
306
306
|
|
|
@@ -339,11 +339,11 @@ Or state it per instance — only its type is read, so the value can stay empty
|
|
|
339
339
|
const i18n = new I18n({ ...config, schema: {} as TranslationSchema });
|
|
340
340
|
```
|
|
341
341
|
|
|
342
|
-
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.
|
|
342
|
+
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.2/docs/README.md#schema) for the full rules.
|
|
343
343
|
|
|
344
344
|
### `cache`
|
|
345
345
|
|
|
346
|
-
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.
|
|
346
|
+
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.2/docs/README.md#cache-optional)) runs once per locale and [route params](https://github.com/sveltekit-i18n/base/blob/3.3.2/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).
|
|
347
347
|
|
|
348
348
|
Set a finite value when your loaders fetch from a source that can change at runtime (e.g. a CMS):
|
|
349
349
|
|
|
@@ -366,7 +366,15 @@ const { t, locale, loading } = new I18n({
|
|
|
366
366
|
});
|
|
367
367
|
```
|
|
368
368
|
|
|
369
|
-
An extension may augment the instance in place, or replace the surface entirely (like the store adapter above).
|
|
369
|
+
An extension may augment the instance in place, or replace the surface entirely (like the store adapter above). The official extensions live in the [extensions](https://github.com/sveltekit-i18n/extensions) repository:
|
|
370
|
+
|
|
371
|
+
- [@sveltekit-i18n/extension-stores](https://github.com/sveltekit-i18n/extensions/tree/master/extension-stores) – replaces the instance with the Svelte-store surface of v2 (`$t`, `$locale`, `$loading`, …), the instance it received at `instance`
|
|
372
|
+
- [@sveltekit-i18n/extension-html](https://github.com/sveltekit-i18n/extensions/tree/master/extension-html) – adds a `T` component that renders the markup a message carries as elements and Svelte components, from an allowlist, with no `{@html}`
|
|
373
|
+
- [@sveltekit-i18n/extension-typed-access](https://github.com/sveltekit-i18n/extensions/tree/master/extension-typed-access) – keys as members of `t`: `i18n.t.home.title()` beside `i18n.t('home.title')`, typed from the [`schema`](#schema)
|
|
374
|
+
|
|
375
|
+
Their order matters. `stores` returns no instance, so it goes after the other two: `[typedAccess, stores]` hands out the tree as `$t.home.title()`, and with `[html({ onReport: null }), stores]` the component is at `instance.T`. `html` after `typedAccess` adds `T` beside the tree, while before it `T` is typed at `instance.T` only. Each package's README has the details, and [lib's examples](https://github.com/sveltekit-i18n/lib/tree/master/examples#extensions) run each one.
|
|
376
|
+
|
|
377
|
+
A custom extension is just a function:
|
|
370
378
|
|
|
371
379
|
```javascript
|
|
372
380
|
const withGreeting = (i18n) => Object.assign(i18n, {
|
|
@@ -449,12 +457,12 @@ export const { handle, load, use, get } = defineI18n(config, { preferredLocale }
|
|
|
449
457
|
- `use(() => data)` – called once in the root `+layout.svelte`; provides the instance, follows every navigation and keeps `<html lang>` and `<html dir>` in sync
|
|
450
458
|
- `get()` – the instance, in any component below the root layout
|
|
451
459
|
|
|
452
|
-
Full API documentation: [docs/README.md](https://github.com/sveltekit-i18n/base/blob/3.3.
|
|
460
|
+
Full API documentation: [docs/README.md](https://github.com/sveltekit-i18n/base/blob/3.3.2/docs/README.md)
|
|
453
461
|
|
|
454
462
|
## Documentation
|
|
455
463
|
|
|
456
464
|
- 🌐 [sveltekit-i18n.github.io](https://sveltekit-i18n.github.io) – The documentation site, with a live playground
|
|
457
|
-
- 📖 [Full API Documentation](https://github.com/sveltekit-i18n/base/blob/3.3.
|
|
465
|
+
- 📖 [Full API Documentation](https://github.com/sveltekit-i18n/base/blob/3.3.2/docs/README.md) – Complete reference
|
|
458
466
|
- 📚 [Main Library Docs](https://github.com/sveltekit-i18n/lib/tree/master/docs/INDEX.md) – Guides, tutorials, and best practices
|
|
459
467
|
- 🎨 [Parsers](https://github.com/sveltekit-i18n/parsers) – Available parsers and how to create your own
|
|
460
468
|
- 💡 [Examples](https://github.com/sveltekit-i18n/lib/tree/master/examples) – Real-world usage examples
|
|
@@ -485,7 +493,9 @@ i18n.setLocale('en'); // 'en' | 'de' autocomplete here
|
|
|
485
493
|
i18n.setLocale('sv'); // still accepted — the union is a hint, not a constraint
|
|
486
494
|
```
|
|
487
495
|
|
|
488
|
-
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.
|
|
496
|
+
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.2/docs/README.md#typescript) for both.
|
|
497
|
+
|
|
498
|
+
Keys as members of `t` — `i18n.t.home.title()` beside `i18n.t('home.title')` — come from [@sveltekit-i18n/extension-typed-access](https://github.com/sveltekit-i18n/extensions/tree/master/extension-typed-access), an official [extension](#extensions) typed from the same schema. It reads the keys nested by segment that [@sveltekit-i18n/typegen](https://github.com/sveltekit-i18n/typegen) registers beside the schema, as `tree`, and groups the keys itself without them; the core reads none of it.
|
|
489
499
|
|
|
490
500
|
## Related Packages
|
|
491
501
|
|
|
@@ -48,6 +48,7 @@ export const defineI18n = (config, options = {}) => {
|
|
|
48
48
|
let reported = false;
|
|
49
49
|
const preferred = (event) => {
|
|
50
50
|
try {
|
|
51
|
+
// Typed for string params; a param a matcher parsed misses as no locale.
|
|
51
52
|
return options.preferredLocale?.(event);
|
|
52
53
|
}
|
|
53
54
|
catch (error) {
|
package/dist/kit/internal.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { I18n } from '../I18n.svelte.js';
|
|
2
2
|
import type { Kit } from './types.js';
|
|
3
|
+
/** The params of an event the wiring reads: SvelteKit 3 hands a param its matcher parsed as it parsed it. */
|
|
4
|
+
export type Params = Partial<Record<string, Kit.ParamValue>>;
|
|
3
5
|
/** The negotiated locale, and whether `preferredLocale` gave it. */
|
|
4
6
|
export type Negotiated = {
|
|
5
7
|
locale: string | undefined;
|
|
@@ -8,7 +10,7 @@ export type Negotiated = {
|
|
|
8
10
|
/** What the server half needs from the factory. */
|
|
9
11
|
export type Shared = {
|
|
10
12
|
create: () => I18n;
|
|
11
|
-
negotiate: (event: Kit.Event
|
|
13
|
+
negotiate: (event: Kit.Event<Params>, ranges: string | readonly string[] | null | undefined) => Negotiated;
|
|
12
14
|
/** The locales the config serves. */
|
|
13
15
|
locales: () => string[];
|
|
14
16
|
basePath: string | undefined;
|
|
@@ -21,7 +23,7 @@ export type Shared = {
|
|
|
21
23
|
};
|
|
22
24
|
export type ServerHalf = {
|
|
23
25
|
handle: Kit.T['handle'];
|
|
24
|
-
load: (event: Kit.ServerLoadEvent) => Promise<{
|
|
26
|
+
load: (event: Kit.ServerLoadEvent<Params>) => Promise<{
|
|
25
27
|
i18n: Kit.Payload;
|
|
26
28
|
}>;
|
|
27
29
|
/** The instance a page render loaded for `payload`, handed out once. */
|
package/dist/kit/types.d.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import type { I18n } from '../I18n.svelte.js';
|
|
2
2
|
import type { Snapshot } from '../types.js';
|
|
3
3
|
export declare namespace Kit {
|
|
4
|
+
/** A route param as SvelteKit 3 types it: a string, or what its matcher parsed it to. */
|
|
5
|
+
type ParamValue = string | number | boolean | bigint;
|
|
4
6
|
/**
|
|
5
|
-
* The members of a SvelteKit load or request event the wiring reads.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* The members of a SvelteKit load or request event the wiring reads. The
|
|
8
|
+
* default `Params` are string params, as SvelteKit 2 hands them; SvelteKit 3
|
|
9
|
+
* hands a param its matcher parsed as it parsed it, and `Kit.T` accepts
|
|
10
|
+
* events of any params. The server-only members are optional, since an app
|
|
11
|
+
* without a server load hands the universal one, which has none.
|
|
9
12
|
*/
|
|
10
|
-
type Event = {
|
|
13
|
+
type Event<Params extends Partial<Record<string, ParamValue>> = Partial<Record<string, string>>> = {
|
|
11
14
|
url: URL;
|
|
12
|
-
params:
|
|
15
|
+
params: Params;
|
|
13
16
|
route: {
|
|
14
17
|
id: string | null;
|
|
15
18
|
};
|
|
@@ -19,11 +22,11 @@ export declare namespace Kit {
|
|
|
19
22
|
request?: Request;
|
|
20
23
|
locals?: Record<string, any>;
|
|
21
24
|
};
|
|
22
|
-
type RequestEvent = Event & Required<Pick<Event
|
|
23
|
-
type ServerLoadEvent = RequestEvent & {
|
|
25
|
+
type RequestEvent<Params extends Partial<Record<string, ParamValue>> = Partial<Record<string, string>>> = Event<Params> & Required<Pick<Event<Params>, 'cookies' | 'request'>>;
|
|
26
|
+
type ServerLoadEvent<Params extends Partial<Record<string, ParamValue>> = Partial<Record<string, string>>> = RequestEvent<Params> & {
|
|
24
27
|
isDataRequest: boolean;
|
|
25
28
|
};
|
|
26
|
-
type UniversalLoadEvent = Event & {
|
|
29
|
+
type UniversalLoadEvent<Params extends Partial<Record<string, ParamValue>> = Partial<Record<string, string>>> = Event<Params> & {
|
|
27
30
|
data: Record<string, any> | null;
|
|
28
31
|
};
|
|
29
32
|
type Resolve = (event: any, options?: {
|
|
@@ -51,8 +54,12 @@ export declare namespace Kit {
|
|
|
51
54
|
* profile in `locals`. It is tried before `Accept-Language` (without a
|
|
52
55
|
* server load, before `navigator.languages`), and a value no configured
|
|
53
56
|
* locale matches is skipped; a custom `sanitizeLocales` is applied to it
|
|
54
|
-
* first.
|
|
55
|
-
*
|
|
57
|
+
* first. Under SvelteKit 3 a param its matcher parsed reaches the event
|
|
58
|
+
* parsed, whatever the default `Event` type says: annotate the event as
|
|
59
|
+
* `Kit.Event<Partial<Record<string, Kit.ParamValue>>>` to see it, and
|
|
60
|
+
* return a string, since a number is no locale. It runs on every
|
|
61
|
+
* navigation and every preload, so it must be pure: it reads the event
|
|
62
|
+
* and writes nothing.
|
|
56
63
|
* With a server load it runs in the browser only on a root error page
|
|
57
64
|
* rendered without the server's data (an unknown URL a static host answers
|
|
58
65
|
* with its fallback page): a navigation to a prerendered page takes the
|
|
@@ -63,22 +70,27 @@ export declare namespace Kit {
|
|
|
63
70
|
*/
|
|
64
71
|
preferredLocale?: (event: Event) => string | null | undefined;
|
|
65
72
|
};
|
|
66
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* What `defineI18n()` returns. Each member is a plain function, so it can be
|
|
75
|
+
* exported on its own. `handle` and `load` take events of `any` params: a
|
|
76
|
+
* member implemented by hand annotates its event (for `handle`,
|
|
77
|
+
* `Kit.RequestEvent`) to read them typed.
|
|
78
|
+
*/
|
|
67
79
|
type T<Instance = I18n> = {
|
|
68
80
|
/** A `handle` hook: fills `%lang%` in the `<html>` tag of `app.html` with the negotiated locale, and `%dir%` with its direction. */
|
|
69
81
|
handle: (input: {
|
|
70
|
-
event: RequestEvent
|
|
82
|
+
event: RequestEvent<Partial<Record<string, any>>>;
|
|
71
83
|
resolve: Resolve;
|
|
72
84
|
}) => Promise<Response>;
|
|
73
85
|
/** The root layout's `load`, exported from `+layout.server.js` and `+layout.js` alike. */
|
|
74
86
|
load: {
|
|
75
|
-
(event: ServerLoadEvent): Promise<{
|
|
87
|
+
(event: ServerLoadEvent<Partial<Record<string, any>>>): Promise<{
|
|
76
88
|
i18n: Payload;
|
|
77
89
|
}>;
|
|
78
|
-
<E extends UniversalLoadEvent
|
|
90
|
+
<E extends UniversalLoadEvent<Partial<Record<string, any>>>>(event: E): Promise<Omit<NonNullable<E['data']>, 'i18n'> & {
|
|
79
91
|
i18n: Instance;
|
|
80
92
|
}>;
|
|
81
|
-
(event: UniversalLoadEvent): Promise<{
|
|
93
|
+
(event: UniversalLoadEvent<Partial<Record<string, any>>>): Promise<{
|
|
82
94
|
i18n: Instance;
|
|
83
95
|
}>;
|
|
84
96
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltekit-i18n/base",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.2",
|
|
4
4
|
"description": "Base functionality of sveltekit-i18n library with a support for external message parsers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"default": "./dist/kit/env.js"
|
|
29
29
|
},
|
|
30
30
|
"#kit-server": {
|
|
31
|
-
"browser": "./dist/kit/
|
|
32
|
-
"default": "./dist/kit/
|
|
31
|
+
"browser": "./dist/kit/backend.browser.js",
|
|
32
|
+
"default": "./dist/kit/backend.js"
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|