@ragnoryok1/dsh-client-locale-ru 0.2.0 → 0.2.2

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/lib/index.d.ts CHANGED
@@ -1,5 +1,11 @@
1
+ //#region src/index.d.ts
1
2
  /**
2
3
  * Russian (ru) language pack, node half. Pure localization contribution: the
3
- * empty apply exists so the plugin appears in the host cordis.yml / Loader.
4
+ * empty apply exists so the plugin appears in the host cordis.yml / Loader;
5
+ * the browser half ships via exports["./client"], discovered through the
6
+ * package.json dsh.client declaration.
4
7
  */
5
- export declare function apply(): void
8
+ /** Host plugin body — no host-side behavior for a language-pack plugin. */
9
+ declare function apply(): void;
10
+ //#endregion
11
+ export { apply };
@@ -0,0 +1,31 @@
1
+ //#region src/client/typography.d.ts
2
+ /**
3
+ * Russian screen typography for translated strings.
4
+ *
5
+ * The harness locale contract is a flat `Record<string, string>`, so a
6
+ * language pack cannot reach the composed sentences a component builds from
7
+ * several keys, and cannot ask the host to insert typography. The rendered DOM
8
+ * is the one place where every translated string passes through, so this module
9
+ * rewrites text nodes in place. The rules are deliberately conservative: they
10
+ * only fire on unambiguous straight-quote and spaced-hyphen patterns, and the
11
+ * DOM pass skips code, form fields and editable content.
12
+ *
13
+ * Text that changes after the first pass — counters, timers, progress — is
14
+ * rewritten again, so a live «4 с» keeps its non-breaking space.
15
+ */
16
+ /** Guillemets, em dash, ellipsis, and non-breaking spaces in running text. */
17
+ declare function applyRussianTypography(text: string): string;
18
+ /**
19
+ * Start the typography pass on a document and keep it current as the app
20
+ * renders. Returns a disposer that stops observing.
21
+ *
22
+ * @param doc - document whose body carries the rendered interface.
23
+ * @param isActive - whether the pass may run; the rules are Russian, so a pack
24
+ * installed while another language is active must not rewrite that language's
25
+ * punctuation. Checked before every rewrite, so a language switch takes effect
26
+ * on the next render.
27
+ * @returns disposer removing the observer.
28
+ */
29
+ declare function startRussianTypography(doc: Document, isActive?: () => boolean): () => void;
30
+ //#endregion
31
+ export { applyRussianTypography, startRussianTypography };
package/lib/typography.js CHANGED
@@ -9,6 +9,9 @@
9
9
  * rewrites text nodes in place. The rules are deliberately conservative: they
10
10
  * only fire on unambiguous straight-quote and spaced-hyphen patterns, and the
11
11
  * DOM pass skips code, form fields and editable content.
12
+ *
13
+ * Text that changes after the first pass — counters, timers, progress — is
14
+ * rewritten again, so a live «4 с» keeps its non-breaking space.
12
15
  */
13
16
  /** Straight double quotes around a span become Russian guillemets. */
14
17
  const QUOTED = /"([^"\n]{1,200})"/g;
@@ -20,9 +23,20 @@ const ELLIPSIS = /\.{3}(?=\s|$)/g;
20
23
  const NUMBER_UNIT = /(\d) ([а-яё]{1,24})(?![а-яё])/giu;
21
24
  /** Non-breaking space keeps a number attached to a short unit-like token. */
22
25
  const NUMBER_SYMBOL = /(\d) ([%°₽$€£]|кб|КБ|МБ|ГБ)(?=\s|$)/giu;
