@i18n-micro/node 1.2.20 → 2.0.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2016
3
+ Copyright (c) 2024 s00d
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,44 +1,24 @@
1
1
  # @i18n-micro/node
2
2
 
3
- Node.js runtime for nuxt-i18n-micro — filesystem translation loading on top of [`@i18n-micro/runtime`](../runtime). Use this in Node.js applications, CLI tools, or backend services.
4
-
5
- For browser / vanilla JS without `fs`, use `@i18n-micro/runtime` directly.
6
-
7
- ## Installation
3
+ Node.js loader for Nuxt I18n Micro: reads a translation folder (`locales/en.json`, `locales/pages/<page>/en.json`) into an `@i18n-micro/runtime` instance, for servers, CLIs and generators. Node.js `>=20`.
8
4
 
9
5
  ```bash
10
6
  pnpm add @i18n-micro/node
11
- # or
12
- npm install @i18n-micro/node
13
- # or
14
- yarn add @i18n-micro/node
15
7
  ```
16
8
 
17
- ## Quick Start
18
-
19
- ```typescript
9
+ ```ts
20
10
  import { createI18n } from '@i18n-micro/node'
21
11
 
22
- // 1. Create I18n instance
23
- const i18n = createI18n({
24
- locale: 'en',
25
- fallbackLocale: 'en',
26
- translationDir: './locales', // Path to your locales directory
27
- disablePageLocales: false, // If true, ignores pages/ folder and treats all files as global translations
28
- })
29
-
30
- // 2. Load translations from directory (recursive, supports pages structure)
12
+ const i18n = createI18n({ locale: 'en', fallbackLocale: 'en', translationDir: './locales' })
31
13
  await i18n.loadTranslations()
32
14
 
