@aiwayds/dsh-tui-pi 2.19.0 → 2.20.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.
Files changed (105) hide show
  1. package/README.md +12 -48
  2. package/README.zh-CN.md +11 -47
  3. package/lib/agents.js +67 -52
  4. package/lib/agents.js.map +1 -1
  5. package/lib/ask-user.js +30 -30
  6. package/lib/ask-user.js.map +1 -1
  7. package/lib/attachments.js +8 -3
  8. package/lib/attachments.js.map +1 -1
  9. package/lib/btw.d.ts +4 -2
  10. package/lib/btw.js +22 -16
  11. package/lib/btw.js.map +1 -1
  12. package/lib/custom-provider.js +34 -28
  13. package/lib/custom-provider.js.map +1 -1
  14. package/lib/footer.d.ts +9 -8
  15. package/lib/footer.js +36 -18
  16. package/lib/footer.js.map +1 -1
  17. package/lib/hard-exit.d.ts +36 -0
  18. package/lib/hard-exit.js +64 -0
  19. package/lib/hard-exit.js.map +1 -0
  20. package/lib/history-fork.d.ts +2 -2
  21. package/lib/history-fork.js +12 -9
  22. package/lib/history-fork.js.map +1 -1
  23. package/lib/history-turns.d.ts +4 -2
  24. package/lib/history-turns.js +7 -3
  25. package/lib/history-turns.js.map +1 -1
  26. package/lib/history.js +57 -45
  27. package/lib/history.js.map +1 -1
  28. package/lib/hotkeys.js +44 -33
  29. package/lib/hotkeys.js.map +1 -1
  30. package/lib/i18n/index.d.ts +54 -0
  31. package/lib/i18n/index.js +98 -0
  32. package/lib/i18n/index.js.map +1 -0
  33. package/lib/i18n/registry.d.ts +65 -0
  34. package/lib/i18n/registry.js +129 -0
  35. package/lib/i18n/registry.js.map +1 -0
  36. package/lib/index.js +216 -108
  37. package/lib/index.js.map +1 -1
  38. package/lib/language-ask.d.ts +98 -0
  39. package/lib/language-ask.js +118 -0
  40. package/lib/language-ask.js.map +1 -0
  41. package/lib/live-widgets.js +9 -8
  42. package/lib/live-widgets.js.map +1 -1
  43. package/lib/login.js +5 -4
  44. package/lib/login.js.map +1 -1
  45. package/lib/messages.d.ts +0 -4
  46. package/lib/messages.js +14 -15
  47. package/lib/messages.js.map +1 -1
  48. package/lib/model-profiles.js +32 -20
  49. package/lib/model-profiles.js.map +1 -1
  50. package/lib/panels.js +18 -17
  51. package/lib/panels.js.map +1 -1
  52. package/lib/preflight-projcache.js +9 -3
  53. package/lib/preflight-projcache.js.map +1 -1
  54. package/lib/preset-dialog.d.ts +3 -3
  55. package/lib/preset-dialog.js +20 -17
  56. package/lib/preset-dialog.js.map +1 -1
  57. package/lib/provider-catalog.d.ts +23 -7
  58. package/lib/provider-catalog.js +90 -68
  59. package/lib/provider-catalog.js.map +1 -1
  60. package/lib/queue-panel.d.ts +2 -2
  61. package/lib/queue-panel.js +13 -9
  62. package/lib/queue-panel.js.map +1 -1
  63. package/lib/repair-dialog.d.ts +4 -4
  64. package/lib/repair-dialog.js +23 -16
  65. package/lib/repair-dialog.js.map +1 -1
  66. package/lib/route-dialog.d.ts +3 -3
  67. package/lib/route-dialog.js +20 -14
  68. package/lib/route-dialog.js.map +1 -1
  69. package/lib/selectors.d.ts +15 -1
  70. package/lib/selectors.js +57 -23
  71. package/lib/selectors.js.map +1 -1
  72. package/lib/sessions.d.ts +47 -14
  73. package/lib/sessions.js +162 -53
  74. package/lib/sessions.js.map +1 -1
  75. package/lib/settings.d.ts +68 -9
  76. package/lib/settings.js +327 -78
  77. package/lib/settings.js.map +1 -1
  78. package/lib/skills-manager.js +27 -21
  79. package/lib/skills-manager.js.map +1 -1
  80. package/lib/skills.js +5 -4
  81. package/lib/skills.js.map +1 -1
  82. package/lib/startup-info.js +9 -3
  83. package/lib/startup-info.js.map +1 -1
  84. package/lib/steer-flow.d.ts +14 -4
  85. package/lib/steer-flow.js +24 -9
  86. package/lib/steer-flow.js.map +1 -1
  87. package/lib/stop-dialog.d.ts +2 -2
  88. package/lib/stop-dialog.js +16 -12
  89. package/lib/stop-dialog.js.map +1 -1
  90. package/lib/subagent-viewer.d.ts +3 -6
  91. package/lib/subagent-viewer.js +38 -36
  92. package/lib/subagent-viewer.js.map +1 -1
  93. package/lib/theme-preview.js +12 -11
  94. package/lib/theme-preview.js.map +1 -1
  95. package/lib/theme-settings.d.ts +23 -2
  96. package/lib/theme-settings.js +68 -61
  97. package/lib/theme-settings.js.map +1 -1
  98. package/lib/tui.js +2 -1
  99. package/lib/tui.js.map +1 -1
  100. package/locales/en.json +646 -0
  101. package/locales/ja.json +646 -0
  102. package/locales/ko.json +646 -0
  103. package/locales/zh-CN.json +646 -0
  104. package/package.json +2 -1
  105. package/skills/dsh-tui-pi-config/SKILL.md +9 -2
