@sveltekit-i18n/base 1.3.6 → 1.3.8

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,303 @@
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
8
19
 
9
- ## Key features
20
+ ## Key Features
21
+
22
+ ✅ **SvelteKit ready** – Full SSR and CSR support
23
+ ✅ **Parser-agnostic** – Use any message syntax you need
24
+ ✅ **Custom data sources** – Load translations from anywhere (files, APIs, databases)
25
+ ✅ **Module-based** – Translations load only for visited pages
26
+ ✅ **Route-aware** – Automatic loading based on SvelteKit routes
27
+ ✅ **Component-scoped** – Multiple translation instances with custom definitions
28
+ ✅ **TypeScript** – Full type support
29
+ ✅ **Zero dependencies** – Lightweight and fast
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ npm install @sveltekit-i18n/base
35
+ ```
10
36
 
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
37
+ You'll also need a parser:
38
+
39
+ ```bash
40
+ # Choose one:
41
+ npm install @sveltekit-i18n/parser-default
42
+ npm install @sveltekit-i18n/parser-icu
43
+ # or create your own
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ### 1. Create translation files
49
+
50
+ ```json
51
+ // src/lib/translations/en/common.json
52
+ {
53
+ "greeting": "Hello, {{name}}!",
54
+ "farewell": "Goodbye!"
55
+ }
56
+ ```
19
57
 
20
- ## Usage
58
+ ### 2. Setup with a parser
21
59
 
22
- Setup `translations.js` in your lib folder...
23
60
  ```javascript
61
+ // src/lib/translations/index.js
24
62
  import i18n from '@sveltekit-i18n/base';
25
- // use your preferred parser (or create your own)
26
63
  import parser from '@sveltekit-i18n/parser-default';
27
- // import parser from '@sveltekit-i18n/parser-icu';
28
64
 
29
- /** @type {import('@sveltekit-i18n/parser-default').Config} */
30
- const config = ({
31
- parser: parser({/* Parser options */}),
65
+ /** @type {import('@sveltekit-i18n/base').Config} */
66
+ const config = {
67
+ parser: parser({ /* parser options */ }),
32
68
  loaders: [
33
69
  {
34
70
  locale: 'en',
35
71
  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,
72
+ loader: async () => (await import('./en/common.json')).default,
55
73
  },
56
74
  {
57
75
  locale: 'cs',
58
76
  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,
77
+ loader: async () => (await import('./cs/common.json')).default,
78
78
  },
79
79
  ],
80
- });
80
+ };
81
81
 
82
82
  export const { t, locale, locales, loading, loadTranslations } = new i18n(config);
83
83
  ```
84
84
 
85
- ...load your translations in `+layout.js`...
85
+ ### 3. Load translations in your layout
86
86
 
87
- ```js
87
+ ```javascript
88
+ // src/routes/+layout.js
88
89
  import { loadTranslations } from '$lib/translations';
89
90
 
90
- /** @type {import('@sveltejs/kit').Load} */
91
+ /** @type {import('./$types').LayoutLoad} */
91
92
  export const load = async ({ url }) => {
92
93
  const { pathname } = url;
93
-
94
- const initLocale = 'en'; // get from cookie, user session, ...
95
-
96
- await loadTranslations(initLocale, pathname); // keep this just before the `return`
97
-
94
+ const initLocale = 'en';
95
+
96
+ await loadTranslations(initLocale, pathname);
97
+
98
98
  return {};
99
- }
99
+ };
100
100
  ```
101
101
 
102
- ...and include your translations within pages and components.
102
+ ### 4. Use in components
103
103
 
104
104
  ```svelte
105
105
  <script>
106
106
  import { t } from '$lib/translations';
107
-
108
- const pageName = 'This page is Home page!';
109
107
  </script>
110
108
 