26
+ /**
27
+ * A short word — a preposition, a conjunction or a particle — keeps the word
28
+ * that follows it, so a line break cannot leave it alone at the end of a line.
29
+ * Russian typography forbids a one-letter word there and discourages a
30
+ * two-letter one, and the list holds only the words that never carry stress.
31
+ *
32
+ * A numeric range rule would be the obvious neighbour — Russian writes ranges
33
+ * with an en dash — but the pack's only digit-hyphen-digit string is the cron
34
+ * example `0 9 * * 1-5`, which an en dash would corrupt. Measured, and left out.
35
+ */
36
+ const SHORT_WORD = /(?<=^|[\s(«"—])((?:в|во|на|за|к|ко|с|со|о|об|от|до|по|из|у|и|а|но|да|не|ни|же|ли|бы|то)) (?=[«"(]?[а-яё])/giu;
23
37
  /** Guillemets, em dash, ellipsis, and non-breaking spaces in running text. */
24
38
  function applyRussianTypography(text) {
25
- return text.replace(QUOTED, "«$1»").replace(SPACED_HYPHEN, " — ").replace(ELLIPSIS, "…").replace(NUMBER_UNIT, "$1\xA0$2").replace(NUMBER_SYMBOL, "$1\xA0$2");
39
+ return text.replace(QUOTED, "«$1»").replace(SPACED_HYPHEN, " — ").replace(ELLIPSIS, "…").replace(NUMBER_UNIT, "$1\xA0$2").replace(NUMBER_SYMBOL, "$1\xA0$2").replace(SHORT_WORD, "$1\xA0");
26
40
  }
27
41
  /** Elements whose text is code, data or user input and must stay verbatim. */
28
42
  const SKIP_SELECTOR = [
@@ -38,40 +52,46 @@ const SKIP_SELECTOR = [
38
52
  "[contenteditable]:not([contenteditable=\"false\"])",
39
53
  "[data-typography=\"off\"]"
40
54
  ].join(",");
41
- /** Text nodes already rewritten, so a later pass leaves them alone. */
42
- const processed = /* @__PURE__ */ new WeakSet();
43
55
  /** Whether the node sits inside content that must not be rewritten. */
44
56
  function isSkipped(node) {
45
57
  const element = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
46
58
  return element === null || element.closest(SKIP_SELECTOR) !== null;
47
59
  }
48
- function rewriteNode(node) {
49
- if (node.nodeType === Node.TEXT_NODE) {
50
- if (processed.has(node)) return;
51
- processed.add(node);
52
- const before = node.data;
53
- const after = applyRussianTypography(before);
54
- if (after !== before) node.data = after;
55
- return;
56
- }
57
- if (node.nodeType !== Node.ELEMENT_NODE || isSkipped(node)) return;
58
- for (const child of node.childNodes) rewriteNode(child);
59
- }
60
60
  /**
61
61
  * Start the typography pass on a document and keep it current as the app
62
62
  * renders. Returns a disposer that stops observing.
63
63
  *
64
64
  * @param doc - document whose body carries the rendered interface.
65
+ * @param isActive - whether the pass may run; the rules are Russian, so a pack
66
+ * installed while another language is active must not rewrite that language's
67
+ * punctuation. Checked before every rewrite, so a language switch takes effect
68
+ * on the next render.
65
69
  * @returns disposer removing the observer.
66
70
  */
67
- function startRussianTypography(doc) {
71
+ function startRussianTypography(doc, isActive = () => true) {
68
72
  const root = doc.body;
69
73
  if (root === null) return () => {};
74
+ /** Text nodes already rewritten, so a batch of mutations does not re-walk them. */
75
+ const processed = /* @__PURE__ */ new WeakSet();
76
+ function rewriteNode(node) {
77
+ if (!isActive()) return;
78
+ if (node.nodeType === Node.TEXT_NODE) {
79
+ if (processed.has(node)) return;
80
+ processed.add(node);
81
+ const before = node.data;
82
+ const after = applyRussianTypography(before);
83
+ if (after !== before) node.data = after;
84
+ return;
85
+ }
86
+ if (node.nodeType !== Node.ELEMENT_NODE || isSkipped(node)) return;
87
+ for (const child of node.childNodes) rewriteNode(child);
88
+ }
70
89
  rewriteNode(root);
71
90
  const observer = new MutationObserver((records) => {
72
91
  for (const record of records) {
73
92
  if (record.type === "characterData") {
74
93
  if (isSkipped(record.target)) continue;
94
+ processed.delete(record.target);
75
95
  rewriteNode(record.target);
76
96
  continue;
77
97
  }
package/package.json CHANGED
@@ -1,20 +1,29 @@
1
1
  {
2
2
  "name": "@ragnoryok1/dsh-client-locale-ru",
3
- "description": "Russian (ru) language pack for the DeepSeek Harness web GUI - installable hybrid dsh.bundle + dsh.client plugin, 53 namespaces, verified against dsh 0.2.1-alpha.1",
4
- "version": "0.2.0",
3
+ "description": "dsh language pack — Russian (ru) locale for the DeepSeek Harness Web GUI: 77 namespaces, 4495 strings, 13 third-party plugin dictionaries, ru plural forms",
4
+ "version": "0.2.2",
5
5
  "keywords": [
6
- "deepseek",
7
- "deepseek-harness",
8
6
  "dsh",
9
- "cordis",
10
- "cordis-plugin",
11
- "localization",
12
- "localisation",
7
+ "deepseek-harness",
8
+ "dsh-plugin",
9
+ "dsh-language-pack",
10
+ "dsh-locale",
11
+ "dsh-i18n",
12
+ "dsh-russian",
13
13
  "language-pack",
14
+ "locale",
14
15
  "i18n",
15
16
  "l10n",
17
+ "localization",
18
+ "localisation",
16
19
  "russian",
17
- "ru"
20
+ "ru",
21
+ "русский",
22
+ "перевод",
23
+ "локализация",
24
+ "typography",
25
+ "cordis",
26
+ "cordis-plugin"
18
27
  ],
19
28
  "publishConfig": {
20
29
  "access": "public"
@@ -37,7 +46,6 @@
37
46
  "default": "./lib/index.js"
38
47
  },
39
48
  "./client": {
40
- "types": "./lib/client.d.ts",
41
49
  "default": "./lib/client.js"
42
50
  },
43
51
  "./typography": {
@@ -59,31 +67,60 @@
59
67
  }
60
68
  },
61
69
  "scripts": {
62
- "build": "tsdown",
70
+ "build": "tsdown && node scripts/normalize-map.mjs",
71
+ "check:readmes": "node scripts/check-readmes.mjs",
63
72
  "check:typography": "node scripts/check-typography.mjs",
73
+ "check:typography:dom": "node scripts/check-typography-dom.mjs",
74
+ "check:locale": "node scripts/check-locale.mjs",
75
+ "check:plural": "node scripts/check-plural.mjs",
76
+ "check:upstream": "node scripts/watch-upstream.mjs --self-test",
77
+ "check:compat": "node scripts/check-compat.mjs",
78
+ "check:peers": "node scripts/check-peers.mjs",
79
+ "check:manifest": "node scripts/check-manifest.mjs",
80
+ "check:built": "node scripts/check-built.mjs",
81
+ "check:size": "node scripts/check-size.mjs",
64
82
  "audit": "node scripts/audit.mjs",
65
- "verify": "npm run build && npm run check:typography && node scripts/audit.mjs",
66
- "prepublishOnly": "npm run build"
83
+ "verify": "npm run check:readmes && npm run check:readmes:pairs && npm run check:changelog && npm run check:manifest && npm run check:built && npm run check:size && npm run check:tarball && npm run check:typography && npm run check:typography:dom && npm run check:locale && npm run check:plural && npm run check:composition && npm run check:namespaces && npm run check:upstream && npm run check:peers && npm run check:workflows && npm run check:descriptors && node scripts/audit.mjs",
84
+ "prepublishOnly": "npm run build",
85
+ "check:composition": "node scripts/check-composition.mjs",
86
+ "namespaces": "node scripts/namespaces.mjs",
87
+ "check:namespaces": "node scripts/namespaces.mjs --check",
88
+ "readmes:record": "node scripts/readmes-pairs.mjs --record",
89
+ "check:readmes:pairs": "node scripts/readmes-pairs.mjs",
90
+ "check:workflows": "node scripts/check-workflows.mjs",
91
+ "check:changelog": "node scripts/check-changelog.mjs",
92
+ "check:tarball": "node scripts/check-tarball.mjs",
93
+ "diff:harness": "node scripts/diff-harness.mjs",
94
+ "fetch:plugins": "node scripts/fetch-plugin-dicts.mjs",
95
+ "report:plugins": "node scripts/report-plugins.mjs",
96
+ "report:descriptors": "node scripts/descriptor-coverage.mjs",
97
+ "apply:descriptors": "node scripts/apply-descriptor-ru.mjs",
98
+ "check:descriptors": "node scripts/apply-descriptor-ru.mjs --check"
67
99
  },
68
100
  "license": "MIT",
69
101
  "peerDependencies": {
70
- "@deepseek-ai/cordis": "^4.0.2",
71
- "@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.2 <0.3.0"
102
+ "@deepseek-ai/cordis": "^4.0.2 || >=4.0.5-0 <4.0.6-0",
103
+ "@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.2 <0.1.1-0 || >=0.1.1-0 <0.1.2-0 || >=0.1.2-0 <0.1.3-0 || >=0.1.3-0 <0.1.5-0 || >=0.1.5-0 <0.1.6-0 || >=0.1.6-0 <0.1.7-0 || >=0.1.7-0 <0.2.0-0 || >=0.2.0-rc.1 <0.2.1-0 || >=0.2.1-0 <0.3.0-0"
72
104
  },
73
105
  "devDependencies": {
74
- "@deepseek-ai/cordis": "^4.0.2",
75
- "@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.2 <0.3.0",
106
+ "@deepseek-ai/cordis": "4.0.5",
107
+ "@deepseek-ai/dsh-client-locale": "0.2.1-rc.2",
108
+ "jsdom": "^30.1.2",
109
+ "semver": "^7.8.5",
76
110
  "tsdown": "^0.22.2",
77
111
  "typescript": "^5.6.0"
78
112
  },
79
113
  "files": [
80
- "lib/",
114
+ "lib/*.js",
115
+ "lib/*.d.ts",
81
116
  "images/",
82
- "assets/",
117
+ "assets/banner.jpg",
83
118
  "cordis.patch.yml",
84
119
  "README.md",
85
120
  "CHANGELOG.md",
86
- "LICENSE"
121
+ "LICENSE",
122
+ "README.en.md",
123
+ "README.zh.md",
124
+ "NAMESPACES.md"
87
125
  ]
88
126
  }
89
-
package/assets/banner.png DELETED
Binary file
package/assets/icon.png DELETED
Binary file
package/lib/client.d.ts DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * Russian (ru) language pack, browser half. The plugin joins the client tree
3
- * and registers `ru` as a selectable language plus a dictionary per namespace.
4
- */
5
- export declare const inject: readonly string[]
6
- export declare function apply(ctx: unknown): void