@things-factory/i18n-base 10.1.147 → 10.1.150

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.
@@ -2,6 +2,8 @@ import './routes';
2
2
  export * from './service';
3
3
  export * from './apis';
4
4
  export * from './middlewares';
5
+ export { translatorFor, loadTranslations } from './translator';
6
+ export type { Translate } from './translator';
5
7
  export * from './controllers/clear-cache-for-translation.js';
6
8
  export * from './ai-entry/terminology-entry-targets';
7
9
  export type { EntryTargetDeclaration as TerminologyEntryTarget } from './ai-entry/entry-target-shape';
@@ -1,10 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadTranslations = exports.translatorFor = void 0;
3
4
  const tslib_1 = require("tslib");
4
5
  require("./routes");
5
6
  tslib_1.__exportStar(require("./service"), exports);
6
7
  tslib_1.__exportStar(require("./apis"), exports);
7
8
  tslib_1.__exportStar(require("./middlewares"), exports);
9
+ var translator_1 = require("./translator");
10
+ Object.defineProperty(exports, "translatorFor", { enumerable: true, get: function () { return translator_1.translatorFor; } });
11
+ Object.defineProperty(exports, "loadTranslations", { enumerable: true, get: function () { return translator_1.loadTranslations; } });
8
12
  tslib_1.__exportStar(require("./controllers/clear-cache-for-translation.js"), exports);
9
13
  tslib_1.__exportStar(require("./ai-entry/terminology-entry-targets"), exports);
10
14
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;AAAA,oBAAiB;AAEjB,oDAAyB;AACzB,iDAAsB;AACtB,wDAA6B;AAC7B,uFAA4D;AAC5D,+EAAoD","sourcesContent":["import './routes'\n\nexport * from './service'\nexport * from './apis'\nexport * from './middlewares'\nexport * from './controllers/clear-cache-for-translation.js'\nexport * from './ai-entry/terminology-entry-targets'\nexport type { EntryTargetDeclaration as TerminologyEntryTarget } from './ai-entry/entry-target-shape'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;;AAAA,oBAAiB;AAEjB,oDAAyB;AACzB,iDAAsB;AACtB,wDAA6B;AAC7B,2CAA8D;AAArD,2GAAA,aAAa,OAAA;AAAE,8GAAA,gBAAgB,OAAA;AAExC,uFAA4D;AAC5D,+EAAoD","sourcesContent":["import './routes'\n\nexport * from './service'\nexport * from './apis'\nexport * from './middlewares'\nexport { translatorFor, loadTranslations } from './translator'\nexport type { Translate } from './translator'\nexport * from './controllers/clear-cache-for-translation.js'\nexport * from './ai-entry/terminology-entry-targets'\nexport type { EntryTargetDeclaration as TerminologyEntryTarget } from './ai-entry/entry-target-shape'\n"]}
@@ -2,30 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.initMiddlewares = initMiddlewares;
4
4
  const tslib_1 = require("tslib");
5
- const fs_1 = tslib_1.__importDefault(require("fs"));
6
- const i18next_1 = tslib_1.__importDefault(require("i18next"));
7
5
  const koa_i18next_1 = tslib_1.__importDefault(require("./koa-i18next"));