33
- // 3. Use translations
34
- console.log(i18n.t('greeting', { name: 'John' })) // "Hello, John!"
35
- console.log(i18n.tc('apples', 5)) // "5 apples"
15
+ i18n.t('greeting', { name: 'Ada' })
16
+ i18n.t('title', undefined, undefined, 'blog-post') // locales/pages/blog/post/en.json
36
17
  ```
37
18
 
38
- ## Resources
19
+ Per request, `i18n.run(locale, () => next())` gives everything the request awaits its own locale and route; `i18n.fork(locale)` returns such an instance to pass around.
39
20
 
40
- - **Repository**: [https://github.com/s00d/nuxt-i18n-micro](https://github.com/s00d/nuxt-i18n-micro)
41
- - **Documentation**: [https://s00d.github.io/nuxt-i18n-micro/](https://s00d.github.io/nuxt-i18n-micro/)
21
+ Docs: [https://s00d.github.io/nuxt-i18n-micro/integrations/nodejs-package](https://s00d.github.io/nuxt-i18n-micro/integrations/nodejs-package) · Repository: [github.com/s00d/nuxt-i18n-micro](https://github.com/s00d/nuxt-i18n-micro)
42
22
 
43
23
  ## License
44
24
 
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@i18n-micro/runtime"),t=require("@i18n-micro/utils/parse-path"),n=require("node:fs/promises"),r=require("node:path"),i=require("@i18n-micro/core");async function a(e,i=!1){let a={root:{},routes:{}};try{let o=(await(0,n.readdir)(e,{recursive:!0,withFileTypes:!0})).filter(e=>e.isFile()&&e.name.endsWith(`.json`)),s=await Promise.all(o.map(async t=>{let i=(0,r.join)(t.path,t.name),a=(0,r.relative)(e,i).split(r.sep).join(`/`);try{let e=await(0,n.readFile)(i,`utf-8`);return{relativePath:a,translations:JSON.parse(e)}}catch(e){return console.error(`Failed to load translation file ${i}:`,e),null}}));for(let e of s)e&&(0,t.storeLoadedTranslationFile)(a,e.relativePath,e.translations,i)}catch(t){t&&typeof t==`object`&&`code`in t&&t.code!==`ENOENT`&&console.error(`Failed to read directory ${e}:`,t)}return a}async function o(e,t=!1){let{root:n}=await a(e,t);return n}var s=class extends e.I18n{constructor(e){let{translationDir:t,disablePageLocales:n,...r}=e;super(r),this.translationDir=t,this.disablePageLocales=n??!1}async loadTranslations(e){let n=e||this.translationDir;if(!n){console.warn(`[i18n-node] No translation directory specified`);return}let{root:r,routes:i}=await a(n,this.disablePageLocales);for(let[e,t]of Object.entries(r))this.helper.mergeTranslation(e,`index`,t,!0);for(let[e,n]of Object.entries(i))for(let[r,i]of Object.entries(n)){let n=this.helper.getCache(r,`index`);this.helper.loadPageTranslations(r,e,(0,t.mergeRouteTranslationsWithRoot)(n,i))}this.onTranslationsChanged()}async reload(){let e=this.translationDir;if(!e){console.warn(`[i18n-node] No translation directory specified`);return}this.clearCache(),await this.loadTranslations(e),console.log(`[i18n-node] Cache cleared and translations reloaded.`)}};function c(e){return new s(e)}Object.defineProperty(exports,"FormatService",{enumerable:!0,get:function(){return i.FormatService}}),exports.I18n=s,exports.createI18n=c,Object.defineProperty(exports,"interpolate",{enumerable:!0,get:function(){return i.interpolate}}),exports.loadRootTranslations=o,exports.loadTranslations=a;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("node:async_hooks"),t=require("node:fs"),n=require("@i18n-micro/runtime"),r=require("@i18n-micro/utils/load-dir"),i=require("@i18n-micro/core");function a(e,t=!1){return(0,r.loadTranslationDirAsync)(e,t)}async function o(e,t=!1){let{root:n}=await a(e,t);return n}var s=class extends n.I18n{constructor(t){let{translationDir:n,disablePageLocales:r,...i}=t;super(i);let a=t.parent;this.translationDir=n??a?.translationDir,this.disablePageLocales=r??a?.disablePageLocales??!1,this.scope=a?.scope??new e.AsyncLocalStorage,this.forked=a!==void 0}get store(){return this.forked?this.ownStore:this.scope?.getStore()?.ownStore??this.ownStore}run(e,t){let n=this.fork(e);return this.scope.run(n,t,n)}async loadTranslations(e){let t=e||this.translationDir;if(!t){console.warn(`[i18n-node] No translation directory specified`);return}let{root:n,routes:r}=await a(t,this.disablePageLocales);this.loadMessages(n,r)}async reload(){let e=this.translationDir;if(!e){console.warn(`[i18n-node] No translation directory specified`);return}let{root:n,routes:r}=await a(e,this.disablePageLocales);(0,t.existsSync)(e)&&(this.clearCache(),this.loadMessages(n,r))}};function c(e){return new s(e)}Object.defineProperty(exports,"FormatService",{enumerable:!0,get:function(){return i.FormatService}}),exports.I18n=s,exports.createI18n=c,Object.defineProperty(exports,"interpolate",{enumerable:!0,get:function(){return i.interpolate}}),exports.loadRootTranslations=o,exports.loadTranslations=a,Object.defineProperty(exports,"localeIsoMap",{enumerable:!0,get:function(){return i.localeIsoMap}});
package/dist/index.d.cts CHANGED
@@ -6,8 +6,10 @@ import { I18nOptions as I18nOptions_2 } from '@i18n-micro/runtime';
6
6
  import { interpolate } from '@i18n-micro/core';
7
7
  import { Locale } from '@i18n-micro/types';
8
8
  import { LocaleCode } from '@i18n-micro/types';
9
+ import { localeIsoMap } from '@i18n-micro/core';
9
10
  import { Params } from '@i18n-micro/types';
10
11
  import { PluralFunc } from '@i18n-micro/types';
12
+ import { ReactiveI18nStore } from '@i18n-micro/core';
11
13
  import { TranslationFileBuckets } from '@i18n-micro/utils/parse-path';
12
14
  import { Translations } from '@i18n-micro/types';
13
15
 
@@ -22,8 +24,20 @@ export { Getter }
22
24
  export declare class I18n extends I18n_2 {
23
25
  translationDir?: string;
24
26
  private disablePageLocales;
27
+ /** The request's fork; shared with forks, so `run` works from any of them. */
28
+ private readonly scope;
29
+ private readonly forked;
25
30
  constructor(options: I18nOptions);
31
+ /** Inside `run`, the shared instance answers with the request's locale and route. A fork always answers with its own. */
32
+ protected get store(): ReactiveI18nStore;
33
+ /**
34
+ * Runs `fn` with a fork for `locale` as the current request: until `fn` and everything it awaits
35
+ * finish, this instance reads and sets that fork's locale and route. `fn` also gets the fork.
36
+ * ponytail: dictionary writes go to the instance they are called on; write to the fork for request-only keys.
37
+ */
38
+ run<T>(locale: string, fn: (i18n: this) => T): T;
26
39
  loadTranslations(dir?: string): Promise<void>;
40
+ /** Re-reads the directory. The old dictionaries answer until the new ones are in, so no request sees an empty instance. */
27
41
  reload(): Promise<void>;
28
42
  }
29
43
 
@@ -57,6 +71,8 @@ export { Locale }
57
71
 
58
72
  export { LocaleCode }
59
73
 
74
+ export { localeIsoMap }
75
+
60
76
  export { Params }
61
77
 
62
78
  export { PluralFunc }
package/dist/index.d.ts CHANGED
@@ -6,8 +6,10 @@ import { I18nOptions as I18nOptions_2 } from '@i18n-micro/runtime';
6
6
  import { interpolate } from '@i18n-micro/core';
7
7
  import { Locale } from '@i18n-micro/types';
8
8
  import { LocaleCode } from '@i18n-micro/types';
9
+ import { localeIsoMap } from '@i18n-micro/core';
9
10
  import { Params } from '@i18n-micro/types';
10
11
  import { PluralFunc } from '@i18n-micro/types';
12
+ import { ReactiveI18nStore } from '@i18n-micro/core';
11
13
  import { TranslationFileBuckets } from '@i18n-micro/utils/parse-path';
12
14
  import { Translations } from '@i18n-micro/types';
13
15
 
@@ -22,8 +24,20 @@ export { Getter }
22
24
  export declare class I18n extends I18n_2 {
23
25
  translationDir?: string;
24
26
  private disablePageLocales;
27
+ /** The request's fork; shared with forks, so `run` works from any of them. */
28
+ private readonly scope;
29
+ private readonly forked;
25
30
  constructor(options: I18nOptions);
31
+ /** Inside `run`, the shared instance answers with the request's locale and route. A fork always answers with its own. */
32
+ protected get store(): ReactiveI18nStore;
33
+ /**
34
+ * Runs `fn` with a fork for `locale` as the current request: until `fn` and everything it awaits
35
+ * finish, this instance reads and sets that fork's locale and route. `fn` also gets the fork.
36
+ * ponytail: dictionary writes go to the instance they are called on; write to the fork for request-only keys.
37
+ */
38
+ run<T>(locale: string, fn: (i18n: this) => T): T;
26
39
  loadTranslations(dir?: string): Promise<void>;
40
+ /** Re-reads the directory. The old dictionaries answer until the new ones are in, so no request sees an empty instance. */
27
41
  reload(): Promise<void>;
28
42
  }
29
43
 
@@ -57,6 +71,8 @@ export { Locale }
57
71
 
58
72
  export { LocaleCode }
59
73
 
74
+ export { localeIsoMap }
75
+
60
76
  export { Params }
61
77
 
62
78
  export { PluralFunc }
package/dist/index.mjs CHANGED
@@ -1,60 +1,39 @@
1
- import { I18n as e } from "@i18n-micro/runtime";
2
- import { mergeRouteTranslationsWithRoot as t, storeLoadedTranslationFile as n } from "@i18n-micro/utils/parse-path";
3
- import { readFile as r, readdir as i } from "node:fs/promises";
4
- import { join as a, relative as o, sep as s } from "node:path";
5
- import { FormatService as c, interpolate as l } from "@i18n-micro/core";
6
- //#region src/loader.ts
7
- async function u(e, t = !1) {
8
- let c = {
9
- root: {},
10
- routes: {}
11
- };
12
- try {
13
- let l = (await i(e, {
14
- recursive: !0,
15
- withFileTypes: !0
16
- })).filter((e) => e.isFile() && e.name.endsWith(".json")), u = await Promise.all(l.map(async (t) => {
17
- let n = a(t.path, t.name), i = o(e, n).split(s).join("/");
18
- try {
19
- let e = await r(n, "utf-8");
20
- return {
21
- relativePath: i,
22
- translations: JSON.parse(e)
23
- };
24
- } catch (e) {
25
- return console.error(`Failed to load translation file ${n}:`, e), null;
26
- }
27
- }));
28
- for (let e of u) e && n(c, e.relativePath, e.translations, t);
29
- } catch (t) {
30
- t && typeof t == "object" && "code" in t && t.code !== "ENOENT" && console.error(`Failed to read directory ${e}:`, t);
31
- }
32
- return c;
1
+ import { AsyncLocalStorage as e } from "node:async_hooks";
2
+ import { existsSync as t } from "node:fs";
3
+ import { I18n as n } from "@i18n-micro/runtime";
4
+ import { loadTranslationDirAsync as r } from "@i18n-micro/utils/load-dir";
5
+ import { FormatService as i, interpolate as a, localeIsoMap as o } from "@i18n-micro/core";
6
+ // src/loader.ts
7
+ function s(e, t = !1) {
8
+ return r(e, t);
33
9
  }
34
- async function d(e, t = !1) {
35
- let { root: n } = await u(e, t);
10
+ async function c(e, t = !1) {
11
+ let { root: n } = await s(e, t);
36
12
  return n;
37
13
  }
38
- //#endregion
39
- //#region src/i18n.ts
40
- var f = class extends e {
41
- constructor(e) {
42
- let { translationDir: t, disablePageLocales: n, ...r } = e;
43
- super(r), this.translationDir = t, this.disablePageLocales = n ?? !1;
14
+ // src/i18n.ts
15
+ var l = class extends n {
16
+ constructor(t) {
17
+ let { translationDir: n, disablePageLocales: r, ...i } = t;
18
+ super(i);
19
+ let a = t.parent;
20
+ this.translationDir = n ?? a?.translationDir, this.disablePageLocales = r ?? a?.disablePageLocales ?? !1, this.scope = a?.scope ?? new e(), this.forked = a !== void 0;
21
+ }
22
+ get store() {
23
+ return this.forked ? this.ownStore : this.scope?.getStore()?.ownStore ?? this.ownStore;
24
+ }
25
+ run(e, t) {
26
+ let n = this.fork(e);
27
+ return this.scope.run(n, t, n);
44
28
  }
45
29
  async loadTranslations(e) {
46
- let n = e || this.translationDir;
47
- if (!n) {
30
+ let t = e || this.translationDir;
31
+ if (!t) {
48
32
  console.warn("[i18n-node] No translation directory specified");
49
33
  return;
50
34
  }
51
- let { root: r, routes: i } = await u(n, this.disablePageLocales);
52
- for (let [e, t] of Object.entries(r)) this.helper.mergeTranslation(e, "index", t, !0);
53
- for (let [e, n] of Object.entries(i)) for (let [r, i] of Object.entries(n)) {
54
- let n = this.helper.getCache(r, "index");
55
- this.helper.loadPageTranslations(r, e, t(n, i));
56
- }
57
- this.onTranslationsChanged();
35
+ let { root: n, routes: r } = await s(t, this.disablePageLocales);
36
+ this.loadMessages(n, r);
58
37
  }
59
38
  async reload() {
60
39
  let e = this.translationDir;
@@ -62,11 +41,11 @@ var f = class extends e {
62
41
  console.warn("[i18n-node] No translation directory specified");
63
42
  return;
64
43
  }
65
- this.clearCache(), await this.loadTranslations(e), console.log("[i18n-node] Cache cleared and translations reloaded.");
44
+ let { root: n, routes: r } = await s(e, this.disablePageLocales);
45
+ t(e) && (this.clearCache(), this.loadMessages(n, r));
66
46
  }
67
47
  };
68
- function p(e) {
69
- return new f(e);
48
+ function u(e) {
49
+ return new l(e);
70
50
  }
71
- //#endregion
72
- export { c as FormatService, f as I18n, p as createI18n, l as interpolate, d as loadRootTranslations, u as loadTranslations };
51
+ export { i as FormatService, l as I18n, u as createI18n, a as interpolate, c as loadRootTranslations, s as loadTranslations, o as localeIsoMap };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@i18n-micro/node",
3
- "version": "1.2.20",
3
+ "version": "2.0.0",
4
4
  "description": "Node.js utilities for loading translations and locale data in Nuxt I18n Micro.",
5
5
  "keywords": [
6
6
  "i18n",
@@ -13,6 +13,11 @@
13
13
  "url": "https://github.com/s00d/nuxt-i18n-micro/issues"
14
14
  },
15
15
  "license": "MIT",
16
+ "author": {
17
+ "name": "s00d",
18
+ "email": "Virus191288@gmail.com",
19
+ "url": "https://s00d.github.io/"
20
+ },
16
21
  "repository": {
17
22
  "type": "git",
18
23
  "url": "git+https://github.com/s00d/nuxt-i18n-micro.git",
@@ -45,25 +50,25 @@
45
50
  "access": "public"
46
51
  },
47
52
  "dependencies": {
48
- "@i18n-micro/core": "^1.3.21",
49
- "@i18n-micro/types": "^1.2.17",
50
- "@i18n-micro/runtime": "^1.0.4",
51
- "@i18n-micro/utils": "^1.0.26"
53
+ "@i18n-micro/core": "^2.0.0",
54
+ "@i18n-micro/runtime": "^2.0.0",
55
+ "@i18n-micro/types": "^2.0.0",
56
+ "@i18n-micro/utils": "^2.0.0"
52
57
  },
53
58
  "devDependencies": {
54
59
  "@types/node": "^22.19.0",
55
- "publint": "^0.3.24",
56
- "vite": "^8.3.1",
57
- "vite-plugin-dts": "^5.1.1",
58
- "vitest": "^5.0.2"
60
+ "publint": "^0.3.25",
61
+ "vite": "^8.3.5",
62
+ "vite-plugin-dts": "^5.1.2",
63
+ "vitest": "^5.1.0"
59
64
  },
60
65
  "engines": {
61
- "node": ">=20.0.0"
66
+ "node": ">=20"
62
67
  },
63
68
  "scripts": {
64
69
  "build": "vite build",
65
70
  "check:package": "publint",
66
- "dev": "cd playground && npm run dev",
71
+ "dev": "pnpm --dir playground dev",
67
72
  "test": "vitest run",
68
73
  "typecheck": "tsc --noEmit"
69
74
  }