@sveltekit-i18n/base 3.1.0-next.2 → 3.1.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
@@ -228,11 +228,11 @@ A named capture group in a `RegExp` route is a load parameter: its match reaches
228
228
  locale: 'en',
229
229
  namespace: 'article',
230
230
  routes: [/^\/article\/(?<articleId>[^/]+)/],
231
- loader: async ({ locale, params }) => (await fetch(`/api/articles/${params.articleId}/i18n/${locale}`)).json(),
231
+ loader: async ({ locale, params }) => (await fetch(`${API_ORIGIN}/api/articles/${params.articleId}/i18n/${locale}`)).json(),
232
232
  }
233
233
  ```
234
234
 
235
- See [route params](./docs/README.md#route-params) for the rules.
235
+ `API_ORIGIN` stands for an origin such as `https://api.example.com`: a loader runs on the server too, where `fetch` takes only an absolute URL. See [route params](./docs/README.md#route-params) for the rules.
236
236
 
237
237
  A loader whose source does the caching itself — a SvelteKit remote `query`, an SWR layer, an HTTP cache — sets `cache: false`. It then runs on every load trigger that selects it, and `config.cache` does not apply to it; only a hydrated snapshot holds it back, for the locale and route it was rendered for. See [the loader's `cache`](./docs/README.md#cache-optional).
238
238
 
@@ -45,7 +45,7 @@ class I18nCore {
45
45
  // What each source last put into a namespace, so a loader whose params
46
46
  // changed can replace its own part and leave its siblings' in place. Kept
47
47
  // apart from the records: invalidation drops those, not what is displayed,
48
- // and a reconfiguration hands them on to the loaders with the same id.
48
+ // and a reconfiguration hands them on to the same loaders of the new config.
49
49
  #deliveries = new Map();
50
50
  #externalTranslations = {};
51
51
  // The params signature the next trigger asks each loader for:
@@ -561,18 +561,31 @@ class I18nCore {
561
561
  }
562
562
  /**
563
563
  * Gives each delivery of the previous config to the loader of the new one
564
- * with the same id, so its params can still replace it. What no loader can
565
- * take over is kept as data supplied without a loader, so a namespace rebuilt
566
- * later keeps it rather than losing it.
564
+ * with the same id, or else to the one loader that runs the same function
565
+ * for the same locale and namespace when no other delivery came from that
566
+ * function there: a `{ ...config, … }` hands its loaders over as they were,
567
+ * whatever became of their routes. Its params can then still replace it.
568
+ * What no loader can take over is kept as data supplied without a loader, so
569
+ * a namespace rebuilt later keeps it rather than losing it.
567
570
  */
568
571
  #handOnDeliveries(loaders) {
569
- const takers = new Map(loaders.flatMap((loader) => (loader.id === null ? [] : [[loader.id, loader]])));
572
+ const byId = new Map(loaders.flatMap((loader) => (loader.id === null ? [] : [[loader.id, loader]])));
570
573
  const deliveries = Array.from(this.#deliveries.values());
571
- const orphaned = deliveries.filter(({ loader }) => loader.id === null || !takers.has(loader.id));
572
- this.#deliveries = new Map(deliveries.flatMap((delivery) => {
573
- const taker = delivery.loader.id === null ? undefined : takers.get(delivery.loader.id);
574
- return taker ? [[taker, { ...delivery, loader: taker }]] : [];
574
+ const byIdTaken = new Map(deliveries.flatMap((delivery) => {
575
+ const taker = delivery.loader.id === null ? undefined : byId.get(delivery.loader.id);
576
+ return taker ? [[delivery, taker]] : [];
575
577
  }));
578
+ const free = loaders.filter((loader) => !Array.from(byIdTaken.values()).includes(loader));
579
+ const rest = deliveries.filter((delivery) => !byIdTaken.has(delivery));
580
+ const runsAs = (a) => (b) => a.loader === b.loader && a.locale === b.locale && a.namespace === b.namespace;
581
+ const byFunction = rest.flatMap((delivery) => {
582
+ const [only, ...more] = free.filter(runsAs(delivery.loader));
583
+ const alone = rest.filter((other) => runsAs(delivery.loader)(other.loader)).length === 1;
584
+ return only && !more.length && alone ? [[delivery, only]] : [];
585
+ });
586
+ const takers = new Map([...byIdTaken, ...byFunction]);
587
+ const orphaned = deliveries.filter((delivery) => !takers.has(delivery));
588
+ this.#deliveries = new Map(Array.from(takers, ([delivery, taker]) => [taker, { ...delivery, loader: taker }]));
576
589
  this.#keepExternal(serialize(orphaned.map(({ loader, data }) => ({ ...loader, data }))));
577
590
  }
578
591
  /**
@@ -53,9 +53,10 @@ export declare namespace Kit {
53
53
  * locale matches is skipped; a custom `sanitizeLocales` is applied to it
54
54
  * first. It runs on every navigation and every
55
55
  * preload, so it must be pure: it reads the event and writes nothing.
56
- * With a server load it runs on the server only: a navigation to a
57
- * prerendered page takes the locale it gave at build time, and otherwise
58
- * keeps the tab's.
56
+ * With a server load it runs in the browser only on a root error page
57
+ * rendered without the server's data (an unknown URL a static host answers
58
+ * with its fallback page): a navigation to a prerendered page takes the
59
+ * locale it gave at build time, and otherwise keeps the tab's.
59
60
  *
60
61
  * @example
61
62
  * preferredLocale: (event) => event.cookies?.get('lang')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltekit-i18n/base",
3
- "version": "3.1.0-next.2",
3
+ "version": "3.1.0",
4
4
  "description": "Base functionality of sveltekit-i18n library with a support for external message parsers.",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",