8
- const translations_1 = require("./translations");
9
- i18next_1.default.init({
10
- debug: false,
11
- ns: ['translations'],
12
- defaultNS: 'translations',
13
- preload: ['ko', 'en', 'ja', 'zh', 'ms', 'es'],
14
- fallbackLng: 'en',
15
- interpolation: {
16
- prefix: '{',
17
- suffix: '}'
18
- },
19
- load: 'languageOnly',
20
- keySeparator: false
21
- });
22
- (0, translations_1.build)(fs_1.default);
23
- process.on('client-rebuilt', (app, fs) => {
24
- /* rebuild once done webpacking assets. only for development mode. */
25
- (0, translations_1.build)(fs);
6
+ const translator_1 = require("../translator");
7
+ process.on('client-rebuilt', () => {
8
+ /* A dev build ran — the sources may have changed. Reload from them, not from what webpack wrote. */
9
+ (0, translator_1.loadTranslations)();
26
10
  });
27
11
  function initMiddlewares(app) {
28
- app.use((0, koa_i18next_1.default)(i18next_1.default, {
12
+ app.use((0, koa_i18next_1.default)(translator_1.i18next, {
29
13
  lookupCookie: 'i18next',
30
14
  order: ['cookie', 'header'],
31
15
  next: true // if koa is version 2
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/middlewares/index.ts"],"names":[],"mappings":";;AA2BA,0CAQC;;AAnCD,oDAAmB;AACnB,8DAA6B;AAE7B,wEAAsC;AACtC,iDAAsC;AAEtC,iBAAO,CAAC,IAAI,CAAC;IACX,KAAK,EAAE,KAAK;IACZ,EAAE,EAAE,CAAC,cAAc,CAAC;IACpB,SAAS,EAAE,cAAc;IACzB,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;IAC7C,WAAW,EAAE,IAAI;IACjB,aAAa,EAAE;QACb,MAAM,EAAE,GAAG;QACX,MAAM,EAAE,GAAG;KACZ;IACD,IAAI,EAAE,cAAc;IACpB,YAAY,EAAE,KAAK;CACpB,CAAC,CAAA;AAEF,IAAA,oBAAK,EAAC,YAAE,CAAC,CAAA;AAET,OAAO,CAAC,EAAE,CAAC,gBAAuB,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE;IAC9C,qEAAqE;IACrE,IAAA,oBAAK,EAAC,EAAE,CAAC,CAAA;AACX,CAAC,CAAC,CAAA;AAEF,SAAgB,eAAe,CAAC,GAAQ;IACtC,GAAG,CAAC,GAAG,CACL,IAAA,qBAAU,EAAC,iBAAO,EAAE;QAClB,YAAY,EAAE,SAAS;QACvB,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC;QAC3B,IAAI,EAAE,IAAI,CAAC,sBAAsB;KAClC,CAAC,CACH,CAAA;AACH,CAAC","sourcesContent":["import fs from 'fs'\nimport i18next from 'i18next'\n\nimport koaI18next from './koa-i18next'\nimport { build } from './translations'\n\ni18next.init({\n debug: false,\n ns: ['translations'],\n defaultNS: 'translations',\n preload: ['ko', 'en', 'ja', 'zh', 'ms', 'es'],\n fallbackLng: 'en',\n interpolation: {\n prefix: '{',\n suffix: '}'\n },\n load: 'languageOnly',\n keySeparator: false\n})\n\nbuild(fs)\n\nprocess.on('client-rebuilt' as any, (app, fs) => {\n /* rebuild once done webpacking assets. only for development mode. */\n build(fs)\n})\n\nexport function initMiddlewares(app: any) {\n app.use(\n koaI18next(i18next, {\n lookupCookie: 'i18next',\n order: ['cookie', 'header'],\n next: true // if koa is version 2\n })\n )\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/middlewares/index.ts"],"names":[],"mappings":";;AAQA,0CAQC;;AAhBD,wEAAsC;AACtC,8CAAyD;AAEzD,OAAO,CAAC,EAAE,CAAC,gBAAuB,EAAE,GAAG,EAAE;IACvC,oGAAoG;IACpG,IAAA,6BAAgB,GAAE,CAAA;AACpB,CAAC,CAAC,CAAA;AAEF,SAAgB,eAAe,CAAC,GAAQ;IACtC,GAAG,CAAC,GAAG,CACL,IAAA,qBAAU,EAAC,oBAAO,EAAE;QAClB,YAAY,EAAE,SAAS;QACvB,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC;QAC3B,IAAI,EAAE,IAAI,CAAC,sBAAsB;KAClC,CAAC,CACH,CAAA;AACH,CAAC","sourcesContent":["import koaI18next from './koa-i18next'\nimport { i18next, loadTranslations } from '../translator'\n\nprocess.on('client-rebuilt' as any, () => {\n /* A dev build ran — the sources may have changed. Reload from them, not from what webpack wrote. */\n loadTranslations()\n})\n\nexport function initMiddlewares(app: any) {\n app.use(\n koaI18next(i18next, {\n lookupCookie: 'i18next',\n order: ['cookie', 'header'],\n next: true // if koa is version 2\n })\n )\n}\n"]}
@@ -0,0 +1,29 @@
1
+ import i18next from 'i18next';
2
+ /**
3
+ * The server's translations — loaded from the sources, not from the webpack output.
4
+ *
5
+ * ── What was wrong (2026-10-11) ──────────────────────────────────────────
6
+ * The server read only `dist-app/translations`, which webpack writes. A test run never has it, and a
7
+ * dev server has it only after its first webpack pass. Server code that froze a sentence before then
8
+ * got the key back. The sources are every module's `translations/` folder and the application's own,
9
+ * merged by the same rule the bundler uses (`collectTranslations` in env).
10
+ *
11
+ * This file is light on purpose — no routes, no entities — so server code and tests can take a
12
+ * translator without loading the whole module (`@things-factory/i18n-base/translator`).
13
+ */
14
+ export declare const NAMESPACE = "translations";
15
+ /** Load every locale from the sources. Called once here, and again when a dev build changes them. */
16
+ export declare function loadTranslations(): void;
17
+ export type Translate = (key: string, options?: {
18
+ [name: string]: unknown;
19
+ }) => string;
20
+ /**
21
+ * A translator for one language that **does not fall back** to another.
22
+ *
23
+ * A request's translator falls back to English, which is right for a screen. A sentence the server
24
+ * stores is not: an English sentence filed as the Korean one is wrong and nobody sees why. So a key
25
+ * missing in this language — with its `context` form and without — answers `options.defaultValue`,
26
+ * and the caller decides what that means.
27
+ */
28
+ export declare function translatorFor(lng: string): Translate;
29
+ export { i18next };
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.i18next = exports.NAMESPACE = void 0;
4
+ exports.loadTranslations = loadTranslations;
5
+ exports.translatorFor = translatorFor;
6
+ const tslib_1 = require("tslib");
7
+ const i18next_1 = tslib_1.__importDefault(require("i18next"));
8
+ exports.i18next = i18next_1.default;
9
+ const env_1 = require("@things-factory/env");
10
+ /**
11
+ * The server's translations — loaded from the sources, not from the webpack output.
12
+ *
13
+ * ── What was wrong (2026-10-11) ──────────────────────────────────────────
14
+ * The server read only `dist-app/translations`, which webpack writes. A test run never has it, and a
15
+ * dev server has it only after its first webpack pass. Server code that froze a sentence before then
16
+ * got the key back. The sources are every module's `translations/` folder and the application's own,
17
+ * merged by the same rule the bundler uses (`collectTranslations` in env).
18
+ *
19
+ * This file is light on purpose — no routes, no entities — so server code and tests can take a
20
+ * translator without loading the whole module (`@things-factory/i18n-base/translator`).
21
+ */
22
+ exports.NAMESPACE = 'translations';
23
+ i18next_1.default.init({
24
+ initImmediate: false,
25
+ debug: false,
26
+ ns: [exports.NAMESPACE],
27
+ defaultNS: exports.NAMESPACE,
28
+ preload: ['ko', 'en', 'ja', 'zh', 'ms', 'es'],
29
+ fallbackLng: 'en',
30
+ interpolation: {
31
+ prefix: '{',
32
+ suffix: '}'
33
+ },
34
+ load: 'languageOnly',
35
+ keySeparator: false
36
+ });
37
+ /** Load every locale from the sources. Called once here, and again when a dev build changes them. */
38
+ function loadTranslations() {
39
+ const all = (0, env_1.collectTranslations)(exports.NAMESPACE);
40
+ for (const lng of Object.keys(all)) {
41
+ i18next_1.default.removeResourceBundle(lng, exports.NAMESPACE);
42
+ i18next_1.default.addResourceBundle(lng, exports.NAMESPACE, all[lng], true, true);
43
+ }
44
+ }
45
+ loadTranslations();
46
+ /**
47
+ * A translator for one language that **does not fall back** to another.
48
+ *
49
+ * A request's translator falls back to English, which is right for a screen. A sentence the server
50
+ * stores is not: an English sentence filed as the Korean one is wrong and nobody sees why. So a key
51
+ * missing in this language — with its `context` form and without — answers `options.defaultValue`,
52
+ * and the caller decides what that means.
53
+ */
54
+ function translatorFor(lng) {
55
+ const fixed = i18next_1.default.getFixedT(lng, exports.NAMESPACE);
56
+ const has = (key) => i18next_1.default.getResource(lng, exports.NAMESPACE, key) !== undefined;
57
+ return (key, options = {}) => {
58
+ const context = options.context === undefined || options.context === null ? '' : String(options.context);
59
+ if ((context && has(`${key}_${context}`)) || has(key)) {
60
+ return fixed(key, options);
61
+ }
62
+ return options.defaultValue ?? key;
63
+ };
64
+ }
65
+ //# sourceMappingURL=translator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translator.js","sourceRoot":"","sources":["../server/translator.ts"],"names":[],"mappings":";;;AAkCA,4CAOC;AAcD,sCAaC;;AApED,8DAA6B;AAsEpB,kBAtEF,iBAAO,CAsEE;AApEhB,6CAAyD;AAEzD;;;;;;;;;;;GAWG;AACU,QAAA,SAAS,GAAG,cAAc,CAAA;AAEvC,iBAAO,CAAC,IAAI,CAAC;IACX,aAAa,EAAE,KAAK;IACpB,KAAK,EAAE,KAAK;IACZ,EAAE,EAAE,CAAC,iBAAS,CAAC;IACf,SAAS,EAAE,iBAAS;IACpB,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;IAC7C,WAAW,EAAE,IAAI;IACjB,aAAa,EAAE;QACb,MAAM,EAAE,GAAG;QACX,MAAM,EAAE,GAAG;KACZ;IACD,IAAI,EAAE,cAAc;IACpB,YAAY,EAAE,KAAK;CACpB,CAAC,CAAA;AAEF,qGAAqG;AACrG,SAAgB,gBAAgB;IAC9B,MAAM,GAAG,GAAG,IAAA,yBAAmB,EAAC,iBAAS,CAAC,CAAA;IAE1C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,iBAAO,CAAC,oBAAoB,CAAC,GAAG,EAAE,iBAAS,CAAC,CAAA;QAC5C,iBAAO,CAAC,iBAAiB,CAAC,GAAG,EAAE,iBAAS,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;IACjE,CAAC;AACH,CAAC;AAED,gBAAgB,EAAE,CAAA;AAIlB;;;;;;;GAOG;AACH,SAAgB,aAAa,CAAC,GAAW;IACvC,MAAM,KAAK,GAAG,iBAAO,CAAC,SAAS,CAAC,GAAG,EAAE,iBAAS,CAAC,CAAA;IAC/C,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,iBAAO,CAAC,WAAW,CAAC,GAAG,EAAE,iBAAS,EAAE,GAAG,CAAC,KAAK,SAAS,CAAA;IAEnF,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,EAAE;QAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAExG,IAAI,CAAC,OAAO,IAAI,GAAG,CAAC,GAAG,GAAG,IAAI,OAAO,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACtD,OAAO,KAAK,CAAC,GAAG,EAAE,OAAc,CAAW,CAAA;QAC7C,CAAC;QAED,OAAQ,OAAO,CAAC,YAAuB,IAAI,GAAG,CAAA;IAChD,CAAC,CAAA;AACH,CAAC","sourcesContent":["import i18next from 'i18next'\n\nimport { collectTranslations } from '@things-factory/env'\n\n/**\n * The server's translations — loaded from the sources, not from the webpack output.\n *\n * ── What was wrong (2026-10-11) ──────────────────────────────────────────\n * The server read only `dist-app/translations`, which webpack writes. A test run never has it, and a\n * dev server has it only after its first webpack pass. Server code that froze a sentence before then\n * got the key back. The sources are every module's `translations/` folder and the application's own,\n * merged by the same rule the bundler uses (`collectTranslations` in env).\n *\n * This file is light on purpose — no routes, no entities — so server code and tests can take a\n * translator without loading the whole module (`@things-factory/i18n-base/translator`).\n */\nexport const NAMESPACE = 'translations'\n\ni18next.init({\n initImmediate: false,\n debug: false,\n ns: [NAMESPACE],\n defaultNS: NAMESPACE,\n preload: ['ko', 'en', 'ja', 'zh', 'ms', 'es'],\n fallbackLng: 'en',\n interpolation: {\n prefix: '{',\n suffix: '}'\n },\n load: 'languageOnly',\n keySeparator: false\n})\n\n/** Load every locale from the sources. Called once here, and again when a dev build changes them. */\nexport function loadTranslations(): void {\n const all = collectTranslations(NAMESPACE)\n\n for (const lng of Object.keys(all)) {\n i18next.removeResourceBundle(lng, NAMESPACE)\n i18next.addResourceBundle(lng, NAMESPACE, all[lng], true, true)\n }\n}\n\nloadTranslations()\n\nexport type Translate = (key: string, options?: { [name: string]: unknown }) => string\n\n/**\n * A translator for one language that **does not fall back** to another.\n *\n * A request's translator falls back to English, which is right for a screen. A sentence the server\n * stores is not: an English sentence filed as the Korean one is wrong and nobody sees why. So a key\n * missing in this language — with its `context` form and without — answers `options.defaultValue`,\n * and the caller decides what that means.\n */\nexport function translatorFor(lng: string): Translate {\n const fixed = i18next.getFixedT(lng, NAMESPACE)\n const has = (key: string) => i18next.getResource(lng, NAMESPACE, key) !== undefined\n\n return (key, options = {}) => {\n const context = options.context === undefined || options.context === null ? '' : String(options.context)\n\n if ((context && has(`${key}_${context}`)) || has(key)) {\n return fixed(key, options as any) as string\n }\n\n return (options.defaultValue as string) ?? key\n }\n}\n\nexport { i18next }\n"]}