@sveltekit-i18n/base 3.0.0 → 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 +122 -48
- package/dist/I18n.svelte.d.ts +101 -23
- package/dist/I18n.svelte.js +1127 -237
- package/dist/exports/kit.d.ts +2 -0
- package/dist/exports/kit.js +1 -0
- package/dist/exports/utils.d.ts +1 -1
- package/dist/exports/utils.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/kit/define.svelte.d.ts +9 -0
- package/dist/kit/define.svelte.js +178 -0
- package/dist/kit/env.browser.d.ts +1 -0
- package/dist/kit/env.browser.js +1 -0
- package/dist/kit/env.d.ts +1 -0
- package/dist/kit/env.js +1 -0
- package/dist/kit/internal.d.ts +16 -0
- package/dist/kit/internal.js +1 -0
- package/dist/kit/server.browser.d.ts +2 -0
- package/dist/kit/server.browser.js +6 -0
- package/dist/kit/server.d.ts +2 -0
- package/dist/kit/server.js +72 -0
- package/dist/kit/types.d.ts +83 -0
- package/dist/kit/types.js +1 -0
- package/dist/types.d.ts +167 -22
- package/dist/utils.d.ts +82 -3
- package/dist/utils.js +452 -31
- package/package.json +23 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { defineI18n } from '../kit/define.svelte.js';
|
package/dist/exports/utils.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { sanitizeLocales, toDotNotation } from '../utils.js';
|
|
1
|
+
export { matchLocale, resolveLoaders, sanitizeLocales, textDirection, toDotNotation } from '../utils.js';
|
|
2
2
|
export type { DotNotation } from '../types.js';
|
package/dist/exports/utils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { sanitizeLocales, toDotNotation } from '../utils.js';
|
|
1
|
+
export { matchLocale, resolveLoaders, sanitizeLocales, textDirection, toDotNotation } from '../utils.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { default, I18n } from './I18n.svelte.js';
|
|
2
|
-
export type { Config, Extension, Loader, Logger, Parser, Schema, Translations } from './types.js';
|
|
2
|
+
export type { Config, Extension, Loader, Logger, Parser, Schema, Snapshot, Translations } from './types.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { I18n } from '../I18n.svelte.js';
|
|
2
|
+
import type { Config } from '../types.js';
|
|
3
|
+
import type { Kit } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Wires SvelteKit to an instance of `config`: a `handle` hook, the root
|
|
6
|
+
* layout's `load`, and `use()` / `get()` for components. The server builds an
|
|
7
|
+
* instance per request; the browser keeps one per tab.
|
|
8
|
+
*/
|
|
9
|
+
export declare const defineI18n: <const C extends Config.T<any, any> = Config.T<any, any>>(config: C, options?: Kit.Options) => Kit.T<InstanceType<typeof I18n<C>>>;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { getContext, setContext, untrack } from 'svelte';
|
|
2
|
+
import { BROWSER } from '#kit-env';
|
|
3
|
+
import { serverHalf } from '#kit-server';
|
|
4
|
+
import { I18n } from '../I18n.svelte.js';
|
|
5
|
+
import { logError, loggerFactory, setLogger } from '../logger.js';
|
|
6
|
+
import { configLocales, matchLocale, sanitizerFactory, textDirection } from '../utils.js';
|
|
7
|
+
// Registry-wide, so two copies of this package meet: the context key, and the
|
|
8
|
+
// key of the pass the universal branch hands `use()` in `data`.
|
|
9
|
+
const KEY = Symbol.for('@sveltekit-i18n/base/kit');
|
|
10
|
+
const passOf = (data) => data?.[KEY];
|
|
11
|
+
const isServerEvent = (event) => 'cookies' in event;
|
|
12
|
+
/**
|
|
13
|
+
* Wires SvelteKit to an instance of `config`: a `handle` hook, the root
|
|
14
|
+
* layout's `load`, and `use()` / `get()` for components. The server builds an
|
|
15
|
+
* instance per request; the browser keeps one per tab.
|
|
16
|
+
*/
|
|
17
|
+
export const defineI18n = (config, options = {}) => {
|
|
18
|
+
// The constructor would start an `initLocale` load of its own, next to the
|
|
19
|
+
// negotiated one; here `initLocale` is a negotiation candidate instead. The
|
|
20
|
+
// wiring drives the core itself, whatever the extensions make of it.
|
|
21
|
+
const create = () => new I18n({ ...config, initLocale: undefined, extensions: undefined });
|
|
22
|
+
const pipe = (i18n) => (config.extensions ?? []).reduce((acc, extension) => extension(acc), i18n);
|
|
23
|
+
const sanitize = sanitizerFactory(config.sanitizeLocales);
|
|
24
|
+
const sanitized = (locale) => (locale ? sanitize(locale)[0] : undefined);
|
|
25
|
+
let configured;
|
|
26
|
+
// `initLocale` and `fallbackLocale`, spelled as the config's locales are and
|
|
27
|
+
// so sanitized alike.
|
|
28
|
+
let defaults = [];
|
|
29
|
+
// Resolved on first use, never at import, and once: resolving the loaders
|
|
30
|
+
// and sanitizing reports what is wrong with them.
|
|
31
|
+
const locales = () => {
|
|
32
|
+
if (configured)
|
|
33
|
+
return configured;
|
|
34
|
+
if (config.log)
|
|
35
|
+
setLogger(loggerFactory(config.log));
|
|
36
|
+
try {
|
|
37
|
+
configured = configLocales(config);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// The instance reports a malformed config itself.
|
|
41
|
+
configured = [];
|
|
42
|
+
}
|
|
43
|
+
defaults = [sanitized(config.initLocale), sanitized(config.fallbackLocale)];
|
|
44
|
+
return configured;
|
|
45
|
+
};
|
|
46
|
+
let reported = false;
|
|
47
|
+
const preferred = (event) => {
|
|
48
|
+
try {
|
|
49
|
+
return options.preferredLocale?.(event);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (!reported)
|
|
53
|
+
logError('`preferredLocale` failed. Negotiating without it.', error);
|
|
54
|
+
reported = true;
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
// What `preferredLocale` returns is the visitor's, so it goes through a
|
|
59
|
+
// custom sanitizer silently — a value it rejects is matched as it is — and
|
|
60
|
+
// never through the default one, which warns on every tag `Intl` does not
|
|
61
|
+
// know: either would turn a visitor's cookie into a report per request.
|
|
62
|
+
const visitorSanitized = (locale) => {
|
|
63
|
+
const { sanitizeLocales: custom } = config;
|
|
64
|
+
if (!locale || typeof custom !== 'function')
|
|
65
|
+
return locale;
|
|
66
|
+
try {
|
|
67
|
+
const result = custom(`${locale}`);
|
|
68
|
+
return result ? `${result}` : locale;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return locale;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const negotiate = (event, ranges) => {
|
|
75
|
+
// First: it sets the config's logger, which `preferred` reports through.
|
|
76
|
+
const available = locales();
|
|
77
|
+
return [visitorSanitized(preferred(event)), ranges, ...defaults].reduce((found, candidate) => found ?? matchLocale(candidate, available), undefined);
|
|
78
|
+
};
|
|
79
|
+
const server = serverHalf({ create, negotiate, locales, basePath: config.basePath });
|
|
80
|
+
// Browser only: the tab's instance, the server's answer at the last commit,
|
|
81
|
+
// and the locale that commit is switching to with the one it switches from,
|
|
82
|
+
// which only `use()` writes. A server keeps nothing between requests.
|
|
83
|
+
const tab = { committed: false };
|
|
84
|
+
// The locale the tab shows once the wiring's own switch lands: that switch
|
|
85
|
+
// is no client change, while a locale that moved from where it started is.
|
|
86
|
+
const heading = (i18n) => {
|
|
87
|
+
const active = untrack(() => i18n.locale);
|
|
88
|
+
return tab.switching && tab.switching.from === active ? tab.switching.to : active;
|
|
89
|
+
};
|
|
90
|
+
const universalLoad = async (event) => {
|
|
91
|
+
const route = event.url.pathname;
|
|
92
|
+
const payload = event.data?.i18n;
|
|
93
|
+
const fresh = !BROWSER || !tab.i18n;
|
|
94
|
+
const i18n = fresh ? create() : tab.i18n;
|
|
95
|
+
const surface = fresh ? pipe(i18n) : tab.surface;
|
|
96
|
+
const seen = heading(i18n);
|
|
97
|
+
// A live server sends the tables on a page render only, so a later pass
|
|
98
|
+
// that carries them read a prerendered file, whose locale was negotiated
|
|
99
|
+
// at build time, without the visitor. Node and Deno define
|
|
100
|
+
// `navigator.languages` too, from the server's own environment.
|
|
101
|
+
const answer = !fresh && payload?.translations
|
|
102
|
+
? tab.answer
|
|
103
|
+
: payload ? payload.locale : negotiate(event, BROWSER ? navigator.languages : undefined);
|
|
104
|
+
if (BROWSER)
|
|
105
|
+
Object.assign(tab, { i18n, surface });
|
|
106
|
+
if (fresh) {
|
|
107
|
+
if (payload?.translations)
|
|
108
|
+
i18n.hydrate({ ...payload, translations: payload.translations });
|
|
109
|
+
// No preload runs before the first navigation completes, so the pass
|
|
110
|
+
// that builds the instance may activate it.
|
|
111
|
+
await (answer ? i18n.loadTranslations(answer, route) : i18n.setRoute(route));
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
// Warm only: this pass may be a preload, which must not change what is
|
|
115
|
+
// shown. The commit switches to a changed answer, or else stays.
|
|
116
|
+
const target = (answer !== tab.answer ? answer : undefined) ?? heading(i18n);
|
|
117
|
+
if (target)
|
|
118
|
+
await i18n.loadTranslations(target, route, { activate: false });
|
|
119
|
+
}
|
|
120
|
+
const pass = { i18n, surface, locale: answer, route, seen };
|
|
121
|
+
return { ...event.data, i18n: surface, [KEY]: pass };
|
|
122
|
+
};
|
|
123
|
+
const load = ((event) => (isServerEvent(event) ? server.load(event) : universalLoad(event)));
|
|
124
|
+
const use = (data) => {
|
|
125
|
+
const first = passOf(data());
|
|
126
|
+
if (!first)
|
|
127
|
+
throw new Error('[i18n]: `use()` found no data from `load`. Export `load` from the root `+layout.js`.');
|
|
128
|
+
const { i18n, surface } = first;
|
|
129
|
+
setContext(KEY, surface);
|
|
130
|
+
// `data` moves only when a navigation commits; a preload leaves it. The
|
|
131
|
+
// answer is compared with the last commit's, so a client `setLocale()`
|
|
132
|
+
// stands until the server answers differently, and an answer given before
|
|
133
|
+
// the active locale changed is stale.
|
|
134
|
+
$effect.pre(() => {
|
|
135
|
+
const pass = passOf(data());
|
|
136
|
+
if (!pass)
|
|
137
|
+
return;
|
|
138
|
+
if (!tab.committed || (pass.locale !== tab.answer && heading(pass.i18n) === pass.seen)) {
|
|
139
|
+
const { locale } = pass;
|
|
140
|
+
const previous = tab.answer;
|
|
141
|
+
tab.committed = true;
|
|
142
|
+
tab.answer = locale;
|
|
143
|
+
if (locale !== undefined) {
|
|
144
|
+
const switching = { from: untrack(() => pass.i18n.locale), to: locale };
|
|
145
|
+
const done = () => {
|
|
146
|
+
if (tab.switching === switching)
|
|
147
|
+
tab.switching = undefined;
|
|
148
|
+
};
|
|
149
|
+
tab.switching = switching;
|
|
150
|
+
// A switch that failed, and that no later call landed either, leaves
|
|
151
|
+
// the answer to the next commit.
|
|
152
|
+
pass.i18n.loadTranslations(locale, pass.route).then(done, () => {
|
|
153
|
+
done();
|
|
154
|
+
if (tab.answer === locale && untrack(() => pass.i18n.locale) !== locale)
|
|
155
|
+
tab.answer = previous;
|
|
156
|
+
});
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
void pass.i18n.setRoute(pass.route);
|
|
161
|
+
});
|
|
162
|
+
$effect(() => {
|
|
163
|
+
const { locale } = i18n;
|
|
164
|
+
if (!locale)
|
|
165
|
+
return;
|
|
166
|
+
document.documentElement.lang = locale;
|
|
167
|
+
document.documentElement.dir = textDirection(locale);
|
|
168
|
+
});
|
|
169
|
+
return surface;
|
|
170
|
+
};
|
|
171
|
+
const get = () => {
|
|
172
|
+
const surface = getContext(KEY);
|
|
173
|
+
if (!surface)
|
|
174
|
+
throw new Error('[i18n]: `get()` found no instance. Call `use(() => data)` in the root `+layout.svelte`.');
|
|
175
|
+
return surface;
|
|
176
|
+
};
|
|
177
|
+
return { handle: server.handle, load, use, get };
|
|
178
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BROWSER: boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const BROWSER = true;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BROWSER: boolean;
|
package/dist/kit/env.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const BROWSER = false;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { I18n } from '../I18n.svelte.js';
|
|
2
|
+
import type { Kit } from './types.js';
|
|
3
|
+
/** What the server half needs from the factory. */
|
|
4
|
+
export type Shared = {
|
|
5
|
+
create: () => I18n;
|
|
6
|
+
negotiate: (event: Kit.Event, ranges: string | readonly string[] | null | undefined) => string | undefined;
|
|
7
|
+
/** The locales the config serves. */
|
|
8
|
+
locales: () => string[];
|
|
9
|
+
basePath: string | undefined;
|
|
10
|
+
};
|
|
11
|
+
export type ServerHalf = {
|
|
12
|
+
handle: Kit.T['handle'];
|
|
13
|
+
load: (event: Kit.ServerLoadEvent) => Promise<{
|
|
14
|
+
i18n: Kit.Payload;
|
|
15
|
+
}>;
|
|
16
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
const serverOnly = () => {
|
|
2
|
+
throw new Error('[i18n]: `handle` and the server branch of `load` run on the server only.');
|
|
3
|
+
};
|
|
4
|
+
// What `#kit-server` resolves to under the `browser` condition: the browser
|
|
5
|
+
// bundle carries this instead of the server half.
|
|
6
|
+
export const serverHalf = () => ({ handle: serverOnly, load: serverOnly });
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { logger } from '../logger.js';
|
|
2
|
+
import { matchLocale, routePrefix, textDirection, withoutBasePath } from '../utils.js';
|
|
3
|
+
export const serverHalf = ({ create, negotiate, locales, basePath }) => {
|
|
4
|
+
const answer = (event) => negotiate(event, event.request.headers.get('accept-language'));
|
|
5
|
+
let warned = false;
|
|
6
|
+
// A base path SvelteKit strips and `basePath` does not keeps every
|
|
7
|
+
// route-scoped loader from matching, silently. Here, on the server only, so
|
|
8
|
+
// the matcher stays out of the browser bundle.
|
|
9
|
+
const check = (event) => {
|
|
10
|
+
if (warned)
|
|
11
|
+
return;
|
|
12
|
+
const available = locales();
|
|
13
|
+
const found = routePrefix(event.url.pathname, event.route.id);
|
|
14
|
+
if (!found)
|
|
15
|
+
return;
|
|
16
|
+
const segments = found.split('/');
|
|
17
|
+
const last = segments[segments.length - 1].toLowerCase();
|
|
18
|
+
// A locale segment in front of the route is a `reroute` that strips it,
|
|
19
|
+
// spelled in the URL as a language (`en`) or a region (`en-gb`) of one.
|
|
20
|
+
const isLocale = matchLocale(last, available) !== undefined;
|
|
21
|
+
const prefix = isLocale ? segments.slice(0, -1).join('/') : found;
|
|
22
|
+
if (!prefix || withoutBasePath(prefix, basePath) === '/')
|
|
23
|
+
return;
|
|
24
|
+
warned = true;
|
|
25
|
+
logger.warn(`'${prefix}' precedes the route SvelteKit matched. If it is kit.paths.base, set basePath: '${prefix}'.`);
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
handle: ({ event, resolve }) => {
|
|
29
|
+
let lang;
|
|
30
|
+
// Negotiated only for a chunk that asks for it, so a data request never
|
|
31
|
+
// negotiates here; a function replacement is inserted as it is.
|
|
32
|
+
const negotiated = () => {
|
|
33
|
+
if (lang === undefined) {
|
|
34
|
+
check(event);
|
|
35
|
+
lang = answer(event) ?? '';
|
|
36
|
+
}
|
|
37
|
+
return lang;
|
|
38
|
+
};
|
|
39
|
+
let filled = false;
|
|
40
|
+
// Only the `<html>` start tag is filled: the template writes it, while
|
|
41
|
+
// the head and the body carry the app's content, where a placeholder
|
|
42
|
+
// stays as it is written.
|
|
43
|
+
return Promise.resolve(resolve(event, {
|
|
44
|
+
transformPageChunk: ({ html }) => {
|
|
45
|
+
if (filled)
|
|
46
|
+
return html;
|
|
47
|
+
filled = true;
|
|
48
|
+
const start = html.search(/<html[\s>]/i);
|
|
49
|
+
const end = start === -1 ? -1 : html.indexOf('>', start) + 1;
|
|
50
|
+
if (end < 1)
|
|
51
|
+
return html;
|
|
52
|
+
const tag = html.slice(start, end)
|
|
53
|
+
.replaceAll('%lang%', negotiated)
|
|
54
|
+
.replaceAll('%dir%', () => textDirection(negotiated()));
|
|
55
|
+
return html.slice(0, start) + tag + html.slice(end);
|
|
56
|
+
},
|
|
57
|
+
}));
|
|
58
|
+
},
|
|
59
|
+
load: async (event) => {
|
|
60
|
+
// Read before anything returns: SvelteKit re-runs a load on a
|
|
61
|
+
// navigation only for what it read.
|
|
62
|
+
const route = event.url.pathname;
|
|
63
|
+
check(event);
|
|
64
|
+
const locale = answer(event);
|
|
65
|
+
if (event.isDataRequest)
|
|
66
|
+
return { i18n: { locale, route: withoutBasePath(route, basePath) } };
|
|
67
|
+
const i18n = create();
|
|
68
|
+
await (locale ? i18n.loadTranslations(locale, route) : i18n.setRoute(route));
|
|
69
|
+
return { i18n: i18n.snapshot({ records: true }) };
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { I18n } from '../I18n.svelte.js';
|
|
2
|
+
import type { Snapshot } from '../types.js';
|
|
3
|
+
export declare namespace Kit {
|
|
4
|
+
/**
|
|
5
|
+
* The members of a SvelteKit load or request event the wiring reads.
|
|
6
|
+
* SvelteKit's own event types are assignable to it. The server-only members
|
|
7
|
+
* are optional, since an app without a server load hands the universal one,
|
|
8
|
+
* which has none.
|
|
9
|
+
*/
|
|
10
|
+
type Event = {
|
|
11
|
+
url: URL;
|
|
12
|
+
params: Partial<Record<string, string>>;
|
|
13
|
+
route: {
|
|
14
|
+
id: string | null;
|
|
15
|
+
};
|
|
16
|
+
cookies?: {
|
|
17
|
+
get: (name: string) => string | undefined;
|
|
18
|
+
};
|
|
19
|
+
request?: Request;
|
|
20
|
+
locals?: Record<string, any>;
|
|
21
|
+
};
|
|
22
|
+
type RequestEvent = Event & Required<Pick<Event, 'cookies' | 'request'>>;
|
|
23
|
+
type ServerLoadEvent = RequestEvent & {
|
|
24
|
+
isDataRequest: boolean;
|
|
25
|
+
};
|
|
26
|
+
type UniversalLoadEvent = Event & {
|
|
27
|
+
data: Record<string, any> | null;
|
|
28
|
+
};
|
|
29
|
+
type Resolve = (event: any, options?: {
|
|
30
|
+
transformPageChunk?: (input: {
|
|
31
|
+
html: string;
|
|
32
|
+
done: boolean;
|
|
33
|
+
}) => string | undefined;
|
|
34
|
+
}) => Response | Promise<Response>;
|
|
35
|
+
/**
|
|
36
|
+
* What the server branch of `load` returns under `i18n`: the negotiated
|
|
37
|
+
* locale and the route always, the tables and their records on a page
|
|
38
|
+
* render only. Plain data, for `devalue`.
|
|
39
|
+
*/
|
|
40
|
+
type Payload = Omit<Snapshot.Envelope, 'translations'> & Partial<Pick<Snapshot.Envelope, 'translations'>>;
|
|
41
|
+
type Options = {
|
|
42
|
+
/**
|
|
43
|
+
* The visitor's choice, read from the event: a cookie, a route param, a
|
|
44
|
+
* profile in `locals`. It is tried before `Accept-Language` (without a
|
|
45
|
+
* server load, before `navigator.languages`), and a value no configured
|
|
46
|
+
* locale matches is skipped; a custom `sanitizeLocales` is applied to it
|
|
47
|
+
* first. It runs on every navigation and every
|
|
48
|
+
* preload, so it must be pure: it reads the event and writes nothing.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* preferredLocale: (event) => event.cookies?.get('lang')
|
|
52
|
+
*/
|
|
53
|
+
preferredLocale?: (event: Event) => string | null | undefined;
|
|
54
|
+
};
|
|
55
|
+
/** What `defineI18n()` returns. Each member is a plain function, so it can be exported on its own. */
|
|
56
|
+
type T<Instance = I18n> = {
|
|
57
|
+
/** A `handle` hook: fills `%lang%` in the `<html>` tag of `app.html` with the negotiated locale, and `%dir%` with its direction. */
|
|
58
|
+
handle: (input: {
|
|
59
|
+
event: RequestEvent;
|
|
60
|
+
resolve: Resolve;
|
|
61
|
+
}) => Promise<Response>;
|
|
62
|
+
/** The root layout's `load`, exported from `+layout.server.js` and `+layout.js` alike. */
|
|
63
|
+
load: {
|
|
64
|
+
(event: ServerLoadEvent): Promise<{
|
|
65
|
+
i18n: Payload;
|
|
66
|
+
}>;
|
|
67
|
+
<E extends UniversalLoadEvent>(event: E): Promise<Omit<NonNullable<E['data']>, 'i18n'> & {
|
|
68
|
+
i18n: Instance;
|
|
69
|
+
}>;
|
|
70
|
+
(event: UniversalLoadEvent): Promise<{
|
|
71
|
+
i18n: Instance;
|
|
72
|
+
}>;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Called once, in the root layout's script, with a getter of its `data`.
|
|
76
|
+
* Provides the instance to every component below, and follows each
|
|
77
|
+
* navigation as it commits. Returns the instance.
|
|
78
|
+
*/
|
|
79
|
+
use: (data: () => object | null | undefined) => Instance;
|
|
80
|
+
/** The instance `use()` provided, in any component below the root layout. */
|
|
81
|
+
get: () => Instance;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|