package/lib/hotkeys.js CHANGED
@@ -19,6 +19,7 @@
19
19
  */
20
20
  import { readFileSync, writeFileSync } from 'node:fs';
21
21
  import { basename, join } from 'node:path';
22
+ import { t } from "./i18n/index.js";
22
23
  import { DEFAULT_KEYBINDINGS } from "./keymap.js";
23
24
  import { FieldPanel, PanelHost } from "./panels.js";
24
25
  import { EditField } from "./settings.js";
@@ -31,15 +32,17 @@ export function keybindingsPath(home) {
31
32
  }
32
33
  /** The six app-level bindings the file may remap (order = display order). */
33
34
  export const APP_KEY_FIELDS = ['escape', 'ctrlC', 'ctrlD', 'modelPicker', 'subagentViewer', 'queuePanel'];
34
- /** Action descriptions for the `/hotkeys` table. */
35
- const KEY_ACTIONS = {
36
- escape: 'stop the current task — requires two presses (1st arms, 2nd within 500ms fires)',
37
- ctrlC: 'running: cancel turn · idle: clear editor · second press quits',
38
- ctrlD: 'quit — only on an empty editor',
39
- modelPicker: 'open the model / think picker',
40
- subagentViewer: 'open the subagent picker / viewer',
41
- queuePanel: 'open the pending-message queue (d remove · s steer now)',
42
- };
35
+ /** Action description for one app key in the `/hotkeys` table. A function, not a module table: the text resolves through `t()` on every call so a language switch re-renders instead of freezing the boot-time language. */
36
+ function keyAction(field) {
37
+ switch (field) {
38
+ case 'escape': return t('hotkeys.action.escape');
39
+ case 'ctrlC': return t('hotkeys.action.ctrlC');
40
+ case 'ctrlD': return t('hotkeys.action.ctrlD');
41
+ case 'modelPicker': return t('hotkeys.action.modelPicker');
42
+ case 'subagentViewer': return t('hotkeys.action.subagentViewer');
43
+ case 'queuePanel': return t('hotkeys.action.queuePanel');
44
+ }
45
+ }
43
46
  // ------------------------------------------------------------- validation --
44
47
  const MODIFIERS = new Set(['ctrl', 'shift', 'alt', 'super']);
