@sveltekit-i18n/base 3.0.1 → 3.1.0-next.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 CHANGED
@@ -30,10 +30,18 @@ Core i18n functionality for SvelteKit with support for custom message parsers. T
30
30
  ✅ **TypeScript** – Locales inferred from your config, keys and payloads from a [`schema`](#schema)
31
31
  ✅ **Zero dependencies** – Lightweight and fast
32
32
 
33
+ ## Requirements
34
+
35
+ Svelte 5 or newer, and one of Node 22+, Bun 1.2+ or Deno 2+. The package is
36
+ ESM-only and imports no `node:` module, so every runtime that runs your
37
+ SvelteKit build runs it.
38
+
33
39
  ## Installation
34
40
 
35
41
  ```bash
36
42
  npm install @sveltekit-i18n/base
43
+ # bun add @sveltekit-i18n/base
44
+ # deno add npm:@sveltekit-i18n/base
37
45
  ```
38
46
 
39
47
  You'll also need a parser:
@@ -42,7 +50,8 @@ You'll also need a parser:
42
50
  # Choose one:
43
51
  npm install @sveltekit-i18n/parser-curly
44
52
  npm install @sveltekit-i18n/parser-icu
45
- # or create your own
53
+ npm install @sveltekit-i18n/parser-mf2
54
+ npm install @sveltekit-i18n/parser-i18next
46
55
  ```
47
56
 
48
57
  ## Quick Start
@@ -60,70 +69,80 @@ npm install @sveltekit-i18n/parser-icu
60
69
  ### 2. Setup with a parser
61
70
 
62
71
  ```javascript
63
- // src/lib/translations/index.js
64
- import { I18n } from '@sveltekit-i18n/base';
72
+ // src/lib/i18n.js
73
+ import { defineI18n } from '@sveltekit-i18n/base/kit';
65
74
  import parser from '@sveltekit-i18n/parser-curly';
66
75
 
67
- /** @type {import('@sveltekit-i18n/base').Config.T} */
68
- const config = {
76
+ export const config = {
69
77
  parser: parser({ onReport: null, /* other parser options */ }),
70
78
  loaders: [
71
79
  {
72
- locale: 'en',
73
- key: 'common',
74
- loader: async () => (await import('./en/common.json')).default,
75
- },
76
- {
77
- locale: 'cs',
78
- key: 'common',
79
- loader: async () => (await import('./cs/common.json')).default,
80
+ locale: ['en', 'cs'],
81
+ namespace: 'common',
82
+ loader: async ({ locale, namespace }) => (await import(`./translations/${locale}/${namespace}.json`)).default,
80
83
  },
81
84
  ],
82
85
  };
83
86
 
84
- // One reactive instance. Do NOT destructure its value properties — reading
85
- // them off the instance is what makes templates reactive. (`t`/`l` are
86
- // functions and stay reactive even when destructured, since the tracked reads
87
- // happen at call time. In a component, `const { loading } = $derived(i18n)`
88
- // destructures value reads without losing reactivity.)
89
- export const i18n = new I18n(config);
87
+ export const { handle, load, use, get } = defineI18n(config);
90
88
  ```
91
89
 
92
- ### 3. Load translations in your layout
90
+ ### 3. Wire it into SvelteKit
93
91
 
94
92
  ```javascript
95
- // src/routes/+layout.js
96
- import { i18n } from '$lib/translations';
93
+ // src/hooks.server.js
94
+ export { handle } from '$lib/i18n';
95
+ ```
97
96
 
98
- /** @type {import('./$types').LayoutLoad} */
99
- export const load = async ({ url }) => {
100
- const { pathname } = url;
101
- const initLocale = 'en';
97
+ ```javascript
98
+ // src/routes/+layout.server.js and src/routes/+layout.js — the same line in both
99
+ export { load } from '$lib/i18n';
100
+ ```
102
101
 
103
- await i18n.loadTranslations(initLocale, pathname);
102
+ ```svelte
103
+ <!-- src/routes/+layout.svelte -->
104
+ <script>
105
+ import { use } from '$lib/i18n';
104
106
 
105
- return {};
106
- };
107
+ let { data, children } = $props();
108
+
109
+ use(() => data);
110
+ </script>
111
+
112
+ {@render children()}
113
+ ```
114
+
115
+ ```html
116
+ <!-- src/app.html -->
117
+ <html lang="%lang%" dir="%dir%">
107
118
  ```
108
119
 
109
- > **Rendering per-visitor locales on the server?** The instance above is a
110
- > module-level singleton — on the server it is shared by every request in the
111
- > process, so concurrent visitors overwrite each other's locale. Use one
112
- > instance per request and hand its data to the client with `snapshot()`:
113
- > see [Server-Side Rendering](./docs/README.md#server-side-rendering).
120
+ The server picks the visitor's locale from the `Accept-Language` header (or
121
+ from a cookie, with `preferredLocale`), loads it per request and hands it to
122
+ the browser, so nothing loads twice and no visitor sees another's locale. See
123
+ [SvelteKit](./docs/README.md#sveltekit) for the details and
124
+ [Server-Side Rendering](./docs/README.md#server-side-rendering) for wiring it
125
+ by hand.
114
126
 
115
127
  ### 4. Use in components
116
128
 
117
129
  ```svelte
118
130
  <script>
119
- import { i18n } from '$lib/translations';
131
+ import { get } from '$lib/i18n';
132
+
133
+ const i18n = get();
120
134
  </script>
121
135
 
122
136
  <p>{i18n.t('common.greeting', { name: 'World' })}</p>
123
137
  ```
124
138
 
125
139
  The call reads the reactive translation table and locale, so the text updates
126
- automatically when either changes — no stores, no `$` prefix.
140
+ automatically when either changes — no stores, no `$` prefix. Do NOT
141
+ destructure the instance's value properties: reading them off the instance is
142
+ what makes templates reactive. (`t`/`l` are functions and stay reactive even
143
+ when destructured, since the tracked reads happen at call time. In a component,
144
+ `const { loading } = $derived(i18n)` destructures value reads without losing
145
+ reactivity.)
127
146
 
128
147
  ## Using Different Parsers
129
148
 
@@ -179,18 +198,47 @@ Array of loader configurations:
179
198
  loaders: [
180
199
  {
181
200
  locale: 'en', // Required: locale identifier
182
- key: 'common', // Required: translation namespace
201
+ namespace: 'common', // Required: translation namespace
183
202
  loader: async () => {}, // Required: async function returning translations
184
203
  routes: ['/about'], // Optional: load only for specific routes
185
204
  },
186
205
  ]
187
206
  ```
188
207
 
208
+ `locale` and `namespace` each take a list as well. Such a descriptor stands for one loader per locale and namespace pair, and the loader receives the pair it is loading, so one computed loader can replace a descriptor per file:
209
+
210
+ ```javascript
211
+ loaders: [
212
+ {
213
+ locale: ['en', 'cs'],
214
+ namespace: ['common', 'nav'],
215
+ loader: async ({ locale, namespace }) => (await import(`./${locale}/${namespace}.json`)).default,
216
+ },
217
+ ]
218
+ ```
219
+
220
+ A named capture group in a `RegExp` route is a load parameter: its match reaches the loader as `params`, and the loader runs again when it changes, its new data replacing the old:
221
+
222
+ ```javascript
223
+ {
224
+ locale: 'en',
225
+ namespace: 'article',
226
+ routes: [/^\/article\/(?<articleId>[^/]+)/],
227
+ loader: async ({ locale, params }) => (await fetch(`/api/articles/${params.articleId}/i18n/${locale}`)).json(),
228
+ }
229
+ ```
230
+
231
+ See [route params](./docs/README.md#route-params) for the rules.
232
+
233
+ 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`](./docs/README.md#cache-optional).
234
+
235
+ 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](./docs/README.md#loader-required).
236
+
189
237
  Both `loaders` and a loader's `routes` accept readonly arrays, so a whole-config `as const` is fine.
190
238
 
191
239
  ### `translations`
192
240
 
193
- Synchronous translations loaded immediately:
241
+ 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()`](./docs/README.md#hydrateenvelope) instead:
194
242
 
195
243
  ```javascript
196
244
  translations: {
@@ -256,7 +304,7 @@ Hand-write it for a small set of messages, or point the slot at a generated arti
256
304
 
257
305
  ### `cache`
258
306
 
259
- Time in milliseconds the loaded translations stay fresh for. By default, loaded translations never expire — loaders run once per locale and key (a loader's `routes` only decide whether a load trigger considers it, not how often it runs).
307
+ Time in milliseconds the loaded translations stay fresh for. By default, loaded translations never expire — each loader (but one with [`cache: false`](./docs/README.md#cache-optional)) runs once per locale and [route params](./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).
260
308
 
261
309
  Set a finite value when your loaders fetch from a source that can change at runtime (e.g. a CMS):
262
310
 
@@ -315,38 +363,57 @@ log: {
315
363
  - `l(locale, key, ...params)` – translate for an explicit locale
316
364
  - `locale` – the ACTIVE locale; assignment is a fire-and-forget `setLocale()`
317
365
  - `locales` – available locales
318
- - `loading` – `true` while any load is in flight
366
+ - `loading` – `true` while any activating load is in flight; a `{ activate: false }` load counts only once an activating trigger joins it
319
367
  - `initialized` – locale and route set, translations present
320
368
  - `translations` / `rawTranslations` – the (pre/post-preprocess) tables
321
369
 
322
370
  ### Methods
323
371
 
324
- Load-triggering methods return the promise of the matching load — concurrent duplicate triggers share one in-flight load (and its promise) instead of fetching twice.
372
+ 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.
325
373
 
326
- - `loadTranslations(locale, route?)` – load translations for locale and route; `route` defaults to the current one
374
+ - `loadTranslations(locale, route?, options?)` – load translations for locale and route; `route` defaults to the current one, and `{ activate: false }` only fills the tables without switching to them
375
+ - `loadNamespace(namespace, locale?)` – load one namespace on demand, whatever its loaders' routes, without switching to it; it stays loaded across routes
327
376
  - `setLocale(locale)` – request a locale; loads once a route is known
328
377
  - `setRoute(route)` – update the current route
329
378
  - `loadConfig(config)` – (re)configure the instance
330
- - `addTranslations(translations)` – add synchronous translations
331
- - `snapshot()` – serialize the active locale (and the fallback) for the current route, shaped like `config.translations` so the receiving instance hydrates by passing it to `addTranslations()`
332
- - `invalidate(locale?)` – mark loaded translations stale (one locale, or all); loaders run again on the next load trigger, and a load still in flight for an invalidated locale settles with its data discarded
379
+ - `addTranslations(translations)` – seed synchronous translations; the loaders of their namespaces still run and merge into them
380
+ - `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 })`
381
+ - `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
382
+ - `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
333
383
  - `destroy()` – detach a per-request or per-component instance: in-flight loads settle discarded, further load and mutation calls are ignored, reads keep working
334
384
 
335
385
  ### Utilities
336
386
 
337
- Two helpers the instance uses internally ship from a separate subpath, for code that has to match the library's own behavior:
387
+ Pure helpers ship from a separate subpath, for the code around the instance that has to match the library's own behavior or decide which locale to ask for:
338
388
 
339
389
  ```javascript