111
- <div>
112
- <h2>{$t('common.page', { pageName })}</h2>
113
- <p>{$t('home.content')}</p>
114
- </div>
109
+ <p>{$t('common.greeting', { name: 'World' })}</p>
110
+ ```
111
+
112
+ ## Using Different Parsers
113
+
114
+ ### ICU Message Format
115
+
116
+ ```javascript
117
+ import i18n from '@sveltekit-i18n/base';
118
+ import parser from '@sveltekit-i18n/parser-icu';
119
+
120
+ const config = {
121
+ parser: parser(),
122
+ loaders: [/* ... */],
123
+ };
124
+ ```
125
+
126
+ ```json
127
+ {
128
+ "items": "You have {count, plural, =0 {no items} one {# item} other {# items}}."
129
+ }
130
+ ```
131
+
132
+ ### Custom Parser
133
+
134
+ ```javascript
135
+ import i18n from '@sveltekit-i18n/base';
136
+
137
+ const customParser = () => ({
138
+ parse: (value, params) => {
139
+ // Your custom interpolation logic
140
+ return value.replace(/\{(\w+)\}/g, (_, key) => params[0]?.[key] ?? key);
141
+ },
142
+ });
143
+
144
+ const config = {
145
+ parser: customParser(),
146
+ loaders: [/* ... */],
147
+ };
115
148
  ```
116
149
 
150
+ Learn more about [creating custom parsers](https://github.com/sveltekit-i18n/parsers#creating-custom-parsers).
151
+
152
+ ## Configuration Options
153
+
154
+ ### `parser` (required)
155
+
156
+ Message parser instance. See [Parsers](https://github.com/sveltekit-i18n/parsers).
157
+
158
+ ### `loaders`
159
+
160
+ Array of loader configurations:
161
+
162
+ ```javascript
163
+ loaders: [
164
+ {
165
+ locale: 'en', // Required: locale identifier
166
+ key: 'common', // Required: translation namespace
167
+ loader: async () => {}, // Required: async function returning translations
168
+ routes: ['/about'], // Optional: load only for specific routes
169
+ },
170
+ ]
171
+ ```
172
+
173
+ ### `translations`
174
+
175
+ Synchronous translations loaded immediately:
176
+
177
+ ```javascript
178
+ translations: {
179
+ en: {
180
+ 'app.name': 'My App',
181
+ },
182
+ }
183
+ ```
184
+
185
+ ### `initLocale`
186
+
187
+ Initialize with a specific locale immediately:
188
+
189
+ ```javascript
190
+ initLocale: 'en'
191
+ ```
192
+
193
+ ### `fallbackLocale`
194
+
195
+ Fallback when translation is missing:
196
+
197
+ ```javascript
198
+ fallbackLocale: 'en'
199
+ ```
200
+
201
+ **Note:** This loads translations for both current locale and fallback locale, which may impact performance.
202
+
203
+ ### `fallbackValue`
204
+
205
+ Default return value when translation key is not found:
206
+
207
+ ```javascript
208
+ fallbackValue: '...' // Default: returns the key itself
209
+ ```
210
+
211
+ ### `preprocess`
212
+
213
+ Transform translations after loading:
214
+
215
+ ```javascript
216
+ preprocess: 'full' // 'full' | 'preserveArrays' | 'none' | custom function
217
+ ```
218
+
219
+ - `'full'` (default): Flattens all nested objects to dot notation
220
+ - `'preserveArrays'`: Flattens objects but preserves arrays
221
+ - `'none'`: No preprocessing
222
+ - Custom function: `(input) => transformedOutput`
223
+
224
+ ### `cache`
225
+
226
+ Server-side cache duration in milliseconds:
227
+
228
+ ```javascript
229
+ cache: 86400000 // Default: 24 hours
230
+ ```
231
+
232
+ Set to `Number.POSITIVE_INFINITY` to disable cache refresh.
233
+
234
+ ### `log`
235
+
236
+ Logging configuration:
237
+
238
+ ```javascript
239
+ log: {
240
+ level: 'warn', // 'error' | 'warn' | 'debug'
241
+ prefix: '[i18n]: ', // Log prefix
242
+ logger: console, // Custom logger
243
+ }
244
+ ```
245
+
246
+ ## API Reference
247
+
248
+ ### Stores
249
+
250
+ - `t` – Translation function store
251
+ - `locale` – Current locale (writable)
252
+ - `locales` – Available locales (readable)
253
+ - `loading` – Loading state (readable)
254
+ - `initialized` – Initialization state (readable)
255
+ - `translations` – All loaded translations (readable)
256
+
257
+ ### Methods
258
+
259
+ - `loadTranslations(locale, route)` – Load translations for locale and route
260
+ - `setLocale(locale)` – Change current locale
261
+ - `setRoute(route)` – Update current route
262
+
263
+ Full API documentation: [docs/README.md](./docs/README.md)
264
+
265
+ ## Documentation
266
+
267
+ - 📖 [Full API Documentation](./docs/README.md) – Complete reference
268
+ - 📚 [Main Library Docs](https://github.com/sveltekit-i18n/lib/tree/master/docs/INDEX.md) – Guides, tutorials, and best practices
269
+ - 🎨 [Parsers](https://github.com/sveltekit-i18n/parsers) – Available parsers and how to create your own
270
+ - 💡 [Examples](https://github.com/sveltekit-i18n/lib/tree/master/examples) – Real-world usage examples
271
+
272
+ ## TypeScript Support
273
+
274
+ ```typescript
275
+ import i18n, { type Config } from '@sveltekit-i18n/base';
276
+ import parser from '@sveltekit-i18n/parser-default';
277
+ import type { Config as ParserConfig } from '@sveltekit-i18n/parser-default';
278
+
279
+ const config: Config<ParserConfig> = {
280
+ parser: parser(),
281
+ loaders: [/* ... */],
282
+ };
283
+ ```
284
+
285
+ ## Related Packages
286
+
287
+ - [sveltekit-i18n](https://github.com/sveltekit-i18n/lib) – Complete solution with default parser
288
+ - [@sveltekit-i18n/parser-default](https://github.com/sveltekit-i18n/parsers/tree/master/parser-default) – Default message parser
289
+ - [@sveltekit-i18n/parser-icu](https://github.com/sveltekit-i18n/parsers/tree/master/parser-icu) – ICU message format parser
290
+
291
+ ## Contributing
292
+
293
+ For general contribution guidelines, see the [Contributing Guide](https://github.com/sveltekit-i18n/lib/blob/master/CONTRIBUTING.md) in the main library repository.
294
+
295
+ For issues specific to base functionality, create a ticket [here](https://github.com/sveltekit-i18n/lib/issues).
296
+
297
+ ## Changelog
117
298
 
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)
299
+ See [Releases](https://github.com/sveltekit-i18n/base/releases) for version history.
123
300
 
301
+ ## License
124
302
 
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).
303
+ MIT
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var H=Object.defineProperty,q=Object.defineProperties;var B=Object.getOwnPropertyDescriptors;var x=Object.getOwnPropertySymbols;var A=Object.prototype.hasOwnProperty,N=Object.prototype.propertyIsEnumerable;var $=(r,t,e)=>t in r?H(r,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[t]=e,l=(r,t)=>{for(var e in t||(t={}))A.call(t,e)&&$(r,e,t[e]);if(x)for(var e of x(t))N.call(t,e)&&$(r,e,t[e]);return r},u=(r,t)=>q(r,B(t));var T=(r,t)=>{var e={};for(var a in r)A.call(r,a)&&t.indexOf(a)<0&&(e[a]=r[a]);if(r!=null&&x)for(var a of x(r))t.indexOf(a)<0&&N.call(r,a)&&(e[a]=r[a]);return e};var _store = require('svelte/store');var C=["error","warn","debug"],z=({logger:r=console,level:t=C[1],prefix:e="[i18n]: "})=>C.reduce((a,s,o)=>u(l({},a),{[s]:i=>C.indexOf(t)>=o&&r[s](`${e}${i}`)}),{}),d=z({}),V=r=>{d=r};var F=n=>{var c=n,{parser:r,key:t,params:e,translations:a,locale:s,fallbackLocale:o}=c,i=T(c,["parser","key","params","translations","locale","fallbackLocale"]);if(!t)return d.warn(`No translation key provided ('${s}' locale). Skipping translation...`),"";if(!s)return d.warn(`No locale provided for '${t}' key. Skipping translation...`),"";let f=(a[s]||{})[t];return o&&f===void 0&&(f=(a[o]||{})[t]),i.hasOwnProperty("fallbackValue")&&f===void 0?i.fallbackValue:r.parse(f,e,s,t)},h=(...r)=>r.length?r.filter(t=>!!t).map(t=>{let e=`${t}`.toLowerCase();try{let[a]=Intl.Collator.supportedLocalesOf(t);if(!a)throw new Error;e=a}catch(a){d.warn(`'${t}' locale is non-standard.`)}return e}):[],w=(r,t,e)=>{if(t&&Array.isArray(r))return r.map(a=>w(a,t));if(r&&typeof r=="object"){let a=Object.keys(r).reduce((s,o)=>{let i=r[o],n=e?`${e}.${o}`:`${o}`;return i&&typeof i=="object"&&!(t&&Array.isArray(i))?l(l({},s),w(i,t,n)):u(l({},s),{[n]:w(i,t)})},{});return Object.keys(a).length?a:null}return r},G=r=>r.reduce((t,{key:e,data:a,locale:s})=>{if(!a)return t;let[o]=h(s),i=u(l({},t[o]||{}),{[e]:a});return u(l({},t),{[o]:i})},{}),E=async r=>{try{let t=await Promise.all(r.map(s=>{var o=s,{loader:e}=o,a=T(o,["loader"]);return new Promise(async i=>{let n;try{n=await e()}catch(c){d.error(`Failed to load translation. Verify your '${a.locale}' > '${a.key}' Loader.`),d.error(c)}i(u(l({loader:e},a),{data:n}))})}));return G(t)}catch(t){d.error(t)}return{}},W=r=>t=>{try{if(typeof t=="string")return t===r;if(typeof t=="object")return t.test(r)}catch(e){d.error("Invalid route config!")}return!1},O=(r,t)=>{let e=!0;try{e=Object.keys(r).filter(a=>r[a]!==void 0).every(a=>r[a]===t[a])}catch(a){}return e};var D=1e3*60*60*24,j= exports.default =class{constructor(t){this.cachedAt=0;this.loadedKeys={};this.currentRoute=_store.writable.call(void 0, );this.config=_store.writable.call(void 0, );this.isLoading=_store.writable.call(void 0, !1);this.promises=new Set;this.loading={subscribe:this.isLoading.subscribe,toPromise:(t,e)=>{let{fallbackLocale:a}=_store.get.call(void 0, this.config),s=Array.from(this.promises).filter(o=>{let i=O({locale:h(t)[0],route:e},o);return a&&(i=i||O({locale:h(a)[0],route:e},o)),i}).map(({promise:o})=>o);return Promise.all(s)},get:()=>_store.get.call(void 0, this.isLoading)};this.privateRawTranslations=_store.writable.call(void 0, {});this.rawTranslations={subscribe:this.privateRawTranslations.subscribe,get:()=>_store.get.call(void 0, this.rawTranslations)};this.privateTranslations=_store.writable.call(void 0, {});this.translations={subscribe:this.privateTranslations.subscribe,get:()=>_store.get.call(void 0, this.translations)};this.locales=u(l({},_store.derived.call(void 0, [this.config,this.privateTranslations],([t,e])=>{if(!t)return[];let{loaders:a=[]}=t,s=a.map(({locale:i})=>i),o=Object.keys(e).map(i=>i);return Array.from(new Set([...h(...s),...h(...o)]))},[])),{get:()=>_store.get.call(void 0, this.locales)});this.internalLocale=_store.writable.call(void 0, );this.loaderTrigger=_store.derived.call(void 0, [this.internalLocale,this.currentRoute],([t,e],a)=>{var s,o;t!==void 0&&e!==void 0&&!(t===((s=_store.get.call(void 0, this.loaderTrigger))==null?void 0:s[0])&&e===((o=_store.get.call(void 0, this.loaderTrigger))==null?void 0:o[1]))&&(d.debug("Triggering translation load..."),a([t,e]))},[]);this.localeHelper=_store.writable.call(void 0, );this.locale={subscribe:this.localeHelper.subscribe,forceSet:this.localeHelper.set,set:this.internalLocale.set,update:this.internalLocale.update,get:()=>_store.get.call(void 0, this.locale)};this.initialized=_store.derived.call(void 0, [this.locale,this.currentRoute,this.privateTranslations],([t,e,a],s)=>{_store.get.call(void 0, this.initialized)||s(t!==void 0&&e!==void 0&&!!Object.keys(a).length)});this.translation=_store.derived.call(void 0, [this.privateTranslations,this.locale,this.isLoading],([t,e,a],s)=>{let o=t[e];o&&Object.keys(o).length&&!a&&s(o)},{});this.t=u(l({},_store.derived.call(void 0, [this.config,this.translation],s=>{var[o]=s,i=o,{parser:t,fallbackLocale:e}=i,a=T(i,["parser","fallbackLocale"]);return(n,...c)=>F(l({parser:t,key:n,params:c,translations:this.translations.get(),locale:this.locale.get(),fallbackLocale:e},a.hasOwnProperty("fallbackValue")?{fallbackValue:a.fallbackValue}:{}))})),{get:(t,...e)=>_store.get.call(void 0, this.t)(t,...e)});this.l=u(l({},_store.derived.call(void 0, [this.config,this.translations],o=>{var[i,...n]=o,c=i,{parser:t,fallbackLocale:e}=c,a=T(c,["parser","fallbackLocale"]),[s]=n;return(f,b,...k)=>F(l({parser:t,key:b,params:k,translations:s,locale:f,fallbackLocale:e},a.hasOwnProperty("fallbackValue")?{fallbackValue:a.fallbackValue}:{}))})),{get:(t,e,...a)=>_store.get.call(void 0, this.l)(t,e,...a)});this.getLocale=t=>{let{fallbackLocale:e}=_store.get.call(void 0, this.config)||{},a=t||e;if(!a)return;let s=this.locales.get();return s.find(i=>h(a).includes(i))||s.find(i=>h(e).includes(i))};this.setLocale=t=>{if(t&&t!==_store.get.call(void 0, this.internalLocale))return d.debug(`Setting '${t}' locale.`),this.internalLocale.set(t),this.loading.toPromise(t,_store.get.call(void 0, this.currentRoute))};this.setRoute=t=>{if(t!==_store.get.call(void 0, this.currentRoute)){d.debug(`Setting '${t}' route.`),this.currentRoute.set(t);let e=_store.get.call(void 0, this.internalLocale);return this.loading.toPromise(e,t)}};this.loadConfig=async t=>{await this.configLoader(t)};this.getTranslationProps=async(t=this.locale.get(),e=_store.get.call(void 0, this.currentRoute))=>{let a=_store.get.call(void 0, this.config);if(!a||!t)return[];let s=this.translations.get(),{loaders:o,fallbackLocale:i="",cache:n=D}=a||{},c=Number.isNaN(+n)?D:+n;this.cachedAt?Date.now()>c+this.cachedAt&&(d.debug("Refreshing cache."),this.loadedKeys={},this.cachedAt=0):(d.debug("Setting cache timestamp."),this.cachedAt=Date.now());let[f,b]=h(t,i),k=s[f],I=s[b],R=(o||[]).map(K=>{var L=K,{locale:p}=L,y=T(L,["locale"]);return u(l({},y),{locale:h(p)[0]})}).filter(({routes:p})=>!p||(p||[]).some(W(e))).filter(({key:p,locale:y})=>y===f&&(!k||!(this.loadedKeys[f]||[]).includes(p))||i&&y===b&&(!I||!(this.loadedKeys[b]||[]).includes(p)));if(R.length){this.isLoading.set(!0),d.debug("Fetching translations...");let p=await E(R);this.isLoading.set(!1);let y=Object.keys(p).reduce((L,P)=>u(l({},L),{[P]:Object.keys(p[P])}),{}),K=R.filter(({key:L,locale:P})=>(y[P]||[]).some(S=>`${S}`.startsWith(L))).reduce((L,{key:P,locale:S})=>u(l({},L),{[S]:[...L[S]||[],P]}),{});return[p,K]}return[]};this.addTranslations=(t,e)=>{if(!t)return;let a=_store.get.call(void 0, this.config),{preprocess:s}=a||{};d.debug("Adding translations...");let o=Object.keys(t||{});this.privateRawTranslations.update(i=>o.reduce((n,c)=>u(l({},n),{[c]:l(l({},n[c]||{}),t[c])}),i)),this.privateTranslations.update(i=>o.reduce((n,c)=>{let f=!0,b=t[c];return typeof s=="function"&&(b=s(b)),(typeof s=="function"||s==="none")&&(f=!1),u(l({},n),{[c]:l(l({},n[c]||{}),f?w(b,s==="preserveArrays"):b)})},i)),o.forEach(i=>{let n=Object.keys(t[i]).map(c=>`${c}`.split(".")[0]);e&&(n=e[i]),this.loadedKeys[i]=Array.from(new Set([...this.loadedKeys[i]||[],...n||[]]))})};this.loader=async([t,e])=>{let a=this.getLocale(t)||void 0;d.debug(`Adding loader promise for '${a}' locale and '${e}' route.`);let s=(async()=>{let o=await this.getTranslationProps(a,e);o.length&&this.addTranslations(...o)})();this.promises.add({locale:a,route:e,promise:s}),s.then(()=>{a&&this.locale.get()!==a&&this.locale.forceSet(a)})};this.loadTranslations=(t,e=_store.get.call(void 0, this.currentRoute)||"")=>{let a=this.getLocale(t);if(a)return this.setRoute(e),this.setLocale(a),this.loading.toPromise(a,e)};this.loaderTrigger.subscribe(this.loader),this.isLoading.subscribe(async e=>{e&&this.promises.size&&(await this.loading.toPromise(),this.promises.clear(),d.debug("Loader promises have been purged."))}),t&&this.loadConfig(t)}async configLoader(t){if(!t)return d.error("No config provided!");let n=t,{initLocale:e,fallbackLocale:a,translations:s,log:o}=n,i=T(n,["initLocale","fallbackLocale","translations","log"]);o&&V(z(o)),[e]=h(e),[a]=h(a),d.debug("Setting config."),this.config.set(l({initLocale:e,fallbackLocale:a,translations:s},i)),s&&this.addTranslations(s),e&&await this.loadTranslations(e)}};exports.default = j;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var B=Object.defineProperty,G=Object.defineProperties;var J=Object.getOwnPropertyDescriptors;var $=Object.getOwnPropertySymbols;var V=Object.prototype.hasOwnProperty,E=Object.prototype.propertyIsEnumerable;var A=(r,t,e)=>t in r?B(r,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[t]=e,l=(r,t)=>{for(var e in t||(t={}))V.call(t,e)&&A(r,e,t[e]);if($)for(var e of $(t))E.call(t,e)&&A(r,e,t[e]);return r},g=(r,t)=>G(r,J(t));var L=(r,t)=>{var e={};for(var a in r)V.call(r,a)&&t.indexOf(a)<0&&(e[a]=r[a]);if(r!=null&&$)for(var a of $(r))t.indexOf(a)<0&&E.call(r,a)&&(e[a]=r[a]);return e};var _store = require('svelte/store');var S=["error","warn","debug"],O=({logger:r=console,level:t=S[1],prefix:e="[i18n]: "})=>{let a=S.includes(t)?S.indexOf(t):S.indexOf("warn");return S.reduce((n,s,i)=>g(l({},n),{[s]:o=>{if(!(a<i)&&typeof r[s]=="function")return r[s](`${e}${o}`)}}),{})},c=O({}),W=r=>{c=r};var C=(r,t)=>r!=null&&Object.prototype.hasOwnProperty.call(r,t),h=(r,t)=>C(r,t)?r[t]:void 0,F=o=>{var f=o,{parser:r,key:t,params:e,translations:a,locale:n,fallbackLocale:s}=f,i=L(f,["parser","key","params","translations","locale","fallbackLocale"]);if(!t)return c.warn(`No translation key provided ('${n}' locale). Skipping translation...`),"";if(!n)return c.warn(`No locale provided for '${t}' key. Skipping translation...`),"";let T=h(a,n),u=h(T,t);if(s&&u===void 0){c.debug(`No translation provided for '${t}' key in locale '${n}'. Trying fallback '${s}'`);let x=h(a,s);u=h(x,t)}if(u===void 0){if(c.debug(`No translation provided for '${t}' key in fallback '${s}'.`),C(i,"fallbackValue"))return i.fallbackValue;c.warn(`No translation nor fallback found for '${t}' .`)}return!r||typeof r.parse!="function"?(c.debug(`No parser configured. Returning raw value for '${t}' key.`),u===void 0?t:u):r.parse(u,e,n,t)},b=(...r)=>r.length?r.filter(t=>!!t).map(t=>{let e=`${t}`.toLowerCase();try{let[a]=Intl.Collator.supportedLocalesOf(t);if(!a)throw new Error;e=a}catch(a){c.warn(`'${t}' locale is non-standard.`)}return e}):[],R=(r,t,e)=>{if(t&&Array.isArray(r))return r.map(a=>R(a,t));if(r&&typeof r=="object"){let a=Object.keys(r).reduce((n,s)=>{let i=r[s],o=e?`${e}.${s}`:`${s}`;return i&&typeof i=="object"&&!(t&&Array.isArray(i))?l(l({},n),R(i,t,o)):g(l({},n),{[o]:R(i,t)})},{});return Object.keys(a).length?a:null}return r},M=r=>r.reduce((t,{key:e,data:a,locale:n})=>{if(!a)return t;let[s]=b(n),i=g(l({},t[s]||{}),{[e]:a});return g(l({},t),{[s]:i})},{}),D=async r=>{let t=await Promise.all(r.map(async n=>{var s=n,{loader:e}=s,a=L(s,["loader"]);let i;try{i=await e()}catch(o){c.error(`Failed to load translation. Verify your '${a.locale}' > '${a.key}' Loader.`),c.error(o)}return g(l({loader:e},a),{data:i})}));return M(t)},I=r=>t=>{try{if(typeof t=="string")return t===r;if(typeof t=="object")return t.test(r)}catch(e){c.error("Invalid route config!")}return!1},K=(r,t)=>{let e=!0;try{e=Object.keys(r).filter(a=>r[a]!==void 0).every(a=>r[a]===t[a])}catch(a){}return e};var H=1e3*60*60*24,N= exports.default =class{constructor(t){this.cachedAt=0;this.loadedKeys={};this.currentRoute=_store.writable.call(void 0, );this.config=_store.writable.call(void 0, );this.isLoading=_store.writable.call(void 0, !1);this.promises=new Set;this.loading={subscribe:this.isLoading.subscribe,toPromise:(t,e)=>{let{fallbackLocale:a}=_store.get.call(void 0, this.config),n=Array.from(this.promises).filter(s=>{let i=K({locale:b(t)[0],route:e},s);return a&&(i=i||K({locale:b(a)[0],route:e},s)),i}).map(({promise:s})=>s);return Promise.all(n)},get:()=>_store.get.call(void 0, this.isLoading)};this.privateRawTranslations=_store.writable.call(void 0, {});this.rawTranslations={subscribe:this.privateRawTranslations.subscribe,get:()=>_store.get.call(void 0, this.rawTranslations)};this.privateTranslations=_store.writable.call(void 0, {});this.translations={subscribe:this.privateTranslations.subscribe,get:()=>_store.get.call(void 0, this.translations)};this.locales=g(l({},_store.derived.call(void 0, [this.config,this.privateTranslations],([t,e])=>{if(!t)return[];let{loaders:a=[]}=t,n=a.map(({locale:i})=>i),s=Object.keys(e).map(i=>i);return Array.from(new Set([...b(...n),...b(...s)]))},[])),{get:()=>_store.get.call(void 0, this.locales)});this.internalLocale=_store.writable.call(void 0, );this.loaderTrigger=_store.derived.call(void 0, [this.internalLocale,this.currentRoute],([t,e],a)=>{var n,s;t!==void 0&&e!==void 0&&!(t===((n=_store.get.call(void 0, this.loaderTrigger))==null?void 0:n[0])&&e===((s=_store.get.call(void 0, this.loaderTrigger))==null?void 0:s[1]))&&(c.debug("Triggering translation load..."),a([t,e]))},[]);this.localeHelper=_store.writable.call(void 0, );this.locale={subscribe:this.localeHelper.subscribe,forceSet:this.localeHelper.set,set:this.internalLocale.set,update:this.internalLocale.update,get:()=>_store.get.call(void 0, this.locale)};this.initialized=_store.derived.call(void 0, [this.locale,this.currentRoute,this.privateTranslations],([t,e,a],n)=>{_store.get.call(void 0, this.initialized)||n(t!==void 0&&e!==void 0&&!!Object.keys(a).length)});this.translation=_store.derived.call(void 0, [this.privateTranslations,this.locale,this.isLoading],([t,e,a],n)=>{let s=h(t,e);s&&Object.keys(s).length&&!a&&n(s)},{});this.t=g(l({},_store.derived.call(void 0, [this.config,this.translation],n=>{var[s={}]=n,i=s,{parser:t,fallbackLocale:e}=i,a=L(i,["parser","fallbackLocale"]);return(o,...f)=>F(l({parser:t,key:o,params:f,translations:this.translations.get(),locale:this.locale.get(),fallbackLocale:e},C(a,"fallbackValue")?{fallbackValue:a.fallbackValue}:{}))})),{get:(t,...e)=>_store.get.call(void 0, this.t)(t,...e)});this.l=g(l({},_store.derived.call(void 0, [this.config,this.translations],s=>{var[i={},...o]=s,f=i,{parser:t,fallbackLocale:e}=f,a=L(f,["parser","fallbackLocale"]),[n]=o;return(T,u,...x)=>F(l({parser:t,key:u,params:x,translations:n,locale:T,fallbackLocale:e},C(a,"fallbackValue")?{fallbackValue:a.fallbackValue}:{}))})),{get:(t,e,...a)=>_store.get.call(void 0, this.l)(t,e,...a)});this.getLocale=t=>{let{fallbackLocale:e}=_store.get.call(void 0, this.config)||{},a=t||e;if(!a)return;let n=this.locales.get();return n.find(i=>b(a).includes(i))||n.find(i=>b(e).includes(i))};this.setLocale=t=>{if(t&&t!==_store.get.call(void 0, this.internalLocale))return c.debug(`Setting '${t}' locale.`),this.internalLocale.set(t),this.loading.toPromise(t,_store.get.call(void 0, this.currentRoute))};this.setRoute=t=>{if(t!==_store.get.call(void 0, this.currentRoute)){c.debug(`Setting '${t}' route.`),this.currentRoute.set(t);let e=_store.get.call(void 0, this.internalLocale);return this.loading.toPromise(e,t)}};this.loadConfig=async t=>{await this.configLoader(t)};this.getTranslationProps=async(t=this.locale.get(),e=_store.get.call(void 0, this.currentRoute))=>{let a=_store.get.call(void 0, this.config);if(!a||!t)return[];let n=this.translations.get(),{loaders:s,fallbackLocale:i="",cache:o=H}=a||{},f=Number.isNaN(+o)?H:+o;this.cachedAt?Date.now()>f+this.cachedAt&&(c.debug("Refreshing cache."),this.loadedKeys={},this.cachedAt=0):(c.debug("Setting cache timestamp."),this.cachedAt=Date.now());let[T,u]=b(t,i),x=h(n,T),q=h(n,u),z=(s||[]).map(j=>{var y=j,{locale:p}=y,P=L(y,["locale"]);return g(l({},P),{locale:b(p)[0]})}).filter(({routes:p})=>!p||(p||[]).some(I(e))).filter(({key:p,locale:P})=>P===T&&(!x||!(h(this.loadedKeys,T)||[]).includes(p))||i&&P===u&&(!q||!(h(this.loadedKeys,u)||[]).includes(p)));if(z.length){this.isLoading.set(!0),c.debug("Fetching translations...");let p;try{p=await D(z)}finally{this.isLoading.set(!1)}let P=Object.keys(p).reduce((y,v)=>g(l({},y),{[v]:Object.keys(p[v])}),{}),j=z.filter(({key:y,locale:v})=>(h(P,v)||[]).some(k=>`${k}`.startsWith(y))).reduce((y,{key:v,locale:k})=>g(l({},y),{[k]:[...y[k]||[],v]}),{});return[p,j]}return[]};this.addTranslations=(t,e)=>{if(!t)return;let a=_store.get.call(void 0, this.config),{preprocess:n}=a||{};c.debug("Adding translations...");let s=Object.keys(t||{});this.privateRawTranslations.update(i=>s.reduce((o,f)=>g(l({},o),{[f]:l(l({},o[f]||{}),t[f])}),i)),this.privateTranslations.update(i=>s.reduce((o,f)=>{let T=!0,u=t[f];return typeof n=="function"&&(u=n(u)),(typeof n=="function"||n==="none")&&(T=!1),g(l({},o),{[f]:l(l({},o[f]||{}),T?R(u,n==="preserveArrays"):u)})},i)),s.forEach(i=>{let o=Object.keys(t[i]).map(f=>`${f}`.split(".")[0]);e&&(o=h(e,i)),this.loadedKeys[i]=Array.from(new Set([...h(this.loadedKeys,i)||[],...o||[]]))})};this.loader=async([t,e])=>{let a=this.getLocale(t)||void 0;c.debug(`Adding loader promise for '${a}' locale and '${e}' route.`);let n=(async()=>{let s=await this.getTranslationProps(a,e);s.length&&this.addTranslations(...s)})();this.promises.add({locale:a,route:e,promise:n}),n.then(()=>{a&&this.locale.get()!==a&&this.locale.forceSet(a)})};this.loadTranslations=(t,e=_store.get.call(void 0, this.currentRoute)||"")=>{let a=this.getLocale(t);if(a)return this.setRoute(e),this.setLocale(a),this.loading.toPromise(a,e)};this.loaderTrigger.subscribe(this.loader),this.isLoading.subscribe(async e=>{e&&this.promises.size&&(await this.loading.toPromise(),this.promises.clear(),c.debug("Loader promises have been purged."))}),t&&this.loadConfig(t)}async configLoader(t){if(!t)return c.error("No config provided!");let o=t,{initLocale:e,fallbackLocale:a,translations:n,log:s}=o,i=L(o,["initLocale","fallbackLocale","translations","log"]);s&&W(O(s)),[e]=b(e),[a]=b(a),c.debug("Setting config."),this.config.set(l({initLocale:e,fallbackLocale:a,translations:n},i)),n&&this.addTranslations(n),e&&await this.loadTranslations(e)}};exports.default = N;
package/dist/index.d.ts CHANGED
@@ -217,8 +217,7 @@ declare class I18n<ParserParams extends Parser.Params = any> {
217
217
  setRoute: (route: string) => Promise<void | void[]> | undefined;
218
218
  configLoader(config: Config.T<ParserParams>): Promise<void>;
219
219
  loadConfig: (config: Config.T<ParserParams>) => Promise<void>;
220
- getTranslationProps: ($locale?: string, $route?: string) => Promise<[Translations.SerializedTranslations, Loader.IndexedKeys] | [
221
- ]>;
220
+ getTranslationProps: ($locale?: string, $route?: string) => Promise<[Translations.SerializedTranslations, Loader.IndexedKeys] | []>;
222
221
  addTranslations: (translations?: Translations.SerializedTranslations, keys?: Loader.IndexedKeys) => void;
223
222
  private loader;
224
223
  loadTranslations: (locale: Config.Locale, route?: string) => Promise<void | void[]> | undefined;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var H=Object.defineProperty,q=Object.defineProperties;var B=Object.getOwnPropertyDescriptors;var x=Object.getOwnPropertySymbols;var A=Object.prototype.hasOwnProperty,N=Object.prototype.propertyIsEnumerable;var $=(r,t,e)=>t in r?H(r,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[t]=e,l=(r,t)=>{for(var e in t||(t={}))A.call(t,e)&&$(r,e,t[e]);if(x)for(var e of x(t))N.call(t,e)&&$(r,e,t[e]);return r},u=(r,t)=>q(r,B(t));var T=(r,t)=>{var e={};for(var a in r)A.call(r,a)&&t.indexOf(a)<0&&(e[a]=r[a]);if(r!=null&&x)for(var a of x(r))t.indexOf(a)<0&&N.call(r,a)&&(e[a]=r[a]);return e};import{derived as v,get as g,writable as m}from"svelte/store";var C=["error","warn","debug"],z=({logger:r=console,level:t=C[1],prefix:e="[i18n]: "})=>C.reduce((a,s,o)=>u(l({},a),{[s]:i=>C.indexOf(t)>=o&&r[s](`${e}${i}`)}),{}),d=z({}),V=r=>{d=r};var F=n=>{var c=n,{parser:r,key:t,params:e,translations:a,locale:s,fallbackLocale:o}=c,i=T(c,["parser","key","params","translations","locale","fallbackLocale"]);if(!t)return d.warn(`No translation key provided ('${s}' locale). Skipping translation...`),"";if(!s)return d.warn(`No locale provided for '${t}' key. Skipping translation...`),"";let f=(a[s]||{})[t];return o&&f===void 0&&(f=(a[o]||{})[t]),i.hasOwnProperty("fallbackValue")&&f===void 0?i.fallbackValue:r.parse(f,e,s,t)},h=(...r)=>r.length?r.filter(t=>!!t).map(t=>{let e=`${t}`.toLowerCase();try{let[a]=Intl.Collator.supportedLocalesOf(t);if(!a)throw new Error;e=a}catch(a){d.warn(`'${t}' locale is non-standard.`)}return e}):[],w=(r,t,e)=>{if(t&&Array.isArray(r))return r.map(a=>w(a,t));if(r&&typeof r=="object"){let a=Object.keys(r).reduce((s,o)=>{let i=r[o],n=e?`${e}.${o}`:`${o}`;return i&&typeof i=="object"&&!(t&&Array.isArray(i))?l(l({},s),w(i,t,n)):u(l({},s),{[n]:w(i,t)})},{});return Object.keys(a).length?a:null}return r},G=r=>r.reduce((t,{key:e,data:a,locale:s})=>{if(!a)return t;let[o]=h(s),i=u(l({},t[o]||{}),{[e]:a});return u(l({},t),{[o]:i})},{}),E=async r=>{try{let t=await Promise.all(r.map(s=>{var o=s,{loader:e}=o,a=T(o,["loader"]);return new Promise(async i=>{let n;try{n=await e()}catch(c){d.error(`Failed to load translation. Verify your '${a.locale}' > '${a.key}' Loader.`),d.error(c)}i(u(l({loader:e},a),{data:n}))})}));return G(t)}catch(t){d.error(t)}return{}},W=r=>t=>{try{if(typeof t=="string")return t===r;if(typeof t=="object")return t.test(r)}catch(e){d.error("Invalid route config!")}return!1},O=(r,t)=>{let e=!0;try{e=Object.keys(r).filter(a=>r[a]!==void 0).every(a=>r[a]===t[a])}catch(a){}return e};var D=1e3*60*60*24,j=class{constructor(t){this.cachedAt=0;this.loadedKeys={};this.currentRoute=m();this.config=m();this.isLoading=m(!1);this.promises=new Set;this.loading={subscribe:this.isLoading.subscribe,toPromise:(t,e)=>{let{fallbackLocale:a}=g(this.config),s=Array.from(this.promises).filter(o=>{let i=O({locale:h(t)[0],route:e},o);return a&&(i=i||O({locale:h(a)[0],route:e},o)),i}).map(({promise:o})=>o);return Promise.all(s)},get:()=>g(this.isLoading)};this.privateRawTranslations=m({});this.rawTranslations={subscribe:this.privateRawTranslations.subscribe,get:()=>g(this.rawTranslations)};this.privateTranslations=m({});this.translations={subscribe:this.privateTranslations.subscribe,get:()=>g(this.translations)};this.locales=u(l({},v([this.config,this.privateTranslations],([t,e])=>{if(!t)return[];let{loaders:a=[]}=t,s=a.map(({locale:i})=>i),o=Object.keys(e).map(i=>i);return Array.from(new Set([...h(...s),...h(...o)]))},[])),{get:()=>g(this.locales)});this.internalLocale=m();this.loaderTrigger=v([this.internalLocale,this.currentRoute],([t,e],a)=>{var s,o;t!==void 0&&e!==void 0&&!(t===((s=g(this.loaderTrigger))==null?void 0:s[0])&&e===((o=g(this.loaderTrigger))==null?void 0:o[1]))&&(d.debug("Triggering translation load..."),a([t,e]))},[]);this.localeHelper=m();this.locale={subscribe:this.localeHelper.subscribe,forceSet:this.localeHelper.set,set:this.internalLocale.set,update:this.internalLocale.update,get:()=>g(this.locale)};this.initialized=v([this.locale,this.currentRoute,this.privateTranslations],([t,e,a],s)=>{g(this.initialized)||s(t!==void 0&&e!==void 0&&!!Object.keys(a).length)});this.translation=v([this.privateTranslations,this.locale,this.isLoading],([t,e,a],s)=>{let o=t[e];o&&Object.keys(o).length&&!a&&s(o)},{});this.t=u(l({},v([this.config,this.translation],s=>{var[o]=s,i=o,{parser:t,fallbackLocale:e}=i,a=T(i,["parser","fallbackLocale"]);return(n,...c)=>F(l({parser:t,key:n,params:c,translations:this.translations.get(),locale:this.locale.get(),fallbackLocale:e},a.hasOwnProperty("fallbackValue")?{fallbackValue:a.fallbackValue}:{}))})),{get:(t,...e)=>g(this.t)(t,...e)});this.l=u(l({},v([this.config,this.translations],o=>{var[i,...n]=o,c=i,{parser:t,fallbackLocale:e}=c,a=T(c,["parser","fallbackLocale"]),[s]=n;return(f,b,...k)=>F(l({parser:t,key:b,params:k,translations:s,locale:f,fallbackLocale:e},a.hasOwnProperty("fallbackValue")?{fallbackValue:a.fallbackValue}:{}))})),{get:(t,e,...a)=>g(this.l)(t,e,...a)});this.getLocale=t=>{let{fallbackLocale:e}=g(this.config)||{},a=t||e;if(!a)return;let s=this.locales.get();return s.find(i=>h(a).includes(i))||s.find(i=>h(e).includes(i))};this.setLocale=t=>{if(t&&t!==g(this.internalLocale))return d.debug(`Setting '${t}' locale.`),this.internalLocale.set(t),this.loading.toPromise(t,g(this.currentRoute))};this.setRoute=t=>{if(t!==g(this.currentRoute)){d.debug(`Setting '${t}' route.`),this.currentRoute.set(t);let e=g(this.internalLocale);return this.loading.toPromise(e,t)}};this.loadConfig=async t=>{await this.configLoader(t)};this.getTranslationProps=async(t=this.locale.get(),e=g(this.currentRoute))=>{let a=g(this.config);if(!a||!t)return[];let s=this.translations.get(),{loaders:o,fallbackLocale:i="",cache:n=D}=a||{},c=Number.isNaN(+n)?D:+n;this.cachedAt?Date.now()>c+this.cachedAt&&(d.debug("Refreshing cache."),this.loadedKeys={},this.cachedAt=0):(d.debug("Setting cache timestamp."),this.cachedAt=Date.now());let[f,b]=h(t,i),k=s[f],I=s[b],R=(o||[]).map(K=>{var L=K,{locale:p}=L,y=T(L,["locale"]);return u(l({},y),{locale:h(p)[0]})}).filter(({routes:p})=>!p||(p||[]).some(W(e))).filter(({key:p,locale:y})=>y===f&&(!k||!(this.loadedKeys[f]||[]).includes(p))||i&&y===b&&(!I||!(this.loadedKeys[b]||[]).includes(p)));if(R.length){this.isLoading.set(!0),d.debug("Fetching translations...");let p=await E(R);this.isLoading.set(!1);let y=Object.keys(p).reduce((L,P)=>u(l({},L),{[P]:Object.keys(p[P])}),{}),K=R.filter(({key:L,locale:P})=>(y[P]||[]).some(S=>`${S}`.startsWith(L))).reduce((L,{key:P,locale:S})=>u(l({},L),{[S]:[...L[S]||[],P]}),{});return[p,K]}return[]};this.addTranslations=(t,e)=>{if(!t)return;let a=g(this.config),{preprocess:s}=a||{};d.debug("Adding translations...");let o=Object.keys(t||{});this.privateRawTranslations.update(i=>o.reduce((n,c)=>u(l({},n),{[c]:l(l({},n[c]||{}),t[c])}),i)),this.privateTranslations.update(i=>o.reduce((n,c)=>{let f=!0,b=t[c];return typeof s=="function"&&(b=s(b)),(typeof s=="function"||s==="none")&&(f=!1),u(l({},n),{[c]:l(l({},n[c]||{}),f?w(b,s==="preserveArrays"):b)})},i)),o.forEach(i=>{let n=Object.keys(t[i]).map(c=>`${c}`.split(".")[0]);e&&(n=e[i]),this.loadedKeys[i]=Array.from(new Set([...this.loadedKeys[i]||[],...n||[]]))})};this.loader=async([t,e])=>{let a=this.getLocale(t)||void 0;d.debug(`Adding loader promise for '${a}' locale and '${e}' route.`);let s=(async()=>{let o=await this.getTranslationProps(a,e);o.length&&this.addTranslations(...o)})();this.promises.add({locale:a,route:e,promise:s}),s.then(()=>{a&&this.locale.get()!==a&&this.locale.forceSet(a)})};this.loadTranslations=(t,e=g(this.currentRoute)||"")=>{let a=this.getLocale(t);if(a)return this.setRoute(e),this.setLocale(a),this.loading.toPromise(a,e)};this.loaderTrigger.subscribe(this.loader),this.isLoading.subscribe(async e=>{e&&this.promises.size&&(await this.loading.toPromise(),this.promises.clear(),d.debug("Loader promises have been purged."))}),t&&this.loadConfig(t)}async configLoader(t){if(!t)return d.error("No config provided!");let n=t,{initLocale:e,fallbackLocale:a,translations:s,log:o}=n,i=T(n,["initLocale","fallbackLocale","translations","log"]);o&&V(z(o)),[e]=h(e),[a]=h(a),d.debug("Setting config."),this.config.set(l({initLocale:e,fallbackLocale:a,translations:s},i)),s&&this.addTranslations(s),e&&await this.loadTranslations(e)}};export{j as default};
1
+ var B=Object.defineProperty,G=Object.defineProperties;var J=Object.getOwnPropertyDescriptors;var $=Object.getOwnPropertySymbols;var V=Object.prototype.hasOwnProperty,E=Object.prototype.propertyIsEnumerable;var A=(r,t,e)=>t in r?B(r,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[t]=e,l=(r,t)=>{for(var e in t||(t={}))V.call(t,e)&&A(r,e,t[e]);if($)for(var e of $(t))E.call(t,e)&&A(r,e,t[e]);return r},g=(r,t)=>G(r,J(t));var L=(r,t)=>{var e={};for(var a in r)V.call(r,a)&&t.indexOf(a)<0&&(e[a]=r[a]);if(r!=null&&$)for(var a of $(r))t.indexOf(a)<0&&E.call(r,a)&&(e[a]=r[a]);return e};import{derived as w,get as d,writable as m}from"svelte/store";var S=["error","warn","debug"],O=({logger:r=console,level:t=S[1],prefix:e="[i18n]: "})=>{let a=S.includes(t)?S.indexOf(t):S.indexOf("warn");return S.reduce((n,s,i)=>g(l({},n),{[s]:o=>{if(!(a<i)&&typeof r[s]=="function")return r[s](`${e}${o}`)}}),{})},c=O({}),W=r=>{c=r};var C=(r,t)=>r!=null&&Object.prototype.hasOwnProperty.call(r,t),h=(r,t)=>C(r,t)?r[t]:void 0,F=o=>{var f=o,{parser:r,key:t,params:e,translations:a,locale:n,fallbackLocale:s}=f,i=L(f,["parser","key","params","translations","locale","fallbackLocale"]);if(!t)return c.warn(`No translation key provided ('${n}' locale). Skipping translation...`),"";if(!n)return c.warn(`No locale provided for '${t}' key. Skipping translation...`),"";let T=h(a,n),u=h(T,t);if(s&&u===void 0){c.debug(`No translation provided for '${t}' key in locale '${n}'. Trying fallback '${s}'`);let x=h(a,s);u=h(x,t)}if(u===void 0){if(c.debug(`No translation provided for '${t}' key in fallback '${s}'.`),C(i,"fallbackValue"))return i.fallbackValue;c.warn(`No translation nor fallback found for '${t}' .`)}return!r||typeof r.parse!="function"?(c.debug(`No parser configured. Returning raw value for '${t}' key.`),u===void 0?t:u):r.parse(u,e,n,t)},b=(...r)=>r.length?r.filter(t=>!!t).map(t=>{let e=`${t}`.toLowerCase();try{let[a]=Intl.Collator.supportedLocalesOf(t);if(!a)throw new Error;e=a}catch(a){c.warn(`'${t}' locale is non-standard.`)}return e}):[],R=(r,t,e)=>{if(t&&Array.isArray(r))return r.map(a=>R(a,t));if(r&&typeof r=="object"){let a=Object.keys(r).reduce((n,s)=>{let i=r[s],o=e?`${e}.${s}`:`${s}`;return i&&typeof i=="object"&&!(t&&Array.isArray(i))?l(l({},n),R(i,t,o)):g(l({},n),{[o]:R(i,t)})},{});return Object.keys(a).length?a:null}return r},M=r=>r.reduce((t,{key:e,data:a,locale:n})=>{if(!a)return t;let[s]=b(n),i=g(l({},t[s]||{}),{[e]:a});return g(l({},t),{[s]:i})},{}),D=async r=>{let t=await Promise.all(r.map(async n=>{var s=n,{loader:e}=s,a=L(s,["loader"]);let i;try{i=await e()}catch(o){c.error(`Failed to load translation. Verify your '${a.locale}' > '${a.key}' Loader.`),c.error(o)}return g(l({loader:e},a),{data:i})}));return M(t)},I=r=>t=>{try{if(typeof t=="string")return t===r;if(typeof t=="object")return t.test(r)}catch(e){c.error("Invalid route config!")}return!1},K=(r,t)=>{let e=!0;try{e=Object.keys(r).filter(a=>r[a]!==void 0).every(a=>r[a]===t[a])}catch(a){}return e};var H=1e3*60*60*24,N=class{constructor(t){this.cachedAt=0;this.loadedKeys={};this.currentRoute=m();this.config=m();this.isLoading=m(!1);this.promises=new Set;this.loading={subscribe:this.isLoading.subscribe,toPromise:(t,e)=>{let{fallbackLocale:a}=d(this.config),n=Array.from(this.promises).filter(s=>{let i=K({locale:b(t)[0],route:e},s);return a&&(i=i||K({locale:b(a)[0],route:e},s)),i}).map(({promise:s})=>s);return Promise.all(n)},get:()=>d(this.isLoading)};this.privateRawTranslations=m({});this.rawTranslations={subscribe:this.privateRawTranslations.subscribe,get:()=>d(this.rawTranslations)};this.privateTranslations=m({});this.translations={subscribe:this.privateTranslations.subscribe,get:()=>d(this.translations)};this.locales=g(l({},w([this.config,this.privateTranslations],([t,e])=>{if(!t)return[];let{loaders:a=[]}=t,n=a.map(({locale:i})=>i),s=Object.keys(e).map(i=>i);return Array.from(new Set([...b(...n),...b(...s)]))},[])),{get:()=>d(this.locales)});this.internalLocale=m();this.loaderTrigger=w([this.internalLocale,this.currentRoute],([t,e],a)=>{var n,s;t!==void 0&&e!==void 0&&!(t===((n=d(this.loaderTrigger))==null?void 0:n[0])&&e===((s=d(this.loaderTrigger))==null?void 0:s[1]))&&(c.debug("Triggering translation load..."),a([t,e]))},[]);this.localeHelper=m();this.locale={subscribe:this.localeHelper.subscribe,forceSet:this.localeHelper.set,set:this.internalLocale.set,update:this.internalLocale.update,get:()=>d(this.locale)};this.initialized=w([this.locale,this.currentRoute,this.privateTranslations],([t,e,a],n)=>{d(this.initialized)||n(t!==void 0&&e!==void 0&&!!Object.keys(a).length)});this.translation=w([this.privateTranslations,this.locale,this.isLoading],([t,e,a],n)=>{let s=h(t,e);s&&Object.keys(s).length&&!a&&n(s)},{});this.t=g(l({},w([this.config,this.translation],n=>{var[s={}]=n,i=s,{parser:t,fallbackLocale:e}=i,a=L(i,["parser","fallbackLocale"]);return(o,...f)=>F(l({parser:t,key:o,params:f,translations:this.translations.get(),locale:this.locale.get(),fallbackLocale:e},C(a,"fallbackValue")?{fallbackValue:a.fallbackValue}:{}))})),{get:(t,...e)=>d(this.t)(t,...e)});this.l=g(l({},w([this.config,this.translations],s=>{var[i={},...o]=s,f=i,{parser:t,fallbackLocale:e}=f,a=L(f,["parser","fallbackLocale"]),[n]=o;return(T,u,...x)=>F(l({parser:t,key:u,params:x,translations:n,locale:T,fallbackLocale:e},C(a,"fallbackValue")?{fallbackValue:a.fallbackValue}:{}))})),{get:(t,e,...a)=>d(this.l)(t,e,...a)});this.getLocale=t=>{let{fallbackLocale:e}=d(this.config)||{},a=t||e;if(!a)return;let n=this.locales.get();return n.find(i=>b(a).includes(i))||n.find(i=>b(e).includes(i))};this.setLocale=t=>{if(t&&t!==d(this.internalLocale))return c.debug(`Setting '${t}' locale.`),this.internalLocale.set(t),this.loading.toPromise(t,d(this.currentRoute))};this.setRoute=t=>{if(t!==d(this.currentRoute)){c.debug(`Setting '${t}' route.`),this.currentRoute.set(t);let e=d(this.internalLocale);return this.loading.toPromise(e,t)}};this.loadConfig=async t=>{await this.configLoader(t)};this.getTranslationProps=async(t=this.locale.get(),e=d(this.currentRoute))=>{let a=d(this.config);if(!a||!t)return[];let n=this.translations.get(),{loaders:s,fallbackLocale:i="",cache:o=H}=a||{},f=Number.isNaN(+o)?H:+o;this.cachedAt?Date.now()>f+this.cachedAt&&(c.debug("Refreshing cache."),this.loadedKeys={},this.cachedAt=0):(c.debug("Setting cache timestamp."),this.cachedAt=Date.now());let[T,u]=b(t,i),x=h(n,T),q=h(n,u),z=(s||[]).map(j=>{var y=j,{locale:p}=y,P=L(y,["locale"]);return g(l({},P),{locale:b(p)[0]})}).filter(({routes:p})=>!p||(p||[]).some(I(e))).filter(({key:p,locale:P})=>P===T&&(!x||!(h(this.loadedKeys,T)||[]).includes(p))||i&&P===u&&(!q||!(h(this.loadedKeys,u)||[]).includes(p)));if(z.length){this.isLoading.set(!0),c.debug("Fetching translations...");let p;try{p=await D(z)}finally{this.isLoading.set(!1)}let P=Object.keys(p).reduce((y,v)=>g(l({},y),{[v]:Object.keys(p[v])}),{}),j=z.filter(({key:y,locale:v})=>(h(P,v)||[]).some(k=>`${k}`.startsWith(y))).reduce((y,{key:v,locale:k})=>g(l({},y),{[k]:[...y[k]||[],v]}),{});return[p,j]}return[]};this.addTranslations=(t,e)=>{if(!t)return;let a=d(this.config),{preprocess:n}=a||{};c.debug("Adding translations...");let s=Object.keys(t||{});this.privateRawTranslations.update(i=>s.reduce((o,f)=>g(l({},o),{[f]:l(l({},o[f]||{}),t[f])}),i)),this.privateTranslations.update(i=>s.reduce((o,f)=>{let T=!0,u=t[f];return typeof n=="function"&&(u=n(u)),(typeof n=="function"||n==="none")&&(T=!1),g(l({},o),{[f]:l(l({},o[f]||{}),T?R(u,n==="preserveArrays"):u)})},i)),s.forEach(i=>{let o=Object.keys(t[i]).map(f=>`${f}`.split(".")[0]);e&&(o=h(e,i)),this.loadedKeys[i]=Array.from(new Set([...h(this.loadedKeys,i)||[],...o||[]]))})};this.loader=async([t,e])=>{let a=this.getLocale(t)||void 0;c.debug(`Adding loader promise for '${a}' locale and '${e}' route.`);let n=(async()=>{let s=await this.getTranslationProps(a,e);s.length&&this.addTranslations(...s)})();this.promises.add({locale:a,route:e,promise:n}),n.then(()=>{a&&this.locale.get()!==a&&this.locale.forceSet(a)})};this.loadTranslations=(t,e=d(this.currentRoute)||"")=>{let a=this.getLocale(t);if(a)return this.setRoute(e),this.setLocale(a),this.loading.toPromise(a,e)};this.loaderTrigger.subscribe(this.loader),this.isLoading.subscribe(async e=>{e&&this.promises.size&&(await this.loading.toPromise(),this.promises.clear(),c.debug("Loader promises have been purged."))}),t&&this.loadConfig(t)}async configLoader(t){if(!t)return c.error("No config provided!");let o=t,{initLocale:e,fallbackLocale:a,translations:n,log:s}=o,i=L(o,["initLocale","fallbackLocale","translations","log"]);s&&W(O(s)),[e]=b(e),[a]=b(a),c.debug("Setting config."),this.config.set(l({initLocale:e,fallbackLocale:a,translations:n},i)),n&&this.addTranslations(n),e&&await this.loadTranslations(e)}};export{N as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltekit-i18n/base",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "description": "Base functionality of sveltekit-i18n library with a support for external message parsers.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -59,7 +59,7 @@
59
59
  "jest": "^29.6.0",
60
60
  "pre-commit": "^1.2.2",
61
61
  "ts-jest": "^29.1.1",
62
- "tsup": "^7.1.0",
62
+ "tsup": "^8.0.1",
63
63
  "typescript": "^5.1.6"
64
64
  }
65
65
  }