45
48
  const NAMED_KEYS = new Set([
@@ -99,10 +102,10 @@ export function loadKeyBindings(path) {
99
102
  raw = JSON.parse(text);
100
103
  }
101
104
  catch (error) {
102
- return { bindings: {}, warnings: [`${label}: invalid JSON — ${error.message}`], exists: true };
105
+ return { bindings: {}, warnings: [t('hotkeys.warn.invalidJson', { label, error: error.message })], exists: true };
103
106
  }
104
107
  if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
105
- return { bindings: {}, warnings: [`${label}: expected a JSON object of app-key → key id`], exists: true };
108
+ return { bindings: {}, warnings: [t('hotkeys.warn.notObject', { label })], exists: true };
106
109
  }
107
110
  const record = raw;
108
111
  const bindings = {};
@@ -112,7 +115,7 @@ export function loadKeyBindings(path) {
112
115
  if (value === undefined)
113
116
  continue;
114
117
  if (!isValidKeyId(value)) {
115
- warnings.push(`${label}: "${field}" = ${JSON.stringify(value)} is not a valid key id — keeping the default`);
118
+ warnings.push(t('hotkeys.warn.invalidKey', { label, field, value: JSON.stringify(value) }));
116
119
  }
117
120
  else {
118
121
  bindings[field] = value;
@@ -120,7 +123,7 @@ export function loadKeyBindings(path) {
120
123
  }
121
124
  for (const field of Object.keys(record)) {
122
125
  if (!APP_KEY_FIELDS.includes(field)) {
123
- warnings.push(`${label}: unknown field "${field}" — ignored`);
126
+ warnings.push(t('hotkeys.warn.unknownField', { label, field }));
124
127
  }
125
128
  }
126
129
  return { bindings, warnings, exists: true };
@@ -141,13 +144,13 @@ export function updateKeyBindingsFile(path, updates) {
141
144
  fileExisted = true;
142
145
  const parsed = JSON.parse(text);
143
146
  if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
144
- return `${label}: expected a JSON object — fix or delete the file, then retry`;
147
+ return t('hotkeys.file.notObject', { label });
145
148
  }
146
149
  Object.assign(existing, parsed);
147
150
  }
148
151
  catch (error) {
149
152
  if (fileExisted)
150
- return `${label}: ${error.message} — fix or delete the file, then retry`;
153
+ return t('hotkeys.file.parseError', { label, error: error.message });
151
154
  // Absent file: start fresh.
152
155
  }
153
156
  for (const [field, value] of updates) {
@@ -160,7 +163,7 @@ export function updateKeyBindingsFile(path, updates) {
160
163
  writeFileSync(path, JSON.stringify(existing, null, 2) + '\n');
161
164
  }
162
165
  catch (error) {
163
- return `${label}: cannot write — ${error.message}`;
166
+ return t('hotkeys.file.writeError', { label, error: error.message });
164
167
  }
165
168
  return undefined;
166
169
  }
@@ -170,7 +173,7 @@ export function parseKeyInput(text) {
170
173
  if (trimmed === '')
171
174
  return { kind: 'unset' };
172
175
  if (!isValidKeyId(trimmed)) {
173
- return { kind: 'error', error: `not a key id — ctrl/shift/alt/super + key (e.g. ctrl+x, f5, escape)` };
176
+ return { kind: 'error', error: t('hotkeys.parse.notKeyId') };
174
177
  }
175
178
  return { kind: 'value', value: trimmed };
176
179
  }
@@ -185,7 +188,7 @@ export function appHotkeyRows(custom) {
185
188
  return {
186
189
  field,
187
190
  key: displayKey(override ?? DEFAULT_KEYBINDINGS[field]),
188
- action: KEY_ACTIONS[field],
191
+ action: keyAction(field),
189
192
  custom: override !== undefined,
190
193
  };
191
194
  });
@@ -204,7 +207,7 @@ export async function openHotkeysManager(tui, theme, options) {
204
207
  let settle;
205
208
  const host = new PanelHost(tui, theme, message => {
206
209
  options.restoreFocus();
207
- settle?.(`✘ failed to open the hotkeys view: ${message}`);
210
+ settle?.(t('hotkeys.openFailed', { message }));
208
211
  });
209
212
  /** Re-read the file after a write and push the change into the running TUI. */
210
213
  const applyBindings = () => {
@@ -220,25 +223,28 @@ export async function openHotkeysManager(tui, theme, options) {
220
223
  editable: true,
221
224
  }));
222
225
  const customCount = Object.keys(loaded.bindings).length;
226
+ const customLine = loaded.exists
227
+ ? (customCount === 1
228
+ ? t('hotkeys.custom.one', { path: options.filePath })
229
+ : t('hotkeys.custom.many', { path: options.filePath, count: customCount }))
230
+ : t('hotkeys.custom.missing', { path: options.filePath });
223
231
  const content = [
224
- loaded.exists
225
- ? `custom: ${options.filePath} (${customCount} override${customCount === 1 ? '' : 's'})`
226
- : `custom: ${options.filePath} (not found — defaults in use)`,
227
- 'format: ctrl/shift/alt/super+key · Enter edits · empty input resets to the default',
228
- 'editor: pi-tui defaults — arrows · Ctrl+B/F · Alt+←→ word · Home/End · Ctrl+W/U/K delete · Ctrl+- undo',
232
+ customLine,
233
+ t('hotkeys.formatHint'),
234
+ t('hotkeys.editorHint'),
229
235
  ...loaded.warnings.map(warning => `! ${warning}`),
230
236
  ];
231
237
  const panel = new FieldPanel(theme, {
232
- title: ansiFg(theme.palette.accent) + BOLD + '⚙ hotkeys' + RESET,
238
+ title: ansiFg(theme.palette.accent) + BOLD + t('hotkeys.title') + RESET,
233
239
  content,
234
240
  fields,
235
241
  status: () => status,
236
- footer: '↑↓ key · Enter change · Esc close',
242
+ footer: t('hotkeys.footer'),
237
243
  onEdit: index => edit(fields[index].key),
238
244
  onCancel: () => {
239
245
  host.close();
240
246
  options.restoreFocus();
241
- resolve(changed ? 'Keybindings updated.' : undefined);
247
+ resolve(changed ? t('hotkeys.updated') : undefined);
242
248
  },
243
249
  });
244
250
  host.open(panel);
@@ -251,9 +257,14 @@ export async function openHotkeysManager(tui, theme, options) {
251
257
  const loaded = loadKeyBindings(options.filePath);
252
258
  const current = loaded.bindings[field];
253
259
  const editor = new EditField(tui, {
254
- title: `Key for ${field} — default ${displayKey(DEFAULT_KEYBINDINGS[field])}`
255
- + (current !== undefined ? ` · custom ${displayKey(current)}` : ''),
256
- subtitle: 'ctrl/shift/alt/super + key · empty resets to the default',
260
+ title: current !== undefined
261
+ ? t('hotkeys.edit.titleCustom', {
262
+ field,
263
+ defaultValue: displayKey(DEFAULT_KEYBINDINGS[field]),
264
+ custom: displayKey(current),
265
+ })
266
+ : t('hotkeys.edit.title', { field, defaultValue: displayKey(DEFAULT_KEYBINDINGS[field]) }),
267
+ subtitle: t('hotkeys.edit.subtitle'),
257
268
  initial: current ?? '',
258
269
  parse: parseKeyInput,
259
270
  onCommit: async (outcome) => {
@@ -270,8 +281,8 @@ export async function openHotkeysManager(tui, theme, options) {
270
281
  changed = true;
271
282
  applyBindings();
272
283
  status = reset
273
- ? `${field} → default (${displayKey(DEFAULT_KEYBINDINGS[field])}) — applied`
274
- : `${field} → ${id} — applied`;
284
+ ? t('hotkeys.status.reset', { field, defaultValue: displayKey(DEFAULT_KEYBINDINGS[field]) })
285
+ : t('hotkeys.status.set', { field, id });
275
286
  return undefined;
276
287
  }
277
288
  if (outcome.kind === 'unset') {
@@ -283,7 +294,7 @@ export async function openHotkeysManager(tui, theme, options) {
283
294
  return { error };
284
295
  changed = true;
285
296
  applyBindings();
286
- status = `${field} → default (${displayKey(DEFAULT_KEYBINDINGS[field])}) — applied`;
297
+ status = t('hotkeys.status.reset', { field, defaultValue: displayKey(DEFAULT_KEYBINDINGS[field]) });
287
298
  return undefined;
288
299
  }
289
300
  return undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"hotkeys.js","sourceRoot":"","sources":["../src/hotkeys.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hotkeys.js","sourceRoot":"","sources":["../src/hotkeys.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * UI string runtime: `t(key, params)` resolves the active language's text
3
+ * for a flat dot-namespaced key, falling back per key to the bundled English
4
+ * catalog and finally to the key itself (so an un-translated call site is
5
+ * visible instead of rendering `undefined`).
6
+ *
7
+ * Language files are discovered by ./registry.ts (bundled `locales/` merged
8
+ * with the user's `$DSH_HOME/locales`). The active language is the
9
+ * `dsh-tui.language` setting: read once at TUI startup, and re-applied live
10
+ * through the settings watch hook — `t()` reads the current module state on
11
+ * every call, so the next repaint speaks the new language (already-rendered
12
+ * transcript rows rebuild on the next resize, matching the theme hot-swap
13
+ * behavior).
14
+ *
15
+ * The English catalog is ALSO the out-of-the-box behavior: every extracted
16
+ * call site's English text must live in `locales/en.json` byte-identical to
17
+ * the pre-i18n literal (the test suite greps `t('…')` call sites against
18
+ * en.json). Tests that render components without booting the TUI therefore
19
+ * still see the original English — en.json loads lazily here on the first
20
+ * `t()`, no init required.
21
+ */
22
+ /**
23
+ * Initialize the i18n runtime at TUI startup: discover language files and
24
+ * activate `id`. Called once from apply() with the persisted
25
+ * `dsh-tui.language` value; an unknown id degrades to `en`.
26
+ * @param opts.warn - discovery skip reporter (defaults to console.warn).
27
+ */
28
+ export declare function initI18n(opts?: {
29
+ home?: string;
30
+ id?: string;
31
+ warn?: (msg: string) => void;
32
+ }): void;
33
+ /** The active locale (id + display name). */
34
+ export declare function currentLocale(): {
35
+ id: string;
36
+ name: string;
37
+ };
38
+ /** All discovered languages, id-sorted — for the /language listing. */
39
+ export declare function listLocales(): ReadonlyArray<{
40
+ id: string;
41
+ name: string;
42
+ }>;
43
+ /**
44
+ * Activate one discovered language. Unknown ids keep the current language.
45
+ * @returns true when the language exists and is now active.
46
+ */
47
+ export declare function setLocale(id: string): boolean;
48
+ /**
49
+ * Translate one UI string. Resolution order: active language → bundled
50
+ * English → the key itself. `{param}` placeholders are replaced from
51
+ * `params`; a parameter with no entry stays visible as `{param}` (a missing
52
+ * param is a programming error the rendered output exposes).
53
+ */
54
+ export declare function t(key: string, params?: Readonly<Record<string, string | number>>): string;
@@ -0,0 +1,98 @@
1
+ /**
2
+ * UI string runtime: `t(key, params)` resolves the active language's text
3
+ * for a flat dot-namespaced key, falling back per key to the bundled English
4
+ * catalog and finally to the key itself (so an un-translated call site is
5
+ * visible instead of rendering `undefined`).
6
+ *
7
+ * Language files are discovered by ./registry.ts (bundled `locales/` merged
8
+ * with the user's `$DSH_HOME/locales`). The active language is the
9
+ * `dsh-tui.language` setting: read once at TUI startup, and re-applied live
10
+ * through the settings watch hook — `t()` reads the current module state on
11
+ * every call, so the next repaint speaks the new language (already-rendered
12
+ * transcript rows rebuild on the next resize, matching the theme hot-swap
13
+ * behavior).
14
+ *
15
+ * The English catalog is ALSO the out-of-the-box behavior: every extracted
16
+ * call site's English text must live in `locales/en.json` byte-identical to
17
+ * the pre-i18n literal (the test suite greps `t('…')` call sites against
18
+ * en.json). Tests that render components without booting the TUI therefore
19
+ * still see the original English — en.json loads lazily here on the first
20
+ * `t()`, no init required.
21
+ */
22
+ import { readFileSync } from 'node:fs';
23
+ import { join } from 'node:path';
24
+ import { builtinLocalesDir, discoverLocales, parseLocaleFile, } from "./registry.js";
25
+ /** Discovered languages (bundled ∪ user, user wins per key). Populated lazily. */
26
+ let discovered;
27
+ /** The active language. Starts as the en fallback with no translations. */
28
+ let current = { id: 'en', name: 'English', strings: {} };
29
+ /** Lazily-parsed bundled en.json — the per-key fallback catalog. */
30
+ let enFallbackStrings;
31
+ function enFallback() {
32
+ if (enFallbackStrings === undefined) {
33
+ enFallbackStrings = {};
34
+ try {
35
+ const raw = readFileSync(join(builtinLocalesDir(), 'en.json'), 'utf8');
36
+ enFallbackStrings = parseLocaleFile(raw, join(builtinLocalesDir(), 'en.json')).strings;
37
+ }
38
+ catch {
39
+ // Missing/invalid en.json: t() degrades to the key itself (fail-open).
40
+ }
41
+ }
42
+ return enFallbackStrings;
43
+ }
44
+ function localeMap() {
45
+ if (discovered === undefined)
46
+ discovered = discoverLocales();
47
+ return discovered;
48
+ }
49
+ /**
50
+ * Initialize the i18n runtime at TUI startup: discover language files and
51
+ * activate `id`. Called once from apply() with the persisted
52
+ * `dsh-tui.language` value; an unknown id degrades to `en`.
53
+ * @param opts.warn - discovery skip reporter (defaults to console.warn).
54
+ */
55
+ export function initI18n(opts) {
56
+ discovered = discoverLocales({ home: opts?.home, warn: opts?.warn });
57
+ activate(opts?.id ?? 'en');
58
+ }
59
+ /** The active locale (id + display name). */
60
+ export function currentLocale() {
61
+ return { id: current.id, name: current.name };
62
+ }
63
+ /** All discovered languages, id-sorted — for the /language listing. */
64
+ export function listLocales() {
65
+ return [...localeMap().values()]
66
+ .map(locale => ({ id: locale.id, name: locale.name }))
67
+ .sort((a, b) => a.id.localeCompare(b.id));
68
+ }
69
+ /**
70
+ * Activate one discovered language. Unknown ids keep the current language.
71
+ * @returns true when the language exists and is now active.
72
+ */
73
+ export function setLocale(id) {
74
+ return activate(id);
75
+ }
76
+ function activate(id) {
77
+ const locale = localeMap().get(id);
78
+ if (locale === undefined)
79
+ return false;
80
+ current = locale;
81
+ return true;
82
+ }
83
+ /**
84
+ * Translate one UI string. Resolution order: active language → bundled
85
+ * English → the key itself. `{param}` placeholders are replaced from
86
+ * `params`; a parameter with no entry stays visible as `{param}` (a missing
87
+ * param is a programming error the rendered output exposes).
88
+ */
89
+ export function t(key, params) {
90
+ const text = current.strings[key] ?? enFallback()[key] ?? key;
91
+ if (params === undefined)
92
+ return text;
93
+ return text.replace(/\{(\w+)\}/g, (whole, name) => {
94
+ const value = params[name];
95
+ return value === undefined ? whole : String(value);
96
+ });
97
+ }
98
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/i18n/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Locale file registry: discovers UI-language files from the npm-bundled
3
+ * `locales/` directory and the user's `$DSH_HOME/locales` directory, parses
4
+ * and validates each `*.json` file, and merges them into one registry keyed
5
+ * by locale id (the filename without `.json`, e.g. `en`, `zh-CN`).
6
+ *
7
+ * Adding a language is exactly one JSON file: `ko.json` in `locales/` (or the
8
+ * user's `$DSH_HOME/locales/`) with a `name` and one flat `key: string` entry
9
+ * per translatable string. No code changes.
10
+ *
11
+ * JSON contract (a language file):
12
+ * - required: `name` — the display name in that language (e.g. `"简体中文"`),
13
+ * shown by the /language command and the /settings browser.
14
+ * - every other entry: a non-empty string, flat dot-namespaced key → text.
15
+ * `{param}` placeholders in the value are interpolated by `t()`; a
16
+ * translation must carry the same `{param}` set as its `en` twin (enforced
17
+ * by the test suite, not here — the registry stays format-only).
18
+ * - any other value shape (number, nested object, empty string) rejects the
19
+ * whole file with the offending key in the error — strictness is the point:
20
+ * a hand-edited file with one typo must not half-load.
21
+ *
22
+ * Merge semantics: a user file whose id matches a bundled file merges
23
+ * per-key OVER the bundled one (a user fixing three strings keeps the rest
24
+ * of the language), and a user file with a new id registers a new language.
25
+ * Invalid files are skipped with a `warn` line (fail-open), mirroring the
26
+ * theme registry.
27
+ */
28
+ /** One parsed language file: the id, its display name, and the key → text map. */
29
+ export interface LocaleStrings {
30
+ id: string;
31
+ name: string;
32
+ strings: Record<string, string>;
33
+ }
34
+ /** npm-bundled locales dir (repo-root `locales/`; resolves up from lib/ at runtime). */
35
+ export declare function builtinLocalesDir(): string;
36
+ /** User locales dir: `$DSH_HOME/locales` (home is the dshHome() result). */
37
+ export declare function userLocalesDir(home: string): string;
38
+ /**
39
+ * Parse + validate one locale JSON file into its `name` and flat string map.
40
+ * Throws an `Error` carrying the `source` path and the offending key on any
41
+ * invalid input (see the JSON contract in the module header).
42
+ */
43
+ export declare function parseLocaleFile(raw: string, source: string): {
44
+ name: string;
45
+ strings: Record<string, string>;
46
+ };
47
+ /**
48
+ * Scan one directory for `*.json` locale files, keyed by file id (filename
49
+ * minus `.json`). Invalid files are skipped with a `warn` line (fail-open);
50
+ * a missing/unreadable directory yields an empty Map (never throws).
51
+ */
52
+ export declare function scanLocaleDir(dir: string, warn?: (msg: string) => void): Map<string, LocaleStrings>;
53
+ /**
54
+ * Merge-register all discoverable locales: the bundled `locales/` directory
55
+ * first, then the user's `$DSH_HOME/locales` — a user file whose id matches
56
+ * a bundled one merges per-key over it (user strings win), and a user file
57
+ * with a new id registers a new language.
58
+ *
59
+ * @param opts.home - the dsh home (defaults to `$DSH_HOME` or `~/.dsh`).
60
+ * @param opts.warn - per-file skip reporter (invalid locales are fail-open).
61
+ */
62
+ export declare function discoverLocales(opts?: {
63
+ home?: string;
64
+ warn?: (msg: string) => void;
65
+ }): Map<string, LocaleStrings>;
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Locale file registry: discovers UI-language files from the npm-bundled
3
+ * `locales/` directory and the user's `$DSH_HOME/locales` directory, parses
4
+ * and validates each `*.json` file, and merges them into one registry keyed
5
+ * by locale id (the filename without `.json`, e.g. `en`, `zh-CN`).
6
+ *
7
+ * Adding a language is exactly one JSON file: `ko.json` in `locales/` (or the
8
+ * user's `$DSH_HOME/locales/`) with a `name` and one flat `key: string` entry
9
+ * per translatable string. No code changes.
10
+ *
11
+ * JSON contract (a language file):
12
+ * - required: `name` — the display name in that language (e.g. `"简体中文"`),
13
+ * shown by the /language command and the /settings browser.
14
+ * - every other entry: a non-empty string, flat dot-namespaced key → text.
15
+ * `{param}` placeholders in the value are interpolated by `t()`; a
16
+ * translation must carry the same `{param}` set as its `en` twin (enforced
17
+ * by the test suite, not here — the registry stays format-only).
18
+ * - any other value shape (number, nested object, empty string) rejects the
19
+ * whole file with the offending key in the error — strictness is the point:
20
+ * a hand-edited file with one typo must not half-load.
21
+ *
22
+ * Merge semantics: a user file whose id matches a bundled file merges
23
+ * per-key OVER the bundled one (a user fixing three strings keeps the rest
24
+ * of the language), and a user file with a new id registers a new language.
25
+ * Invalid files are skipped with a `warn` line (fail-open), mirroring the
26
+ * theme registry.
27
+ */
28
+ import { readdirSync, readFileSync } from 'node:fs';
29
+ import { homedir } from 'node:os';
30
+ import { dirname, join, resolve } from 'node:path';
31
+ import { fileURLToPath } from 'node:url';
32
+ /** Default $DSH_HOME (mirrors theme/registry.ts's local helper — kept local to avoid a business-module dependency here). */
33
+ function defaultDshHome() {
34
+ return process.env.DSH_HOME ?? join(homedir(), '.dsh');
35
+ }
36
+ /** npm-bundled locales dir (repo-root `locales/`; resolves up from lib/ at runtime). */
37
+ export function builtinLocalesDir() {
38
+ // Compiled: lib/i18n/registry.js → ../.. = package root. From src/ the
39
+ // same two hops land on the repo root too.
40
+ return resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', 'locales');
41
+ }
42
+ /** User locales dir: `$DSH_HOME/locales` (home is the dshHome() result). */
43
+ export function userLocalesDir(home) {
44
+ return join(home, 'locales');
45
+ }
46
+ /**
47
+ * Parse + validate one locale JSON file into its `name` and flat string map.
48
+ * Throws an `Error` carrying the `source` path and the offending key on any
49
+ * invalid input (see the JSON contract in the module header).
50
+ */
51
+ export function parseLocaleFile(raw, source) {
52
+ let data;
53
+ try {
54
+ data = JSON.parse(raw);
55
+ }
56
+ catch (error) {
57
+ throw new Error(`${source}: invalid locale JSON (${error instanceof Error ? error.message : String(error)})`);
58
+ }
59
+ if (data === null || typeof data !== 'object' || Array.isArray(data)) {
60
+ throw new Error(`${source}: locale file must be a JSON object`);
61
+ }
62
+ const input = data;
63
+ const name = input['name'];
64
+ if (typeof name !== 'string' || name === '') {
65
+ throw new Error(`${source}: locale "name" must be a non-empty string`);
66
+ }
67
+ const strings = {};
68
+ for (const [key, value] of Object.entries(input)) {
69
+ if (key === 'name')
70
+ continue;
71
+ if (typeof value !== 'string' || value === '') {
72
+ throw new Error(`${source}: locale key "${key}" must be a non-empty string`);
73
+ }
74
+ strings[key] = value;
75
+ }
76
+ return { name, strings };
77
+ }
78
+ /**
79
+ * Scan one directory for `*.json` locale files, keyed by file id (filename
80
+ * minus `.json`). Invalid files are skipped with a `warn` line (fail-open);
81
+ * a missing/unreadable directory yields an empty Map (never throws).
82
+ */
83
+ export function scanLocaleDir(dir, warn) {
84
+ const locales = new Map();
85
+ let files;
86
+ try {
87
+ files = readdirSync(dir, { withFileTypes: true })
88
+ .filter(entry => entry.isFile() && entry.name.endsWith('.json'))
89
+ .map(entry => join(dir, entry.name));
90
+ }
91
+ catch {
92
+ // Missing/unreadable directory: nothing to register (fail-open).
93
+ return locales;
94
+ }
95
+ for (const file of files) {
96
+ const id = file.slice(dir.length + 1, -'.json'.length);
97
+ try {
98
+ const { name, strings } = parseLocaleFile(readFileSync(file, 'utf8'), file);
99
+ locales.set(id, { id, name, strings });
100
+ }
101
+ catch (error) {
102
+ warn?.(`locale registry: skipping ${file}: ${error instanceof Error ? error.message : String(error)}`);
103
+ }
104
+ }
105
+ return locales;
106
+ }
107
+ /**
108
+ * Merge-register all discoverable locales: the bundled `locales/` directory
109
+ * first, then the user's `$DSH_HOME/locales` — a user file whose id matches
110
+ * a bundled one merges per-key over it (user strings win), and a user file
111
+ * with a new id registers a new language.
112
+ *
113
+ * @param opts.home - the dsh home (defaults to `$DSH_HOME` or `~/.dsh`).
114
+ * @param opts.warn - per-file skip reporter (invalid locales are fail-open).
115
+ */
116
+ export function discoverLocales(opts) {
117
+ const registry = new Map();
118
+ for (const [id, locale] of scanLocaleDir(builtinLocalesDir(), opts?.warn)) {
119
+ registry.set(id, locale);
120
+ }
121
+ for (const [id, user] of scanLocaleDir(userLocalesDir(opts?.home ?? defaultDshHome()), opts?.warn)) {
122
+ const bundled = registry.get(id);
123
+ registry.set(id, bundled === undefined
124
+ ? user
125
+ : { id, name: user.name, strings: { ...bundled.strings, ...user.strings } });
126
+ }
127
+ return registry;
128
+ }
129
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/i18n/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AASxC,4HAA4H;AAC5H,SAAS,cAAc;IACrB,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAA;AACxD,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,iBAAiB;IAC/B,uEAAuE;IACvE,2CAA2C;IAC3C,OAAO,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAA;AAChF,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;AAC9B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,MAAc;IACzD,IAAI,IAAa,CAAA;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,0BAA0B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC/G,CAAC;IACD,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,qCAAqC,CAAC,CAAA;IACjE,CAAC;IACD,MAAM,KAAK,GAAG,IAA+B,CAAA;IAE7C,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAA;IAC1B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,4CAA4C,CAAC,CAAA;IACxE,CAAC;IAED,MAAM,OAAO,GAA2B,EAAE,CAAA;IAC1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,GAAG,KAAK,MAAM;YAAE,SAAQ;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,iBAAiB,GAAG,8BAA8B,CAAC,CAAA;QAC9E,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;IACtB,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;AAC1B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,IAA4B;IACrE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAA;IAChD,IAAI,KAAe,CAAA;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;aAC9C,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;aAC/D,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,iEAAiE;QACjE,OAAO,OAAO,CAAA;IAChB,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QACtD,IAAI,CAAC;YACH,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,CAAA;YAC3E,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,EAAE,CAAC,6BAA6B,IAAI,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACxG,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,IAAsD;IACpF,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAA;IACjD,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,aAAa,CAAC,iBAAiB,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;QAC1E,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;IAC1B,CAAC;IACD,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,aAAa,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,IAAI,cAAc,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;QACnG,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAChC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,KAAK,SAAS;YACpC,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;IAChF,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC"}