dsh-width-tiers 1.0.0 → 1.0.1

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
@@ -47,6 +47,11 @@ Restart `dsh web` (the plugin loads at boot) and hard-refresh the page
47
47
  (Ctrl+Shift+R). A round button with five bars appears at the bottom-right.
48
48
 
49
49
  > Installing from a local checkout: `dsh plugin --profile web add file:/path/to/dsh-width-tiers`.
50
+ > Local-development gotcha: `file:` dependencies are **copied** into the
51
+ > profile's `node_modules` (pnpm does not symlink them). After editing the
52
+ > plugin source, re-sync the copy (e.g. `rsync -a --delete --exclude .git
53
+ > /path/to/dsh-width-tiers/ ~/.dsh/profiles/web/node_modules/dsh-width-tiers/`)
54
+ > or re-install after removing it, then restart `dsh web` and hard-refresh.
50
55
 
51
56
  ## Usage
52
57
 
@@ -57,6 +62,14 @@ Restart `dsh web` (the plugin loads at boot) and hard-refresh the page
57
62
  - Non-standard tiers also close the details panel (re-closed automatically if
58
63
  reopened); `standard` leaves everything to the app.
59
64
 
65
+ ## Language
66
+
67
+ All picker copy (tier labels, button `aria-label` and title) follows the
68
+ app's **Settings → Language** (中文 / English), through the app's own locale
69
+ service. Switching the language re-renders the button and menu immediately;
70
+ when no explicit language is chosen the app falls back to the browser's
71
+ language, and Chinese is the last resort. No plugin-side setting needed.
72
+
60
73
  ## How it works
61
74
 
62
75
  - The element that defines `--dsh-chat-content-width` is **located at
@@ -67,6 +80,9 @@ Restart `dsh web` (the plugin loads at boot) and hard-refresh the page
67
80
  simulating clicks.
68
81
  - The sidebar is only ever collapsed by the `full` tier; returning to
69
82
  `standard` restores it only if this plugin collapsed it.
83
+ - Dictionaries are registered with the app's **locale service**
84
+ (`ctx.locale.register` / `bind`) and re-rendered through its change
85
+ subscription, so the copy always matches the app's active language.
70
86
 
71
87
  ## Limitations
72
88
 
package/README.zh.md CHANGED
@@ -43,6 +43,11 @@ dsh plugin --profile web add dsh-width-tiers
43
43
  右下角会出现五条横条的圆形按钮。
44
44
 
45
45
  > 本地目录安装:`dsh plugin --profile web add file:/path/to/dsh-width-tiers`。
46
+ > 本地开发注意:`file:` 依赖会被 **拷贝** 进 profile 的 node_modules(pnpm
47
+ > 不会建软链)。改完插件源码后,需要重新同步拷贝(例如 `rsync -a --delete
48
+ > --exclude .git /path/to/dsh-width-tiers/
49
+ > ~/.dsh/profiles/web/node_modules/dsh-width-tiers/`)或先 remove 再 add,
50
+ > 然后重启 `dsh web` 并硬刷新。
46
51
 
47
52
  ## 使用
48
53
 
@@ -51,6 +56,13 @@ dsh plugin --profile web add dsh-width-tiers
51
56
  随时点轨道图标展开,展开后保持展开。
52
57
  - 非标准档会关闭详情面板(被重新打开会自动再关);标准档完全交给应用。
53
58
 
59
+ ## 多语言
60
+
61
+ 选择器里的所有文案(档位名、按钮的 `aria-label` 和标题)跟随应用的
62
+ **设置 → 语言**(中文 / English),通过应用自身的 locale 服务实现。切换
63
+ 语言后按钮和菜单会立即重渲染;未显式选择语言时,应用会回退到浏览器语言,
64
+ 最后兜底中文。无需插件侧单独设置。
65
+
54
66
  ## 原理
55
67
 