340
- import { sanitizeLocales, toDotNotation } from '@sveltekit-i18n/base/utils';
390
+ import { matchLocale, resolveLoaders, sanitizeLocales, textDirection, toDotNotation } from '@sveltekit-i18n/base/utils';
341
391
  ```
342
392
 
343
393
  - `toDotNotation(input, preserveArrays?)` – the flattening behind [`preprocess`](#preprocess), for a custom `preprocess` that still wants dot notation
394
+ - `resolveLoaders(loaders, sanitizeLocales?)` – normalizes `config.loaders` the way the instance does, into one loader per locale and namespace pair, for code that reads a config from outside the instance
344
395
  - `sanitizeLocales(...locales)` – normalizes a locale from a URL, cookie or `Accept-Language` header the way the instance does, so it can be compared against `locale`
396
+ - `matchLocale(requested, available)` – picks the configured locale a visitor asked for, from an `Accept-Language` header or `navigator.languages`, falling back from `en-GB` to `en` and answering `undefined` when nothing matches
397
+ - `textDirection(locale)` – `'ltr'` or `'rtl'` for a `dir` attribute, from the script the tag spells or the one `Intl.Locale#maximize()` adds, with no list of languages to keep
398
+
399
+ ### SvelteKit
400
+
401
+ ```javascript
402
+ import { defineI18n } from '@sveltekit-i18n/base/kit';
403
+
404
+ export const { handle, load, use, get } = defineI18n(config, { preferredLocale });
405
+ ```
406
+
407
+ - `handle` – the `hooks.server.js` hook; fills `%lang%` and `%dir%` in `app.html`'s `<html>` tag
408
+ - `load` – the root layout's `load`, exported from `+layout.server.js` and `+layout.js` alike: negotiates the locale, loads it on the server per request and hands it to the one instance a browser tab keeps
409
+ - `use(() => data)` – called once in the root `+layout.svelte`; provides the instance, follows every navigation and keeps `<html lang>` and `<html dir>` in sync
410
+ - `get()` – the instance, in any component below the root layout
345
411
 
