@sveltekit-i18n/base 1.3.7 → 3.0.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
@@ -1,126 +1,401 @@
1
1
 
2
-
3
2
  [![npm version](https://badge.fury.io/js/@sveltekit-i18n%2Fbase.svg)](https://badge.fury.io/js/@sveltekit-i18n%2Fbase) ![](https://github.com/sveltekit-i18n/base/workflows/Tests/badge.svg)
4
3
 
5
4
  # @sveltekit-i18n/base
6
- This repository contains the base functionality of [sveltekit-i18n](https://github.com/sveltekit-i18n/lib) and provides support for external message [parsers](https://github.com/sveltekit-i18n/parsers).
7
5
 
6
+ Core i18n functionality for SvelteKit with support for custom message parsers. This package provides the foundation for [sveltekit-i18n](https://github.com/sveltekit-i18n/lib) and can be used standalone when you need maximum flexibility with custom parsers.
7
+
8
+ ## When to use @sveltekit-i18n/base
9
+
10
+ **Use this package if you:**
11
+ - Need a custom message parser (like ICU, Fluent, or your own format)
12
+ - Want full control over message interpolation
13
+ - Are building a custom i18n solution
14
+
15
+ **Use [sveltekit-i18n](https://github.com/sveltekit-i18n/lib) if you:**
16
+ - Want the quickest setup with sensible defaults
17
+ - Are happy with the default placeholder/modifier syntax
18
+ - Don't need custom parsers
19
+
20
+ ## Key Features
21
+
22
+ ✅ **Svelte 5 runes** – One reactive instance, no stores
23
+ ✅ **Framework ready** – Full SSR and CSR support
24
+ ✅ **Parser-agnostic** – Use any message syntax you need
25
+ ✅ **Custom data sources** – Load translations from anywhere (files, APIs, databases)
26
+ ✅ **Module-based** – Translations load only for visited pages
27
+ ✅ **Route-aware** – Automatic loading based on SvelteKit routes
28
+ ✅ **Component-scoped** – Multiple translation instances with custom definitions
29
+ ✅ **Extensible** – Pipe the instance through [extensions](#extensions) to reshape or augment its surface
30
+ ✅ **TypeScript** – Locales inferred from your config, keys and payloads from a [`schema`](#schema)
31
+ ✅ **Zero dependencies** – Lightweight and fast
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ npm install @sveltekit-i18n/base
37
+ ```
38
+
39
+ You'll also need a parser:
8
40
 
9
- ## Key features
41
+ ```bash
42
+ # Choose one:
43
+ npm install @sveltekit-i18n/parser-default
44
+ npm install @sveltekit-i18n/parser-icu
45
+ # or create your own
46
+ ```
47
+
48
+ ## Quick Start
49
+
50
+ ### 1. Create translation files
10
51
 
11
- ✅ SvelteKit ready\
12
- SSR support\
13
- ✅ Custom parsers – you can use any message syntax you need\
14
- Custom data sources – no matter if you are using local files or remote API to get your translations\
15
- Module-based – your translations are loaded for visited pages only (and only once!)\
16
- ✅ Component-scoped translations – you can create multiple instances with custom definitions\
17
- ✅ TS support\
18
- ✅ No external dependencies
52
+ ```jsonc
53
+ // src/lib/translations/en/common.json
54
+ {
55
+ "greeting": "Hello, {{name}}!",
56
+ "farewell": "Goodbye!"
57
+ }
58
+ ```
19
59
 
20
- ## Usage
60
+ ### 2. Setup with a parser
21
61
 
22
- Setup `translations.js` in your lib folder...
23
62
  ```javascript
24
- import i18n from '@sveltekit-i18n/base';
25
- // use your preferred parser (or create your own)
63
+ // src/lib/translations/index.js
64
+ import { I18n } from '@sveltekit-i18n/base';
26
65
  import parser from '@sveltekit-i18n/parser-default';
27
- // import parser from '@sveltekit-i18n/parser-icu';
28
66
 
29
- /** @type {import('@sveltekit-i18n/parser-default').Config} */
30
- const config = ({
31
- parser: parser({/* Parser options */}),
67
+ /** @type {import('@sveltekit-i18n/base').Config.T} */
68
+ const config = {
69
+ parser: parser({ /* parser options */ }),
32
70
  loaders: [
33
71
  {
34
72
  locale: 'en',
35
73
  key: 'common',
36
- loader: async () => (
37
- await import('./en/common.json')
38
- ).default,
39
- },
40
- {
41
- locale: 'en',
42
- key: 'home',
43
- routes: ['/'], // you can use regexes as well!
44
- loader: async () => (
45
- await import('./en/home.json')
46
- ).default,
47
- },
48
- {
49
- locale: 'en',
50
- key: 'about',
51
- routes: ['/about'],
52
- loader: async () => (
53
- await import('./en/about.json')
54
- ).default,
74
+ loader: async () => (await import('./en/common.json')).default,
55
75
  },
56
76
  {
57
77
  locale: 'cs',
58
78
  key: 'common',
59
- loader: async () => (
60
- await import('./cs/common.json')
61
- ).default,
62
- },
63
- {
64
- locale: 'cs',
65
- key: 'home',
66
- routes: ['/'],
67
- loader: async () => (
68
- await import('./cs/home.json')
69
- ).default,
70
- },
71
- {
72
- locale: 'cs',
73
- key: 'about',
74
- routes: ['/about'],
75
- loader: async () => (
76
- await import('./cs/about.json')
77
- ).default,
79
+ loader: async () => (await import('./cs/common.json')).default,
78
80
  },
79
81
  ],
80
- });
82
+ };
81
83
 
82
- export const { t, locale, locales, loading, loadTranslations } = new i18n(config);
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);
83
90
  ```
84
91
 
85
- ...load your translations in `+layout.js`...
92
+ ### 3. Load translations in your layout
86
93
 
87
- ```js
88
- import { loadTranslations } from '$lib/translations';
94
+ ```javascript
95
+ // src/routes/+layout.js
96
+ import { i18n } from '$lib/translations';
89
97
 
90
- /** @type {import('@sveltejs/kit').Load} */
98
+ /** @type {import('./$types').LayoutLoad} */
91
99
  export const load = async ({ url }) => {
92
100
  const { pathname } = url;
101
+ const initLocale = 'en';
93
102
 
94
- const initLocale = 'en'; // get from cookie, user session, ...
95
-
96
- await loadTranslations(initLocale, pathname); // keep this just before the `return`
103
+ await i18n.loadTranslations(initLocale, pathname);
97
104
 
98
105
  return {};
99
- }
106
+ };
100
107
  ```
101
108
 
102
- ...and include your translations within pages and components.
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).
114
+
115
+ ### 4. Use in components
103
116
 
104
117
  ```svelte
105
118
  <script>
106
- import { t } from '$lib/translations';
107
-
108
- const pageName = 'This page is Home page!';
119
+ import { i18n } from '$lib/translations';
109
120
  </script>
110
121
 
111
- <div>
112
- <h2>{$t('common.page', { pageName })}</h2>
113
- <p>{$t('home.content')}</p>
114
- </div>
122
+ <p>{i18n.t('common.greeting', { name: 'World' })}</p>
123
+ ```
124
+
125
+ The call reads the reactive translation table and locale, so the text updates
126
+ automatically when either changes — no stores, no `$` prefix.
127
+
128
+ ## Using Different Parsers
129
+
130
+ ### ICU Message Format
131
+
132
+ ```javascript
133
+ import i18n from '@sveltekit-i18n/base';
134
+ import parser from '@sveltekit-i18n/parser-icu';
135
+
136
+ const config = {
137
+ parser: parser(),
138
+ loaders: [/* ... */],
139
+ };
140
+ ```
141
+
142
+ ```json
143
+ {
144
+ "items": "You have {count, plural, =0 {no items} one {# item} other {# items}}."
145
+ }
146
+ ```
147
+
148
+ ### Custom Parser
149
+
150
+ ```javascript
151
+ import i18n from '@sveltekit-i18n/base';
152
+
153
+ const customParser = () => ({
154
+ parse: (value, params) => {
155
+ // Your custom interpolation logic
156
+ return value.replace(/\{(\w+)\}/g, (_, key) => params[0]?.[key] ?? key);
157
+ },
158
+ });
159
+
160
+ const config = {
161
+ parser: customParser(),
162
+ loaders: [/* ... */],
163
+ };
164
+ ```
165
+
166
+ Learn more about [creating custom parsers](https://github.com/sveltekit-i18n/parsers#creating-custom-parsers).
167
+
168
+ ## Configuration Options
169
+
170
+ ### `parser` (required)
171
+
172
+ Message parser instance. See [Parsers](https://github.com/sveltekit-i18n/parsers).
173
+
174
+ ### `loaders`
175
+
176
+ Array of loader configurations:
177
+
178
+ ```javascript
179
+ loaders: [
180
+ {
181
+ locale: 'en', // Required: locale identifier
182
+ key: 'common', // Required: translation namespace
183
+ loader: async () => {}, // Required: async function returning translations
184
+ routes: ['/about'], // Optional: load only for specific routes
185
+ },
186
+ ]
187
+ ```
188
+
189
+ Both `loaders` and a loader's `routes` accept readonly arrays, so a whole-config `as const` is fine.
190
+
191
+ ### `translations`
192
+
193
+ Synchronous translations loaded immediately:
194
+
195
+ ```javascript
196
+ translations: {
197
+ en: {
198
+ 'app.name': 'My App',
199
+ },
200
+ }
201
+ ```
202
+
203
+ ### `initLocale`
204
+
205
+ Initialize with a specific locale immediately:
206
+
207
+ ```javascript
208
+ initLocale: 'en'
209
+ ```
210
+
211
+ ### `fallbackLocale`
212
+
213
+ Fallback when translation is missing:
214
+
215
+ ```javascript
216
+ fallbackLocale: 'en'
217
+ ```
218
+
219
+ **Note:** This loads translations for both current locale and fallback locale, which may impact performance.
220
+
221
+ ### `fallbackValue`
222
+
223
+ Default return value when translation key is not found:
224
+
225
+ ```javascript
226
+ fallbackValue: '...' // Default: returns the key itself
227
+ ```
228
+
229
+ ### `preprocess`
230
+
231
+ Transform translations after loading:
232
+
233
+ ```javascript
234
+ preprocess: 'full' // 'full' | 'preserveArrays' | 'none' | custom function
235
+ ```
236
+
237
+ - `'full'` (default): Flattens all nested objects to dot notation
238
+ - `'preserveArrays'`: Flattens objects but preserves arrays
239
+ - `'none'`: No preprocessing
240
+ - Custom function: `(input) => transformedOutput`
241
+
242
+ ### `schema`
243
+
244
+ A map of translation key to the payload its message expects (`never` for a message that takes none). Supplying it types `t`/`l` — keys autocomplete, an unknown key is a type error, and the payload argument is checked. Only its type is read, so the value can stay empty at runtime:
245
+
246
+ ```typescript
247
+ type TranslationSchema = {
248
+ 'common.greeting': { name: string };
249
+ 'common.farewell': never;
250
+ };
251
+
252
+ const i18n = new I18n({ ...config, schema: {} as TranslationSchema });
253
+ ```
254
+
255
+ Hand-write it for a small set of messages, or point the slot at a generated artifact. A schema whose keys are not a closed set is ignored, and keys stay plain strings. See [`schema`](./docs/README.md#schema) for the full rules.
256
+
257
+ ### `cache`
258
+
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).
260
+
261
+ Set a finite value when your loaders fetch from a source that can change at runtime (e.g. a CMS):
262
+
263
+ ```javascript
264
+ cache: 3600000 // Translations older than 1 hour refetch on the next load
265
+ ```
266
+
267
+ Set to `0` to treat translations as always stale (refetch on every load trigger). You can also drop the loaded state manually at any time with [`invalidate()`](#methods).
268
+
269
+ ### `extensions`
270
+
271
+ Pipes the constructed instance through extension functions, left to right. Each extension receives the surface produced so far (the raw instance for the first one) and returns the surface handed on — `new I18n(config)` evaluates to the last extension's output:
272
+
273
+ ```javascript
274
+ import stores from '@sveltekit-i18n/extension-stores';
275
+
276
+ const { t, locale, loading } = new I18n({
277
+ ...config,
278
+ extensions: [stores],
279
+ });
280
+ ```
281
+
282
+ An extension may augment the instance in place, or replace the surface entirely (like the store adapter above). Official extensions live in the [extensions](https://github.com/sveltekit-i18n/extensions) repository; a custom extension is just a function:
283
+
284
+ ```javascript
285
+ const withGreeting = (i18n) => Object.assign(i18n, {
286
+ greet: (name) => i18n.t('common.greeting', { name }),
287
+ });
288
+
289
+ export const i18n = new I18n({ ...config, extensions: [withGreeting] });
290
+
291
+ i18n.greet('World');
292
+ ```
293
+
294
+ **Notes:**
295
+ - Applied at construction time only — a later `loadConfig()` call ignores this property.
296
+ - When an extension returns a new object, the result is no longer `instanceof I18n`; the original instance stays reachable through whatever the extension exposes (the official extensions expose it as `instance`).
297
+
298
+ ### `log`
299
+
300
+ Logging configuration:
301
+
302
+ ```javascript
303
+ log: {
304
+ level: 'warn', // 'error' | 'warn' | 'debug'
305
+ prefix: '[i18n]: ', // Log prefix
306
+ logger: console, // Custom logger
307
+ }
308
+ ```
309
+
310
+ ## API Reference
311
+
312
+ ### Reactive properties
313
+
314
+ - `t(key, ...params)` – translate for the active locale (reactive function)
315
+ - `l(locale, key, ...params)` – translate for an explicit locale
316
+ - `locale` – the ACTIVE locale; assignment is a fire-and-forget `setLocale()`
317
+ - `locales` – available locales
318
+ - `loading` – `true` while any load is in flight
319
+ - `initialized` – locale and route set, translations present
320
+ - `translations` / `rawTranslations` – the (pre/post-preprocess) tables
321
+
322
+ ### Methods
323
+
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.
325
+
326
+ - `loadTranslations(locale, route?)` – load translations for locale and route; `route` defaults to the current one
327
+ - `setLocale(locale)` – request a locale; loads once a route is known
328
+ - `setRoute(route)` – update the current route
329
+ - `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 from it
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
333
+ - `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
+
335
+ ### Utilities
336
+
337
+ Two helpers the instance uses internally ship from a separate subpath, for code that has to match the library's own behavior:
338
+
339
+ ```javascript
340
+ import { sanitizeLocales, toDotNotation } from '@sveltekit-i18n/base/utils';
115
341
  ```
116
342
 
343
+ - `toDotNotation(input, preserveArrays?)` – the flattening behind [`preprocess`](#preprocess), for a custom `preprocess` that still wants dot notation
344
+ - `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`
345
+
346
+ Full API documentation: [docs/README.md](./docs/README.md)
347
+
348
+ ## Documentation
349
+
350
+ - 📖 [Full API Documentation](./docs/README.md) – Complete reference
351
+ - 📚 [Main Library Docs](https://github.com/sveltekit-i18n/lib/tree/master/docs/INDEX.md) – Guides, tutorials, and best practices
352
+ - 🎨 [Parsers](https://github.com/sveltekit-i18n/parsers) – Available parsers and how to create your own
353
+ - 💡 [Examples](https://github.com/sveltekit-i18n/lib/tree/master/examples) – Real-world usage examples
354
+
355
+ ## TypeScript Support
356
+
357
+ ```typescript
358
+ import { I18n, type Config } from '@sveltekit-i18n/base';
359
+ import parser from '@sveltekit-i18n/parser-default';
360
+
361
+ // The parser's params – the rest parameters of `t`/`l`. Annotate only when the
362
+ // config lives on its own; `new I18n({ ... })` infers them.
363
+ type Params = [payload?: Record<string, unknown>];
364
+
365
+ const config: Config.T<Params> = {
366
+ parser: parser(),
367
+ loaders: [/* ... */],
368
+ };
369
+ ```
370
+
371
+ 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`, `invalidate`, `l`, `locale`, `locales`):
372
+
373
+ ```typescript
374
+ const i18n = new I18n({ parser: parser(), initLocale: 'en', fallbackLocale: 'de' });
375
+
376
+ i18n.setLocale('en'); // 'en' | 'de' autocomplete here
377
+ i18n.setLocale('sv'); // still accepted — the union is a hint, not a constraint
378
+ ```
379
+
380
+ 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](./docs/README.md#typescript) for both.
381
+
382
+ ## Related Packages
383
+
384
+ - [sveltekit-i18n](https://github.com/sveltekit-i18n/lib) – Complete solution with default parser
385
+ - [@sveltekit-i18n/parser-default](https://github.com/sveltekit-i18n/parsers/tree/master/parser-default) – Default message parser
386
+ - [@sveltekit-i18n/parser-icu](https://github.com/sveltekit-i18n/parsers/tree/master/parser-icu) – ICU message format parser
387
+ - [Extensions](https://github.com/sveltekit-i18n/extensions) – Official extensions for the `config.extensions` pipe
388
+
389
+ ## Contributing
390
+
391
+ For general contribution guidelines, see the [Contributing Guide](https://github.com/sveltekit-i18n/lib/blob/master/CONTRIBUTING.md) in the main library repository.
392
+
393
+ For issues specific to base functionality, create a ticket [here](https://github.com/sveltekit-i18n/lib/issues).
394
+
395
+ ## Changelog
117
396
 
118
- ## More info
119
- [Parsers](https://github.com/sveltekit-i18n/parsers)\
120
- [Docs](https://github.com/sveltekit-i18n/base/tree/master/docs/README.md)\
121
- [Examples](https://github.com/sveltekit-i18n/lib/tree/master/examples#parsers)\
122
- [Changelog](https://github.com/sveltekit-i18n/base/releases)
397
+ See [Releases](https://github.com/sveltekit-i18n/base/releases) for version history.
123
398
 
399
+ ## License
124
400
 
125
- ## Issues
126
- If you are facing some issues related to the base functionality, create a ticket [here](https://github.com/sveltekit-i18n/lib/issues).
401
+ MIT
@@ -0,0 +1,80 @@
1
+ import type { Config, Extension, Parser, Schema, Translations } from './types.js';
2
+ declare class I18nCore<ParserParams extends Parser.Params = any, ParserOutput = string, TranslationSchema = never, LocaleUnion extends string = string> {
3
+ #private;
4
+ constructor(config?: Config.T<ParserParams, ParserOutput>);
5
+ /**
6
+ * The active locale. Reading it is reactive; assigning it is a shorthand for
7
+ * a fire-and-forget `setLocale()` — the value therefore updates once the
8
+ * locale's translations resolved, not synchronously on assignment.
9
+ */
10
+ get locale(): Config.LocaleInput<LocaleUnion> | undefined;
11
+ set locale(value: Config.LocaleInput<LocaleUnion> | undefined);
12
+ get translations(): Translations.SerializedTranslations;
13
+ get rawTranslations(): Translations.SerializedTranslations;
14
+ loading: boolean;
15
+ locales: Config.LocaleInput<LocaleUnion>[];
16
+ initialized: boolean;
17
+ /**
18
+ * Translates `key` for the active locale. Reactive wherever reads are
19
+ * tracked: the call reads the translation table and locale, so a component
20
+ * using `{i18n.t('key')}` re-renders when either changes.
21
+ */
22
+ t: Translations.TranslationFunction<ParserParams, ParserOutput, TranslationSchema>;
23
+ /** Like `t`, for an explicit locale. */
24
+ l: Translations.LocalTranslationFunction<ParserParams, ParserOutput, TranslationSchema, LocaleUnion>;
25
+ /**
26
+ * Applies a config. Overridable extension seam — `sveltekit-i18n` wires its
27
+ * default parser by extending this method.
28
+ */
29
+ configLoader(config: Config.T<ParserParams, ParserOutput>): Promise<void>;
30
+ /**
31
+ * Public entry for (re)configuration. The failure is reported here and the
32
+ * promise marked handled, so a fire-and-forget call cannot become an
33
+ * unhandled rejection; an awaiting caller still receives it.
34
+ */
35
+ loadConfig: (config: Config.T<ParserParams, ParserOutput>) => Promise<void>;
36
+ setLocale: (locale?: Config.LocaleInput<LocaleUnion>) => Promise<void>;
37
+ setRoute: (route: string) => Promise<void>;
38
+ loadTranslations: (locale: Config.LocaleInput<LocaleUnion>, route?: string) => Promise<void>;
39
+ /**
40
+ * Marks loaded translations stale — for one locale, or all of them. Loaders
41
+ * run again on the NEXT load trigger; the call itself starts no load and
42
+ * keeps the currently displayed translations in place. A load still in
43
+ * flight for an invalidated locale is severed: it settles, but its data is
44
+ * discarded — it predates the invalidation.
45
+ */
46
+ invalidate: (locale?: Config.LocaleInput<LocaleUnion>) => void;
47
+ addTranslations: (translations?: Translations.SerializedTranslations) => void;
48
+ /**
49
+ * Serializes what this instance holds for the active locale and the fallback
50
+ * locale, narrowed to the current route: a key owned only by loaders that do
51
+ * not match the route is left out. The result is shaped like
52
+ * `config.translations`, so a client hydrates by handing it back to the
53
+ * constructor — the bookkeeping derived from it then keeps the matching
54
+ * loaders from fetching the same data again.
55
+ */
56
+ snapshot: () => Translations.SerializedTranslations;
57
+ /**
58
+ * Detaches the instance from its loading lifecycle: in-flight loads settle
59
+ * with their data discarded, `loading` drops to `false`, and every further
60
+ * load or mutation call is ignored with a warning. Reads (`t`, `l`, `locale`,
61
+ * `translations`, `snapshot`) keep working, so a component still tearing down
62
+ * renders its last state instead of breaking. Idempotent.
63
+ */
64
+ destroy: () => void;
65
+ }
66
+ /**
67
+ * A class declaration cannot annotate its constructor's return type, so the
68
+ * extension pipe's construction-time type lives on this construct signature
69
+ * instead: parser params and output are inferred from `config.parser`, locales
70
+ * are narrowed to the ones the config names, and the returned surface is the
71
+ * instance type folded through the `config.extensions` tuple
72
+ * (`const` keeps it a tuple without `as const` at the call site).
73
+ */
74
+ interface I18nConstructor {
75
+ new <const C extends Config.T<any, any> = Config.T<any, any>>(config?: C): Extension.Piped<I18nCore<Parser.FromConfig<C>, Parser.OutputFromConfig<C>, Schema.FromConfig<C>, Config.LocalesFromConfig<C>>, Extension.FromConfig<C>>;
76
+ }
77
+ declare const I18n: I18nConstructor;
78
+ type I18n<ParserParams extends Parser.Params = any, ParserOutput = string, TranslationSchema = never, LocaleUnion extends string = string> = I18nCore<ParserParams, ParserOutput, TranslationSchema, LocaleUnion>;
79
+ export { I18n };
80
+ export default I18n;