56
68
  - 运行时**自动定位**定义 `--dsh-chat-content-width` 的元素(第一个计算值
@@ -58,6 +70,8 @@ dsh plugin --profile web add dsh-width-tiers
58
70
  - 面板操作走 **layout 服务**(`ctx.layout`),从不模拟点击。
59
71
  - 侧边栏只被「全宽」档收起;回到「标准」时,只有本插件自己收起的侧边栏
60
72
  才会被恢复展开(你手动收的不动)。
73
+ - 字典注册到应用的 **locale 服务**(`ctx.locale.register` / `bind`),并
74
+ 订阅其变更事件重渲染,文案始终与应用的当前语言一致。
61
75
 
62
76
  ## 已知限制
63
77
 
package/lib/client.js CHANGED
@@ -35,18 +35,50 @@ window.__ModuleLoader__.load({
35
35
  * active); `standard` leaves everything to the app.
36
36
  * - The chosen tier persists in localStorage and is restored on the
37
37
  * next visit.
38
+ * - All copy is localized through the app's locale service: tier
39
+ * labels and the button's aria/title follow Settings → Language
40
+ * (zh / en, browser-derived fallback) and re-render on switch.
38
41
  */
39
42
  const KEY = "dsh.widthTier";
40
43
  const OLD_KEY = "dsh.wide";
41
44
  const SELF_HEAL_MS = 1000;
42
45
  const READY_TIMEOUT_MS = 30000;
43
46
 
47
+ /** Dictionary namespace owned by this plugin. */
48
+ const NS = "width-tiers";
49
+
50
+ //#region lib/types/client/locales.js
51
+ /** `width-tiers` namespace dictionaries (tier labels and picker copy). */
52
+ /** Simplified Chinese dictionary (the key-set source of truth). */
53
+ const zh = {
54
+ "tier.standard": "标准",
55
+ "tier.medium": "中等",
56
+ "tier.wide": "宽",
57
+ "tier.ultra": "超宽",
58
+ "tier.full": "全宽",
59
+ "button.aria": "对话区宽度档位:{label}({value}),点击选择档位",
60
+ "button.title.summary": "对话区宽度档位:{label}({value})",
61
+ "button.title.hint": "点击选择:{list}"
62
+ };
63
+ /** English dictionary, checked complete against the zh key set. */
64
+ const en = {
65
+ "tier.standard": "Standard",
66
+ "tier.medium": "Medium",
67
+ "tier.wide": "Wide",
68
+ "tier.ultra": "Ultra",
69
+ "tier.full": "Full",
70
+ "button.aria": "Chat width tier: {label} ({value}). Click to choose a tier.",
71
+ "button.title.summary": "Chat width tier: {label} ({value})",
72
+ "button.title.hint": "Click to choose: {list}"
73
+ };
74
+ //#endregion
75
+
44
76
  const TIERS = [
45
- { id: "standard", label: "标准", value: "748px", note: "默认阅读宽度" },
46
- { id: "medium", label: "中等", value: "960px" },
47
- { id: "wide", label: "宽", value: "1280px" },
48
- { id: "ultra", label: "超宽", value: "1400px" },
49
- { id: "full", label: "全宽", value: "100%", note: "占满窗口" }
77
+ { id: "standard", key: "tier.standard", value: "748px" },
78
+ { id: "medium", key: "tier.medium", value: "960px" },
79
+ { id: "wide", key: "tier.wide", value: "1280px" },
80
+ { id: "ultra", key: "tier.ultra", value: "1400px" },
81
+ { id: "full", key: "tier.full", value: "100%" }
50
82
  ];
51
83
 
52
84
  function tierOf(id) {
@@ -76,14 +108,18 @@ window.__ModuleLoader__.load({
76
108
  //#endregion
77
109
 
78
110
  /** Services required by the browser bundle. */
79
- const inject = ["layout"];
111
+ const inject = ["layout", "locale"];
80
112
 
81
113
  /**
82
114
  * Client plugin body: inject the styles, build the picker button and
83
115
  * menu, and drive the width tiers through the layout service.
84
- * @param ctx - client root context (layout injected).
116
+ * @param ctx - client root context (layout + locale injected).
85
117
  */
86
118
  function apply(ctx) {
119
+ ctx.effect(() => ctx.locale.register(NS, {
120
+ zh,
121
+ en
122
+ }), "dsh-width-tiers: dictionaries");
87
123
  ctx.effect(() => {
88
124
  if (typeof document === "undefined") return;
89
125
 
@@ -93,6 +129,7 @@ window.__ModuleLoader__.load({
93
129
  document.head.appendChild(styleTag);
94
130
 
95
131
  const layout = ctx.layout;
132
+ const t = ctx.locale.bind(NS);
96
133
 
97
134
  /* ---- helpers ---- */
98
135
  const body = () => document.body;
@@ -227,13 +264,16 @@ window.__ModuleLoader__.load({
227
264
 
228
265
  function syncButton() {
229
266
  const tier = currentTier();
230
- const t = tierOf(tier);
267
+ const def = tierOf(tier);
268
+ const label = t(def.key);
269
+ const summary = t("button.title.summary", { label, value: def.value });
270
+ const hint = t("button.title.hint", {
271
+ list: TIERS.map((tierDef) => `${t(tierDef.key)} ${tierDef.value}`).join(" / ")
272
+ });
231
273
  btn.innerHTML = barIcon(tier);
232
274
  btn.classList.toggle("active", tier !== "standard");
233
- btn.setAttribute("aria-label", `对话区宽度档位:${t.label}(${t.value}),点击选择档位`);
234
- btn.title =
235
- `对话区宽度档位:${t.label}(${t.value})\n` +
236
- "点击选择:标准 748px / 中等 960px / 宽 1280px / 超宽 1400px / 全宽 100%";
275
+ btn.setAttribute("aria-label", t("button.aria", { label, value: def.value }));
276
+ btn.title = `${summary}\n${hint}`;
237
277
  }
238
278
 
239
279
  /* ---- tier menu ---- */
@@ -242,15 +282,15 @@ window.__ModuleLoader__.load({
242
282
  menu.setAttribute("role", "menu");
243
283
  menu.hidden = true;
244
284
 
245
- for (const t of TIERS) {
285
+ for (const def of TIERS) {
246
286
  const item = document.createElement("button");
247
287
  item.type = "button";
248
288
  item.setAttribute("role", "menuitemradio");
249
- item.setAttribute("data-tier", t.id);
250
- item.innerHTML = `<span class="dshwm-label">${t.label}</span><span class="dshwm-value">${t.value}</span>`;
289
+ item.setAttribute("data-tier", def.id);
290
+ item.innerHTML = `<span class="dshwm-label">${t(def.key)}</span><span class="dshwm-value">${def.value}</span>`;
251
291
  item.addEventListener("click", (e) => {
252
292
  if (e && e.stopPropagation) e.stopPropagation();
253
- applyTier(t.id);
293
+ applyTier(def.id);
254
294
  hideMenu();
255
295
  });
256
296
  menu.appendChild(item);
@@ -263,6 +303,8 @@ window.__ModuleLoader__.load({
263
303
  const on = items[i].getAttribute("data-tier") === tier;
264
304
  items[i].classList.toggle("selected", on);
265
305
  items[i].setAttribute("aria-checked", String(on));
306
+ const labelEl = items[i].querySelector(".dshwm-label");
307
+ if (labelEl) labelEl.textContent = t(tierOf(items[i].getAttribute("data-tier")).key);
266
308
  }
267
309
  }
268
310
 
@@ -301,6 +343,13 @@ window.__ModuleLoader__.load({
301
343
  window.setTimeout(() => btn.classList.remove("pulse"), 700);
302
344
  }
303
345
 
346
+ /* ---- re-render localized copy when the app language changes ---- */
347
+ const renderTexts = () => {
348
+ syncButton();
349
+ syncMenu();
350
+ };
351
+ const unsubscribeLocale = ctx.locale.subscribe(renderTexts);
352
+
304
353
  /* ---- attach once the app shell has mounted ---- */
305
354
  let attached = false;
306
355
 
@@ -339,6 +388,7 @@ window.__ModuleLoader__.load({
339
388
 
340
389
  /* ---- disposer ---- */
341
390
  return () => {
391
+ unsubscribeLocale();
342
392
  clearInterval(readyTimer);
343
393
  clearInterval(healTimer);
344
394
  clearTimeout(timeout);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-width-tiers",
3
- "version": "1.0.0",
4
- "description": "DSH Web client plugin: chat content width tiers (standard / medium / wide / ultra / full) with a floating picker button. Frees wide tables from the app's hard-coded 748px content cap.",
3
+ "version": "1.0.1",
4
+ "description": "DSH Web client plugin: chat content width tiers (standard / medium / wide / ultra / full) with a floating picker button. Frees wide tables from the app's hard-coded 748px content cap. UI copy follows the app language (zh / en).",
5
5
  "license": "MIT",
6
6
  "author": "aaronlei",
7
7
  "publishConfig": {
@@ -24,7 +24,8 @@
24
24
  "client": {
25
25
  "platform": "web",
26
26
  "inject": [
27
- "@deepseek-ai/dsh-client-ui-layout"
27
+ "@deepseek-ai/dsh-client-ui-layout",
28
+ "@deepseek-ai/dsh-client-locale"
28
29
  ]
29
30
  }
30
31
  },