346
412
  Full API documentation: [docs/README.md](./docs/README.md)
347
413
 
348
414
  ## Documentation
349
415
 
416
+ - 🌐 [sveltekit-i18n.github.io](https://sveltekit-i18n.github.io) – The documentation site, with a live playground
350
417
  - 📖 [Full API Documentation](./docs/README.md) – Complete reference
351
418
  - 📚 [Main Library Docs](https://github.com/sveltekit-i18n/lib/tree/master/docs/INDEX.md) – Guides, tutorials, and best practices
352
419
  - 🎨 [Parsers](https://github.com/sveltekit-i18n/parsers) – Available parsers and how to create your own
@@ -382,8 +449,10 @@ The locales survive only when the config reaches the constructor as a literal
382
449
  ## Related Packages
383
450
 
384
451
  - [sveltekit-i18n](https://github.com/sveltekit-i18n/lib) – Complete solution, with the Curly Message Format parser included
385
- - [@sveltekit-i18n/parser-curly](https://github.com/sveltekit-i18n/parsers/tree/master/parser-curly) – [Curly Message Format](https://github.com/curly-message/spec) parser
452
+ - [@sveltekit-i18n/parser-curly](https://github.com/sveltekit-i18n/parsers/tree/master/parser-curly) – [Curly Message Format](https://curlymessage.dev) parser
386
453
  - [@sveltekit-i18n/parser-icu](https://github.com/sveltekit-i18n/parsers/tree/master/parser-icu) – ICU message format parser
454
+ - [@sveltekit-i18n/parser-mf2](https://github.com/sveltekit-i18n/parsers/tree/master/parser-mf2) – [Unicode MessageFormat 2](https://unicode.org/reports/tr35/tr35-messageFormat.html) parser
455
+ - [@sveltekit-i18n/parser-i18next](https://github.com/sveltekit-i18n/parsers/tree/master/parser-i18next) – [i18next](https://www.i18next.com) interpolation and formatting syntax parser
387
456
  - [Extensions](https://github.com/sveltekit-i18n/extensions) – Official extensions for the `config.extensions` pipe
388
457
 
389
458
  ## Contributing
@@ -396,6 +465,11 @@ For issues specific to base functionality, create a ticket [here](https://github
396
465
 
397
466
  See [Releases](https://github.com/sveltekit-i18n/base/releases) for version history.
398
467
 
468
+ ## Sponsor
469
+
470
+ You can support the maintenance of this package through
471
+ [GitHub Sponsors](https://github.com/sponsors/sveltekit-i18n).
472
+
399
473
  ## License
400
474
 
401
475
  MIT
@@ -1,11 +1,13 @@
1
- import type { Config, Extension, Parser, Schema, Translations } from './types.js';
1
+ import type { Config, Extension, Loader, Parser, Schema, Snapshot, Translations } from './types.js';
2
2
  declare class I18nCore<ParserParams extends Parser.Params = any, ParserOutput = string, TranslationSchema = never, LocaleUnion extends string = string> {
3
3
  #private;
4
4
  constructor(config?: Config.T<ParserParams, ParserOutput>);
5
5
  /**
6
6
  * The active locale. Reading it is reactive; assigning it is a shorthand for
7
7
  * a fire-and-forget `setLocale()` — the value therefore updates once the
8
- * locale's translations resolved, not synchronously on assignment.
8
+ * locale's translations resolved, not synchronously on assignment. It does
9
+ * not advance when a loader throws SvelteKit's `redirect()` or an `error()`
10
+ * below 500, which an assignment only logs.
9
11
  */
10
12
  get locale(): Config.LocaleInput<LocaleUnion> | undefined;
11
13
  set locale(value: Config.LocaleInput<LocaleUnion> | undefined);
@@ -25,43 +27,114 @@ declare class I18nCore<ParserParams extends Parser.Params = any, ParserOutput =
25
27
  /** Like `t`, for an explicit locale. */
26
28
  l: Translations.LocalTranslationFunction<ParserParams, ParserOutput, TranslationSchema, LocaleUnion>;
27
29
  /**
28
- * Public entry for (re)configuration. The failure is reported here and the
29
- * promise marked handled, so a fire-and-forget call cannot become an
30
- * unhandled rejection; an awaiting caller still receives it.
30
+ * Public entry for (re)configuration. It returns the promise of the
31
+ * `initLocale` load, which reports its own failure; a config that fails to
32
+ * apply is reported here. Either way the promise is marked handled, so a
33
+ * fire-and-forget call cannot become an unhandled rejection; an awaiting
34
+ * caller still receives it.
31
35
  */
32
36
  loadConfig: (config: Config.T<ParserParams, ParserOutput>) => Promise<void>;
33
37
  setLocale: (locale?: Config.LocaleInput<LocaleUnion>) => Promise<void>;
34
- setRoute: (route: string) => Promise<void>;
35
- loadTranslations: (locale: Config.LocaleInput<LocaleUnion>, route?: string) => Promise<void>;
38
+ setRoute: (input: string) => Promise<void>;
36
39
  /**
37
- * Marks loaded translations stale — for one locale, or all of them. Loaders
38
- * run again on the NEXT load trigger; the call itself starts no load and
39
- * keeps the currently displayed translations in place. A load still in
40
- * flight for an invalidated locale is severed: it settles, but its data is
41
- * discarded — it predates the invalidation.
40
+ * `{ activate: false }` only fills the tables: it leaves the requested
41
+ * locale, the route and `locale` untouched and does not count towards
42
+ * `loading` — what is rendered does not change: data of a loader whose route
43
+ * params differ from the ones the current route asks for is kept aside, the
44
+ * latest per loader, and the activating trigger that asks for them applies
45
+ * it. It
46
+ * leaves `cache` expiry to the next activating trigger. A loader's
47
+ * `redirect()` or `error()` below 500 rejects it all the same.
42
48
  */
43
- invalidate: (locale?: Config.LocaleInput<LocaleUnion>) => void;
49
+ loadTranslations: (locale: Config.LocaleInput<LocaleUnion>, route?: string, { activate }?: {
50
+ activate?: boolean;
51
+ }) => Promise<void>;
52
+ /**
53
+ * Loads one namespace for the active locale (or `locale`), whatever the
54
+ * routes of its loaders say — for what an interaction needs rather than a
55
+ * route: a modal, a panel, an editor. Warm, like `{ activate: false }`: it
56
+ * changes neither the locale nor `loading`, and it leaves `cache` expiry to
57
+ * the next activating trigger. It honours the load records, so calling it
58
+ * on every interaction fetches once — a loader with `cache: false` runs each
59
+ * time on its routes — and what it loads stays loaded across routes. A
60
+ * loader's `redirect()` or `error()` below 500 rejects it.
61
+ */
62
+ loadNamespace: (namespace: Loader.Key, locale?: Config.LocaleInput<LocaleUnion>) => Promise<void>;
63
+ /**
64
+ * Marks loaded translations stale — for one locale or all of them, and for
65
+ * one namespace or all of them. Loaders run again on the NEXT load trigger;
66
+ * the call itself starts no load and keeps the currently displayed
67
+ * translations in place. A loader still in flight for what was invalidated
68
+ * is severed: its load settles, but what it returns or throws is discarded —
69
+ * it predates the invalidation — and an activating trigger fetches it again,
70
+ * once, before its locale activates. It leaves it to the next trigger when
71
+ * another loader of its load threw SvelteKit's control flow that still
72
+ * counts, which rejects the trigger, and when the refetch is severed too. A
73
+ * namespace invalidation leaves the locale's `cache` window where it was.
74
+ */
75
+ invalidate: (locale?: Config.LocaleInput<LocaleUnion>, namespace?: Loader.Key) => void;
44
76
  addTranslations: (translations?: Translations.SerializedTranslations) => void;
77
+ /**
78
+ * Restores the state `snapshot({ records: true })` captured on another
79
+ * instance: its data, its load records, the active locale and the route.
80
+ * A loader named by a record does not run again for the same params — one
81
+ * with `cache: false` only for the pass the envelope arrived with; data no
82
+ * record names is displayed but keeps no loader from running. An envelope
83
+ * without `records` is a plain hand-off instead: every namespace its data
84
+ * names keeps its loaders without params from running, and holds one with
85
+ * `cache: false` back for that pass. Nothing
86
+ * happens for `undefined`, so a load whose server half sent nothing can call
87
+ * it unconditionally.
88
+ */
89
+ hydrate: (envelope?: Snapshot.Envelope) => void;
45
90
  /**
46
91
  * Serializes what this instance holds for the active locale and the fallback
47
- * locale, narrowed to the current route: a key owned only by loaders that do
48
- * not match the route is left out. The result is shaped like
49
- * `config.translations`, so a client hydrates by passing it to
50
- * `addTranslations()` — the bookkeeping derived from it then keeps the
51
- * matching loaders from fetching the same data again. Apply it to the
52
- * instance rather than assigning it to `config.translations`: the payload is
53
- * a subset — two locales, and nothing of a key its loaders claim for another
54
- * route — so assigning it would drop the rest of the config's own data.
55
- * A literal `__proto__` key is left out: the serializer SvelteKit hands load
56
- * data to refuses an object that carries one.
92
+ * locale. The result is shaped like `config.translations`, and a client
93
+ * hands it over with `hydrate({ translations })`: a plain hand-off, whose
94
+ * namespace records keep the matching loaders without params from fetching
95
+ * it again and hold one with `cache: false` back for that pass. Passed to
96
+ * `addTranslations()` or assigned to `config.translations` it only seeds,
97
+ * and every loader runs again.
98
+ * A namespace plain data cannot hand over is left out, for the client to
99
+ * load: one fed by several loaders, whose record would suppress a part the
100
+ * payload lacks; one whose loader's routes can capture params, whose data a
101
+ * plain hand-off keeps as data no loader delivered, so the next params could
102
+ * not replace it; and one none of whose loaders delivered here and no
103
+ * hand-off named, whose seeded data would keep the client's loaders from
104
+ * ever running.
105
+ * A literal `__proto__` key is left out too, and with records its
106
+ * namespace's loaders are, and a namespace whose loader captures params,
107
+ * without them a namespace a loader serves, so the client loads it whole: the serializer SvelteKit hands load data to refuses an
108
+ * object that carries one. A locale
109
+ * named `__proto__` is left out altogether.
110
+ *
111
+ * `{ records: true }` returns an envelope for `hydrate()` instead: the same
112
+ * data, the loaders that delivered it, the active locale and the route. The
113
+ * records name each loader, so a namespace fed by several loaders is handed
114
+ * over too, and so is one a loader delivered for route params while its
115
+ * record says so — not a namespace with both, whose data the client could
116
+ * not split between them. What was seeded into the namespace of a loader
117
+ * whose routes capture params travels apart as `seeds`, so it outlives new
118
+ * params there, and reaches the client where the namespace is left out.
57
119
  */
58
- snapshot: () => Translations.SerializedTranslations;
120
+ snapshot: {
121
+ (options?: {
122
+ records?: false;
123
+ }): Translations.SerializedTranslations;
124
+ (options: {
125
+ records: true;
126
+ }): Snapshot.Envelope;
127
+ (options?: {
128
+ records?: boolean;
129
+ }): Translations.SerializedTranslations | Snapshot.Envelope;
130
+ };
59
131
  /**
60
132
  * Detaches the instance from its loading lifecycle: in-flight loads settle
61
- * with their data discarded, `loading` drops to `false`, and every further
62
- * load or mutation call is ignored with a warning. Reads (`t`, `l`, `locale`,
63
- * `translations`, `snapshot`) keep working, so a component still tearing down
64
- * renders its last state instead of breaking. Idempotent.
133
+ * with whatever their loaders return or throw discarded, `loading` drops to
134
+ * `false`, and every further load or mutation call is ignored with a warning.
135
+ * Reads (`t`, `l`, `locale`, `translations`, `snapshot`) keep working, so a
136
+ * component still tearing down renders its last state instead of breaking.
137
+ * Idempotent.
65
138
  */
66
139
  destroy: () => void;
67
140
  }