@goodandready/dsh-russian-lang 0.3.9 → 0.3.10
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 +1 -1
- package/lib/client.js +178 -456
- package/lib/client.template.js +50 -145
- package/lib/translator.js +46 -13
- package/package.json +1 -1
package/lib/client.template.js
CHANGED
|
@@ -226,7 +226,6 @@ window.__ModuleLoader__.load({
|
|
|
226
226
|
// 1b. Пользовательские переопределения + плюрализация.
|
|
227
227
|
// Overrides: пользовательский слой поверх словарей (russian-lang.overrides).
|
|
228
228
|
// Plural: ядро выбирает .one/.other по n===1, русскому нужны few/many.
|
|
229
|
-
const origTranslate = runtime.translate.bind(runtime)
|
|
230
229
|
const getOverrides = () => {
|
|
231
230
|
try {
|
|
232
231
|
const value = scope.getSnapshot().value
|
|
@@ -234,26 +233,7 @@ window.__ModuleLoader__.load({
|
|
|
234
233
|
} catch (err) { return {} }
|
|
235
234
|
}
|
|
236
235
|
const getPluginLocalizationStatus = makePluginLocalizationStatus(RU)
|
|
237
|
-
|
|
238
|
-
runtime.formatNumber = formatNumber
|
|
239
|
-
runtime.formatCompactNumber = formatCompactNumber
|
|
240
|
-
runtime.formatDate = formatDate
|
|
241
|
-
runtime.formatTokens = formatTokens
|
|
242
|
-
runtime.formatRelativeTime = formatRelativeTime
|
|
243
|
-
runtime.formatCurrency = formatCurrency
|
|
244
|
-
runtime.inflect = inflect
|
|
245
|
-
runtime.getPluginLocalizationStatus = getPluginLocalizationStatus
|
|
246
|
-
runtime.stemRussian = stemRussian
|
|
247
|
-
runtime.fuzzyMatchRu = fuzzyMatchRu
|
|
248
|
-
runtime.humanizeError = humanizeError
|
|
249
|
-
runtime.plural = plural
|
|
250
|
-
runtime.pluralForm = pluralForm
|
|
251
|
-
} catch (err) { /* ignore */ }
|
|
252
|
-
// lookup: в ядре 0.1.2 lookup(ns, key, chain) требует третий довод —
|
|
253
|
-
// цепочку языков; в старых ядрах его два. Спрашиваем у самого метода
|
|
254
|
-
// (lookup.length), цепочку берём у ядра (fallbackChain приватный, но в
|
|
255
|
-
// собранном коде доступен), иначе минимальная [active]. Голый вызов без
|
|
256
|
-
// chain ронял чужой слот sidebar.workspaces (chain is not iterable).
|
|
236
|
+
|
|
257
237
|
const lookupChain = () => {
|
|
258
238
|
try {
|
|
259
239
|
const chain = runtime.fallbackChain && runtime.fallbackChain(runtime.getLocale().active)
|
|
@@ -262,79 +242,62 @@ window.__ModuleLoader__.load({
|
|
|
262
242
|
return [runtime.getLocale().active]
|
|
263
243
|
}
|
|
264
244
|
const translationRegistry = new Map()
|
|
265
|
-
const lookup = (ns, key) =>
|
|
266
|
-
|
|
267
|
-
|
|
245
|
+
const lookup = (ns, key) => (runtime.lookup.length >= 3 ? runtime.lookup(ns, key, lookupChain()) : runtime.lookup(ns, key))
|
|
246
|
+
const syncLang = () => {
|
|
247
|
+
try {
|
|
248
|
+
if (typeof document !== 'undefined' && document.documentElement && runtime.getLocale().active === 'ru') document.documentElement.lang = 'ru-RU'
|
|
249
|
+
} catch (err) { /* ignore */ }
|
|
268
250
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
251
|
+
const RUNTIME_PROP_NAMES = ['plural','pluralForm','formatDate','formatCompactNumber','formatTokens','formatNumber','formatRelativeTime','formatCurrency','inflect','getPluginLocalizationStatus','stemRussian','fuzzyMatchRu','humanizeError']
|
|
252
|
+
ctx.effect(() => {
|
|
253
|
+
const origTranslate = runtime.translate
|
|
254
|
+
const origProps = {}
|
|
255
|
+
for (const p of RUNTIME_PROP_NAMES) origProps[p] = runtime[p]
|
|
256
|
+
runtime.plural = plural
|
|
257
|
+
runtime.pluralForm = pluralForm
|
|
258
|
+
runtime.formatDate = formatDate
|
|
259
|
+
runtime.formatCompactNumber = formatCompactNumber
|
|
260
|
+
runtime.formatTokens = formatTokens
|
|
261
|
+
Object.assign(runtime, { formatNumber, formatRelativeTime, formatCurrency, inflect, getPluginLocalizationStatus, stemRussian, fuzzyMatchRu, humanizeError })
|
|
262
|
+
const boundOrig = typeof origTranslate === 'function' ? origTranslate.bind(runtime) : (() => '')
|
|
263
|
+
runtime.translate = function (ns, key, params) {
|
|
264
|
+
if (ns && !RU[ns] && !loadedPluginNames.has(ns)) schedulePluginLoad(ns)
|
|
265
|
+
const ov = getOverrides()
|
|
266
|
+
if (ov[key] !== undefined) return params ? fill(ov[key], params) : ov[key]
|
|
267
|
+
if (runtime.getLocale().active === 'ru' && params) {
|
|
268
|
+
const n = params.n ?? params.count
|
|
269
|
+
if (typeof n === 'number') {
|
|
270
|
+
const form = pluralForm(n)
|
|
271
|
+
const m = /^(.*)[.](one|other)$/.exec(key)
|
|
272
|
+
if (m) {
|
|
273
|
+
if (form === 'few' || form === 'many') {
|
|
274
|
+
const tmpl = lookup(ns, m[1] + '.' + form) ?? lookup('common', m[1] + '.' + form)
|
|
275
|
+
if (tmpl !== undefined) return fill(tmpl, params)
|
|
289
276
|
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
// X.one / X.few / X.many - берём подходящую, иначе как раньше.
|
|
294
|
-
const pluralKey = key + '.' + form
|
|
295
|
-
const template = lookup(ns, pluralKey) ?? lookup('common', pluralKey)
|
|
296
|
-
if (template !== undefined) {
|
|
297
|
-
return fill(template, params)
|
|
277
|
+
} else if (form !== 'other' && !/[.](one|other|few|many)$/.test(key)) {
|
|
278
|
+
const tmpl = lookup(ns, key + '.' + form) ?? lookup('common', key + '.' + form)
|
|
279
|
+
if (tmpl !== undefined) return fill(tmpl, params)
|
|
298
280
|
}
|
|
299
281
|
}
|
|
300
282
|
}
|
|
283
|
+
const res = boundOrig(ns, key, params)
|
|
284
|
+
if (typeof res === 'string' && res && res.length < 300) translationRegistry.set(res.trim(), { ns, key, params, value: res })
|
|
285
|
+
return res
|
|
301
286
|
}
|
|
302
|
-
|
|
303
|
-
if (
|
|
304
|
-
|
|
287
|
+
let removeLang = null
|
|
288
|
+
if (!runtime.getLocale().locales.some((l) => l.id === 'ru') && typeof runtime.addLanguage === 'function') {
|
|
289
|
+
removeLang = runtime.addLanguage({ id: 'ru', label: 'Русский', fallback: 'en' })
|
|
290
|
+
syncLang()
|
|
305
291
|
}
|
|
306
|
-
return
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
const syncLang = () => {
|
|
312
|
-
try {
|
|
313
|
-
if (typeof document !== 'undefined' && document.documentElement
|
|
314
|
-
&& runtime.getLocale().active === 'ru') {
|
|
315
|
-
document.documentElement.lang = 'ru-RU'
|
|
292
|
+
return () => {
|
|
293
|
+
runtime.translate = origTranslate
|
|
294
|
+
for (const p of RUNTIME_PROP_NAMES) {
|
|
295
|
+
if (origProps[p] !== undefined) runtime[p] = origProps[p]
|
|
296
|
+
else delete runtime[p]
|
|
316
297
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const native = runtime.getLocale().locales.some((l) => l.id === 'ru')
|
|
321
|
-
|
|
322
|
-
if (!native) {
|
|
323
|
-
// Ядро не знает ru: регистрируем его через addLanguage (реальный API
|
|
324
|
-
// LocaleRuntime). Родная строка Language берёт меню из snapshot.locales,
|
|
325
|
-
// setLocale() по нему же валидирует выбор — «Русский» появляется в
|
|
326
|
-
// родном списке. (Старый код писал runtime.snapshot/publish напрямую —
|
|
327
|
-
// этих методов в DSH 0.1.2-alpha нет, переключение молча не работало.)
|
|
328
|
-
runtime.addLanguage({ id: 'ru', label: 'Русский', fallback: 'en' })
|
|
329
|
-
syncLang()
|
|
330
|
-
|
|
331
|
-
// Хост-monkey-patch (подмена runtime.host.getSnapshot/set ради
|
|
332
|
-
// preference="ru") удалён: в DSH v0.1.2-alpha.2 settings пишется через
|
|
333
|
-
// ctx.remote.settings.mutate, а adopt() читает preference из scope
|
|
334
|
-
// snapshot напрямую. Подмена host конфликтовала с новой settings-mirror
|
|
335
|
-
// и ломала запись namespace, из-за чего галочки не сохранялись. Выбор
|
|
336
|
-
// языка держим своим russian-lang.enabled; включение делает tryBoot ниже.
|
|
337
|
-
}
|
|
298
|
+
if (typeof removeLang === 'function') { try { removeLang() } catch (_) { /* bestEffort */ } }
|
|
299
|
+
}
|
|
300
|
+
}, 'dsh-russian-lang: runtime-lifecycle')
|
|
338
301
|
|
|
339
302
|
// 3. Флаг russianLang.enabled всегда повторяет активный язык: выбор
|
|
340
303
|
// английского или китайского в родном меню выключает русский и наоборот.
|
|
@@ -2608,65 +2571,7 @@ window.__ModuleLoader__.load({
|
|
|
2608
2571
|
}
|
|
2609
2572
|
|
|
2610
2573
|
const RL_CSS = [
|
|
2611
|
-
'.rl-modal-mask{position:fixed;top:0;left:0;width:100vw;height:100vh;background:var(--dsw-alias-bg-mask);display:flex;align-items:center;justify-content:center;z-index:99999;backdrop-filter:blur(2px)}'
|
|
2612
|
-
'.rl-modal-box{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;width:calc(100vw - 40px);max-width:500px;box-shadow:var(--dsw-alias-shadow-l3);display:flex;flex-direction:column;gap:12px;padding:18px}',
|
|
2613
|
-
'.rl-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;overflow:hidden;transition:border-color .15s ease}',
|
|
2614
|
-
'.rl-head{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;display:flex;align-items:center;gap:12px;padding:14px 18px}',
|
|
2615
|
-
'.rl-head:hover{background:var(--dsw-alias-bg-layer-2)}',
|
|
2616
|
-
'.rl-head-main{flex:1;display:flex;flex-direction:column;gap:4px}',
|
|
2617
|
-
'.rl-title{color:var(--dsw-alias-label-primary);font-size:16px;font-weight:600;line-height:1.4;display:flex;align-items:center;flex-wrap:wrap;gap:8px}',
|
|
2618
|
-
'.rl-sub{color:var(--dsw-alias-label-secondary);font-size:13px}',
|
|
2619
|
-
'.rl-chev{margin-left:auto;flex:none;color:var(--dsw-alias-label-tertiary);display:inline-flex;transition:transform .16s}',
|
|
2620
|
-
'.rl-chev-open{transform:rotate(180deg)}',
|
|
2621
|
-
'.rl-body{border-top:1px solid var(--dsw-alias-border-l2);padding:18px}',
|
|
2622
|
-
'.rl-page{display:flex;flex-direction:column;gap:16px;max-width:960px}',
|
|
2623
|
-
'.rl-section-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:10px;padding:16px 18px;display:flex;flex-direction:column;gap:12px}',
|
|
2624
|
-
'.rl-section-title{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary);display:flex;align-items:center;justify-content:space-between;gap:8px}',
|
|
2625
|
-
'.rl-section-desc{font-size:12px;color:var(--dsw-alias-label-secondary);margin-top:-4px;line-height:1.4}',
|
|
2626
|
-
'.rl-grid-2{display:grid;grid-template-columns:repeat(auto-fit, minmax(280px, 1fr));gap:10px}',
|
|
2627
|
-
'.rl-grid-3{display:grid;grid-template-columns:repeat(auto-fit, minmax(140px, 1fr));gap:10px}',
|
|
2628
|
-
'.rl-badge{font-size:11px;padding:2px 8px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);display:inline-flex;align-items:center;gap:4px;font-weight:500}',
|
|
2629
|
-
'.rl-badge-ok{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent)}',
|
|
2630
|
-
'.rl-badge-warn{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary);background:color-mix(in srgb, var(--dsw-alias-state-warning-primary) 8%, transparent)}',
|
|
2631
|
-
'.rl-badge-dim{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-3)}',
|
|
2632
|
-
'.rl-item-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:4px}',
|
|
2633
|
-
'.rl-item-head{display:flex;align-items:center;justify-content:space-between;gap:8px}',
|
|
2634
|
-
'.rl-item-label{font-size:13px;font-weight:500;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:8px;cursor:pointer}',
|
|
2635
|
-
'.rl-item-desc{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.4}',
|
|
2636
|
-
'.rl-stat-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:2px}',
|
|
2637
|
-
'.rl-stat-val{font-size:16px;font-weight:700;color:var(--dsw-alias-label-primary)}',
|
|
2638
|
-
'.rl-stat-label{font-size:11px;color:var(--dsw-alias-label-secondary);letter-spacing:0.3px}',
|
|
2639
|
-
'.rl-hotkey-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.4;display:flex;align-items:flex-start;gap:10px}',
|
|
2640
|
-
'.rl-hotkey-tag{font-size:11px;font-weight:700;padding:2px 6px;border-radius:4px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);white-space:nowrap}',
|
|
2641
|
-
'.rl-preview-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.4}',
|
|
2642
|
-
'.rl-btn{appearance:none;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:6px 12px;font-size:12px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font-weight:500;display:inline-flex;align-items:center;justify-content:center;gap:6px;transition:all .15s ease;text-decoration:none}',
|
|
2643
|
-
'.rl-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-1);border-color:var(--dsw-alias-label-secondary)}',
|
|
2644
|
-
'.rl-btn-primary{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3);border-color:transparent}',
|
|
2645
|
-
'.rl-btn-primary:hover:not(:disabled){opacity:0.9}',
|
|
2646
|
-
'.rl-select{height:32px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:6px;padding:0 8px;font-size:12px;outline:none;width:100%;max-width:380px}',
|
|
2647
|
-
'.rl-select:focus{border-color:var(--dsw-alias-state-brand-primary)}',
|
|
2648
|
-
'.rl-check{width:16px;height:16px;accent-color:var(--dsw-alias-label-primary);cursor:pointer;flex-shrink:0}',
|
|
2649
|
-
'.rl-hint-text{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.4}',
|
|
2650
|
-
'.rl-actions-row{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding-top:4px}',
|
|
2651
|
-
'.rl-lang-chip{appearance:none;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary);font-size:11px;font-weight:700;padding:2px 7px;border-radius:6px;display:inline-flex;align-items:center;transition:all .15s;margin:0 4px}',
|
|
2652
|
-
'.rl-lang-chip:hover{border-color:var(--dsw-alias-label-primary);color:var(--dsw-alias-label-primary)}',
|
|
2653
|
-
'.rl-lang-chip-active{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}',
|
|
2654
|
-
'.rl-action-btn{appearance:none;background:0 0;border:1px solid transparent;border-radius:4px;color:var(--dsw-alias-label-secondary);cursor:pointer;font-size:11px;padding:2px 5px;display:inline-flex;align-items:center;transition:all .15s}',
|
|
2655
|
-
'.rl-action-btn:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3)}',
|
|
2656
|
-
'.rl-action-btn-active{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l2)}',
|
|
2657
|
-
'.rl-turn-translation{margin:8px 0;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:8px;font-size:13px;line-height:1.5}',
|
|
2658
|
-
'.rl-trans-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;border-bottom:1px solid var(--dsw-alias-border-l2);padding-bottom:4px}',
|
|
2659
|
-
'.rl-trans-title{font-size:11px;font-weight:600;color:var(--dsw-alias-label-secondary);text-transform:uppercase;letter-spacing:0.5px}',
|
|
2660
|
-
'.rl-trans-tools{display:flex;gap:4px}',
|
|
2661
|
-
'.rl-trans-btn{appearance:none;background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);cursor:pointer;padding:2px 7px;border-radius:4px;font-size:11px}',
|
|
2662
|
-
'.rl-trans-btn:hover{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}',
|
|
2663
|
-
'.rl-trans-body{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;user-select:text}',
|
|
2664
|
-
'.rl-export-md-btn{appearance:none;border:1px solid var(--dsw-alias-border-l2);height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;background:transparent;border-radius:18px;justify-content:center;align-items:center;gap:4px;padding:6px 12px;font-size:13px;font-weight:500;display:inline-flex;white-space:nowrap;margin-left:6px;transition:all .15s ease}',
|
|
2665
|
-
'.rl-export-md-btn:hover{background:var(--dsw-alias-interactive-bg-hover)}',
|
|
2666
|
-
'.rl-inspector-hover{position:absolute;pointer-events:none;border:2px solid var(--dsw-alias-state-brand-primary);border-radius:4px;background:color-mix(in srgb,var(--dsw-alias-state-brand-primary) 12%,transparent);box-shadow:0 0 10px color-mix(in srgb,var(--dsw-alias-state-brand-primary) 30%,transparent);z-index:99998;transition:all .06s ease;display:none}',
|
|
2667
|
-
'.rl-inspector-badge{position:absolute;bottom:calc(100% + 4px);left:0;background:var(--dsw-alias-state-brand-primary);color:var(--dsw-alias-label-inverse);font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;white-space:nowrap;box-shadow:var(--dsw-alias-shadow-l2);pointer-events:none}',
|
|
2668
|
-
'.rl-inspector-pill{position:fixed;bottom:18px;right:18px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l1);border-radius:20px;padding:6px 12px;box-shadow:var(--dsw-alias-shadow-l3);display:none;align-items:center;gap:8px;font-size:12px;z-index:99990;user-select:none}',
|
|
2669
|
-
'.rl-inspector-pill-active{border-color:var(--dsw-alias-state-brand-primary);box-shadow:0 0 12px color-mix(in srgb,var(--dsw-alias-state-brand-primary) 35%,transparent)}',
|
|
2574
|
+
'.rl-modal-mask{position:fixed;top:0;left:0;width:100vw;height:100vh;background:var(--dsw-alias-bg-mask);display:flex;align-items:center;justify-content:center;z-index:99999;backdrop-filter:blur(2px)}.rl-modal-box{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;width:calc(100vw - 40px);max-width:500px;box-shadow:var(--dsw-alias-shadow-l3);display:flex;flex-direction:column;gap:12px;padding:18px}.rl-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;overflow:hidden;transition:border-color .15s ease}.rl-head{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;display:flex;align-items:center;gap:12px;padding:14px 18px}.rl-head:hover{background:var(--dsw-alias-bg-layer-2)}.rl-head-main{flex:1;display:flex;flex-direction:column;gap:4px}.rl-title{color:var(--dsw-alias-label-primary);font-size:16px;font-weight:600;line-height:1.4;display:flex;align-items:center;flex-wrap:wrap;gap:8px}.rl-sub{color:var(--dsw-alias-label-secondary);font-size:13px}.rl-chev{margin-left:auto;flex:none;color:var(--dsw-alias-label-tertiary);display:inline-flex;transition:transform .16s}.rl-chev-open{transform:rotate(180deg)}.rl-body{border-top:1px solid var(--dsw-alias-border-l2);padding:18px}.rl-page{display:flex;flex-direction:column;gap:16px;max-width:960px}.rl-section-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:10px;padding:16px 18px;display:flex;flex-direction:column;gap:12px}.rl-section-title{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary);display:flex;align-items:center;justify-content:space-between;gap:8px}.rl-section-desc{font-size:12px;color:var(--dsw-alias-label-secondary);margin-top:-4px;line-height:1.4}.rl-grid-2{display:grid;grid-template-columns:repeat(auto-fit, minmax(280px, 1fr));gap:10px}.rl-grid-3{display:grid;grid-template-columns:repeat(auto-fit, minmax(140px, 1fr));gap:10px}.rl-badge{font-size:11px;padding:2px 8px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);display:inline-flex;align-items:center;gap:4px;font-weight:500}.rl-badge-ok{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent)}.rl-badge-warn{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary);background:color-mix(in srgb, var(--dsw-alias-state-warning-primary) 8%, transparent)}.rl-badge-dim{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-3)}.rl-item-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:4px}.rl-item-head{display:flex;align-items:center;justify-content:space-between;gap:8px}.rl-item-label{font-size:13px;font-weight:500;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:8px;cursor:pointer}.rl-item-desc{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-stat-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:2px}.rl-stat-val{font-size:16px;font-weight:700;color:var(--dsw-alias-label-primary)}.rl-stat-label{font-size:11px;color:var(--dsw-alias-label-secondary);letter-spacing:0.3px}.rl-hotkey-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.4;display:flex;align-items:flex-start;gap:10px}.rl-hotkey-tag{font-size:11px;font-weight:700;padding:2px 6px;border-radius:4px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);white-space:nowrap}.rl-preview-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-btn{appearance:none;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:6px 12px;font-size:12px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font-weight:500;display:inline-flex;align-items:center;justify-content:center;gap:6px;transition:all .15s ease;text-decoration:none}.rl-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-1);border-color:var(--dsw-alias-label-secondary)}.rl-btn-primary{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3);border-color:transparent}.rl-btn-primary:hover:not(:disabled){opacity:0.9}.rl-select{height:32px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:6px;padding:0 8px;font-size:12px;outline:none;width:100%;max-width:380px}.rl-select:focus{border-color:var(--dsw-alias-state-brand-primary)}.rl-check{width:16px;height:16px;accent-color:var(--dsw-alias-label-primary);cursor:pointer;flex-shrink:0}.rl-hint-text{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-actions-row{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding-top:4px}.rl-lang-chip{appearance:none;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary);font-size:11px;font-weight:700;padding:2px 7px;border-radius:6px;display:inline-flex;align-items:center;transition:all .15s;margin:0 4px}.rl-lang-chip:hover{border-color:var(--dsw-alias-label-primary);color:var(--dsw-alias-label-primary)}.rl-lang-chip-active{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.rl-action-btn{appearance:none;background:0 0;border:1px solid transparent;border-radius:4px;color:var(--dsw-alias-label-secondary);cursor:pointer;font-size:11px;padding:2px 5px;display:inline-flex;align-items:center;transition:all .15s}.rl-action-btn:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3)}.rl-action-btn-active{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l2)}.rl-turn-translation{margin:8px 0;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:8px;font-size:13px;line-height:1.5}.rl-trans-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;border-bottom:1px solid var(--dsw-alias-border-l2);padding-bottom:4px}.rl-trans-title{font-size:11px;font-weight:600;color:var(--dsw-alias-label-secondary);text-transform:uppercase;letter-spacing:0.5px}.rl-trans-tools{display:flex;gap:4px}.rl-trans-btn{appearance:none;background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);cursor:pointer;padding:2px 7px;border-radius:4px;font-size:11px}.rl-trans-btn:hover{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}.rl-trans-body{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;user-select:text}.rl-export-md-btn{appearance:none;border:1px solid var(--dsw-alias-border-l2);height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;background:transparent;border-radius:18px;justify-content:center;align-items:center;gap:4px;padding:6px 12px;font-size:13px;font-weight:500;display:inline-flex;white-space:nowrap;margin-left:6px;transition:all .15s ease}.rl-export-md-btn:hover{background:var(--dsw-alias-interactive-bg-hover)}.rl-inspector-hover{position:absolute;pointer-events:none;border:2px solid var(--dsw-alias-state-brand-primary);border-radius:4px;background:color-mix(in srgb,var(--dsw-alias-state-brand-primary) 12%,transparent);box-shadow:0 0 10px color-mix(in srgb,var(--dsw-alias-state-brand-primary) 30%,transparent);z-index:99998;transition:all .06s ease;display:none}.rl-inspector-badge{position:absolute;bottom:calc(100% + 4px);left:0;background:var(--dsw-alias-state-brand-primary);color:var(--dsw-alias-label-inverse);font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;white-space:nowrap;box-shadow:var(--dsw-alias-shadow-l2);pointer-events:none}.rl-inspector-pill{position:fixed;bottom:18px;right:18px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l1);border-radius:20px;padding:6px 12px;box-shadow:var(--dsw-alias-shadow-l3);display:none;align-items:center;gap:8px;font-size:12px;z-index:99990;user-select:none}.rl-inspector-pill-active{border-color:var(--dsw-alias-state-brand-primary);box-shadow:0 0 12px color-mix(in srgb,var(--dsw-alias-state-brand-primary) 35%,transparent)}'
|
|
2670
2575
|
].join('')
|
|
2671
2576
|
const STYLE_ID = 'dsh-russian-lang-styles'
|
|
2672
2577
|
if (typeof document !== 'undefined' && (document.getElementById && !document.getElementById(STYLE_ID))) {
|
package/lib/translator.js
CHANGED
|
@@ -14,23 +14,53 @@ function execPromise(cmd, args, timeoutMs = 15000) {
|
|
|
14
14
|
})
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
function readJsonBody(request, limit = 500_000) {
|
|
17
|
+
export function readJsonBody(request, limit = 500_000) {
|
|
18
18
|
return new Promise((resolve, reject) => {
|
|
19
|
+
// 1. Ранняя проверка Content-Length
|
|
20
|
+
const contentLength = request?.headers?.['content-length']
|
|
21
|
+
if (contentLength && parseInt(contentLength, 10) > limit) {
|
|
22
|
+
const err = new Error('Payload too large')
|
|
23
|
+
err.statusCode = 413
|
|
24
|
+
return reject(err)
|
|
25
|
+
}
|
|
26
|
+
|
|
19
27
|
let body = ''
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
let bytesReceived = 0
|
|
29
|
+
let settled = false
|
|
30
|
+
|
|
31
|
+
const onData = (chunk) => {
|
|
32
|
+
if (settled) return
|
|
33
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))
|
|
34
|
+
bytesReceived += buf.length
|
|
35
|
+
if (bytesReceived > limit) {
|
|
36
|
+
settled = true
|
|
37
|
+
if (typeof request.removeListener === 'function') request.removeListener('data', onData)
|
|
38
|
+
if (typeof request.destroy === 'function') request.destroy()
|
|
39
|
+
const err = new Error('Payload too large')
|
|
40
|
+
err.statusCode = 413
|
|
41
|
+
return reject(err)
|
|
24
42
|
}
|
|
25
|
-
|
|
43
|
+
body += buf.toString('utf8')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
request.on('data', onData)
|
|
47
|
+
|
|
26
48
|
request.on('end', () => {
|
|
49
|
+
if (settled) return
|
|
50
|
+
settled = true
|
|
27
51
|
try {
|
|
28
52
|
resolve(body ? JSON.parse(body) : {})
|
|
29
53
|
} catch (err) {
|
|
54
|
+
err.statusCode = 400
|
|
30
55
|
reject(err)
|
|
31
56
|
}
|
|
32
57
|
})
|
|
33
|
-
|
|
58
|
+
|
|
59
|
+
request.on('error', (err) => {
|
|
60
|
+
if (settled) return
|
|
61
|
+
settled = true
|
|
62
|
+
reject(err)
|
|
63
|
+
})
|
|
34
64
|
})
|
|
35
65
|
}
|
|
36
66
|
|
|
@@ -232,8 +262,9 @@ export function registerTranslator(wctx, settingsCtx) {
|
|
|
232
262
|
})
|
|
233
263
|
response.end(JSON.stringify(status))
|
|
234
264
|
} catch (err) {
|
|
235
|
-
|
|
236
|
-
response.
|
|
265
|
+
const status = err && err.statusCode ? err.statusCode : 500
|
|
266
|
+
response.writeHead(status, { 'content-type': 'application/json; charset=utf-8' })
|
|
267
|
+
response.end(JSON.stringify({ error: err && err.message ? err.message : String(err) }))
|
|
237
268
|
}
|
|
238
269
|
}
|
|
239
270
|
})
|
|
@@ -266,8 +297,9 @@ export function registerTranslator(wctx, settingsCtx) {
|
|
|
266
297
|
})
|
|
267
298
|
response.end(JSON.stringify(result))
|
|
268
299
|
} catch (err) {
|
|
269
|
-
|
|
270
|
-
response.
|
|
300
|
+
const status = err && err.statusCode ? err.statusCode : 500
|
|
301
|
+
response.writeHead(status, { 'content-type': 'application/json; charset=utf-8' })
|
|
302
|
+
response.end(JSON.stringify({ error: err && err.message ? err.message : String(err) }))
|
|
271
303
|
}
|
|
272
304
|
}
|
|
273
305
|
})
|
|
@@ -341,8 +373,9 @@ export function registerTranslator(wctx, settingsCtx) {
|
|
|
341
373
|
})
|
|
342
374
|
response.end(JSON.stringify({ translatedText, engine }))
|
|
343
375
|
} catch (err) {
|
|
344
|
-
|
|
345
|
-
response.
|
|
376
|
+
const status = err && err.statusCode ? err.statusCode : 500
|
|
377
|
+
response.writeHead(status, { 'content-type': 'application/json; charset=utf-8' })
|
|
378
|
+
response.end(JSON.stringify({ error: err && err.message ? err.message : String(err) }))
|
|
346
379
|
}
|
|
347
380
|
}
|
|
348
381
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-russian-lang",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.10",
|
|
4
4
|
"description": "Russian localization for DeepSeek Harness (DSH v0.1.7-rc.1+) web UI: adds Русский as native language option. 100.0% coverage across 11,295 keys (127 namespaces). Features full DSH v0.1.7-rc.1 core support (terminal, archive, command palette, Auto review, trajectory, PTC/Creator presets) and complete GoodAndReady plugin catalog (subscriptions, tts, image-gen, voice, key-limits, notify, commandcode, plugin-console).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|