@azure-id/orc 1.9.2 → 2.0.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/CHANGELOG.md +321 -0
- package/README-id.md +21 -36
- package/README.md +25 -36
- package/bin/build-agents.js +117 -20
- package/bin/cli.js +725 -29
- package/bin/gotcha-import.js +1081 -0
- package/bin/gotcha.js +1286 -0
- package/bin/graph-query.js +1 -1
- package/bin/graph.js +717 -717
- package/bin/habit.js +1453 -0
- package/bin/mockrun-catalog.js +281 -276
- package/bin/run-undo.js +398 -0
- package/bin/trace-write.js +657 -0
- package/bin/verify-contracts.js +525 -79
- package/bin/verify-package.js +51 -4
- package/bin/webui/api.js +26 -0
- package/bin/webui/app.html +239 -232
- package/bin/webui/css/00-tokens.css +110 -92
- package/bin/webui/css/04-motion.css +87 -0
- package/bin/webui/css/06-responsive.css +203 -178
- package/bin/webui/css/panels/behaviour.css +205 -0
- package/bin/webui/fixtures/behaviour.js +532 -0
- package/bin/webui/fixtures/index.js +34 -0
- package/bin/webui/fixtures/knowledge.js +7 -1
- package/bin/webui/fixtures/stats.js +16 -0
- package/bin/webui/i18n/en/behaviour.json +143 -0
- package/bin/webui/i18n/en/nav.json +25 -24
- package/bin/webui/i18n/en/tour.json +37 -35
- package/bin/webui/i18n/id/behaviour.json +143 -0
- package/bin/webui/i18n/id/nav.json +25 -24
- package/bin/webui/i18n/id/tour.json +37 -35
- package/bin/webui/js/01-i18n.js +155 -154
- package/bin/webui/js/90-tour.js +498 -494
- package/bin/webui/js/91-shortcuts.js +126 -126
- package/bin/webui/js/99-boot.js +121 -118
- package/bin/webui/js/panels/behaviour.js +1022 -0
- package/mock-run/INDEX.md +109 -107
- package/mock-run/gotcha-import.md +118 -0
- package/mock-run/habits.md +129 -0
- package/mock-run/orc-quick.md +6 -1
- package/package.json +1 -1
- package/templates/agents/MODEL-MAPPING.md +7 -7
- package/templates/agents/orc-advisor-opus-5-xhigh.md +1 -7
- package/templates/agents/orc-analyze-mini-opus-5-med.md +1 -6
- package/templates/agents/orc-analyze-mini-sonnet-5-high.md +1 -4
- package/templates/agents/orc-claude-writer-opus-4-8-high.md +48 -53
- package/templates/agents/orc-claude-writer-opus-5-med.md +1 -8
- package/templates/agents/orc-context-combiner-opus-5-high.md +1 -11
- package/templates/agents/orc-executor-haiku-4-5.md +14 -6
- package/templates/agents/orc-executor-opus-4-7-high.md +14 -6
- package/templates/agents/orc-executor-opus-4-7-med.md +14 -6
- package/templates/agents/orc-executor-opus-4-8-high.md +14 -6
- package/templates/agents/orc-executor-opus-5-high.md +14 -6
- package/templates/agents/orc-executor-opus-5-low.md +14 -6
- package/templates/agents/orc-executor-opus-5-med.md +14 -6
- package/templates/agents/orc-executor-sonnet-4-6-high.md +14 -6
- package/templates/agents/orc-executor-sonnet-4-6-med.md +14 -6
- package/templates/agents/orc-executor-sonnet-5-high.md +14 -6
- package/templates/agents/orc-graph-noter-sonnet-4-6-med.md +1 -10
- package/templates/agents/orc-judge-opus-5-xhigh.md +5 -9
- package/templates/agents/orc-learn-writer-opus-5-low.md +1 -7
- package/templates/agents/orc-pattern-codifier-opus-5-med.md +1 -8
- package/templates/agents/orc-pattern-codifier-sonnet-5-high.md +58 -63
- package/templates/agents/orc-planner-mini-opus-5-med.md +1 -4
- package/templates/agents/orc-planner-mini-sonnet-5-high.md +1 -2
- package/templates/agents/orc-planner-opus-5-med.md +1 -4
- package/templates/agents/orc-recon-opus-5-low.md +1 -8
- package/templates/agents/orc-recon-sonnet-4-6-med.md +1 -8
- package/templates/agents/orc-retro-opus-5-med.md +6 -8
- package/templates/agents/orc-retro-sonnet-5-high.md +6 -7
- package/templates/agents/orc-reviewer-opus-5-med.md +52 -16
- package/templates/agents/orc-scout-opus-5-low.md +1 -6
- package/templates/agents/orc-scout-sonnet-4-6-high.md +35 -39
- package/templates/agents/orc-system-analyst-opus-5-high.md +1 -6
- package/templates/agents/orc-test-author-opus-5-med.md +4 -5
- package/templates/agents/orc-trace-writer-haiku-4-5.md +3 -7
- package/templates/agents/orc-verifier-opus-5-med.md +16 -8
- package/templates/agents/orc-wiki-scanner-opus-4-8-high.md +74 -79
- package/templates/agents/orc-wiki-scanner-opus-5-med.md +1 -8
- package/templates/agents/orc-wiki-scanner-sonnet-5-high.md +97 -106
- package/templates/commands/orc-analyze.md +13 -21
- package/templates/commands/orc-fast.md +10 -15
- package/templates/commands/orc-poly.md +12 -21
- package/templates/commands/orc-pr-driver.md +11 -30
- package/templates/commands/orc-pr-setup.md +10 -31
- package/templates/commands/orc-route.md +11 -41
- package/templates/commands/orc-test.md +5 -60
- package/templates/hooks/README.md +34 -0
- package/templates/hooks/orc-session-hook.js +264 -0
- package/templates/hooks/orc-statusline.js +3 -1
- package/templates/skills/_shared/README.md +9 -0
- package/templates/skills/_shared/code-graph.md +47 -55
- package/templates/skills/_shared/config-precedence.md +3 -1
- package/templates/skills/_shared/extra-dispatch.md +73 -88
- package/templates/skills/_shared/gotchas.md +228 -177
- package/templates/skills/_shared/habits.md +101 -0
- package/templates/skills/_shared/lane-contract.md +84 -0
- package/templates/skills/_shared/phases/README.md +142 -83
- package/templates/skills/_shared/phases/analyst-gates.md +10 -21
- package/templates/skills/_shared/phases/execution.md +8 -14
- package/templates/skills/_shared/phases/house-rules.md +27 -32
- package/templates/skills/_shared/phases/intake.md +127 -133
- package/templates/skills/_shared/phases/mock-example.md +46 -56
- package/templates/skills/_shared/phases/plan-handoff.md +91 -97
- package/templates/skills/_shared/phases/planning.md +7 -17
- package/templates/skills/_shared/phases/preflight.md +19 -42
- package/templates/skills/_shared/phases/review.md +23 -27
- package/templates/skills/_shared/phases/rules.md +18 -42
- package/templates/skills/_shared/phases/scoring.md +55 -65
- package/templates/skills/_shared/phases/security-checklist.md +46 -50
- package/templates/skills/_shared/phases/security.md +45 -55
- package/templates/skills/_shared/phases/ship.md +6 -15
- package/templates/skills/_shared/phases/stop-resume.md +2 -5
- package/templates/skills/_shared/phases/summary.md +73 -48
- package/templates/skills/_shared/phases/testgen.md +41 -51
- package/templates/skills/_shared/phases/trace-verbs.md +433 -0
- package/templates/skills/_shared/phases/trace.md +136 -367
- package/templates/skills/_shared/phases/verify.md +62 -70
- package/templates/skills/_shared/phases/wave-grouping.md +128 -133
- package/templates/skills/_shared/phases/wiki-consult.md +10 -6
- package/templates/skills/_shared/read-ladder.md +2 -55
- package/templates/skills/_shared/return-validation.md +17 -70
- package/templates/skills/_shared/review-slice.md +79 -0
- package/templates/skills/_shared/smoke-gate.md +46 -28
- package/templates/skills/context-combiner/SKILL.md +15 -44
- package/templates/skills/orc/SKILL.md +34 -62
- package/templates/skills/orc/references/pattern-gate.md +89 -89
- package/templates/skills/orc/references/phases/intake.md +41 -47
- package/templates/skills/orc/references/phases/integration.md +13 -19
- package/templates/skills/orc/references/preflight-report.md +8 -9
- package/templates/skills/orc/references/ultra-mode.md +8 -6
- package/templates/skills/orc/subskills/orc-execution/SKILL.md +27 -73
- package/templates/skills/orc/subskills/orc-execution/core.md +12 -99
- package/templates/skills/orc/subskills/orc-execution/subagent.md +14 -13
- package/templates/skills/orc/subskills/orc-review-verify/SKILL.md +11 -52
- package/templates/skills/orc/subskills/orc-review-verify/core.md +52 -135
- package/templates/skills/orc/subskills/orc-review-verify/subagent.md +7 -7
- package/templates/skills/orc/subskills/orc-testgen/SKILL.md +11 -22
- package/templates/skills/orc/subskills/orc-testgen/core.md +20 -59
- package/templates/skills/orc/subskills/orc-testgen/subagent.md +7 -7
- package/templates/skills/orc-advisor/SKILL.md +56 -60
- package/templates/skills/orc-analyze/SKILL.md +30 -66
- package/templates/skills/orc-analyze/schemas/report-audit.md +2 -1
- package/templates/skills/orc-analyze/schemas/report-prose.md +2 -1
- package/templates/skills/orc-analyze-mini/SKILL.md +35 -70
- package/templates/skills/orc-diy/README.md +31 -0
- package/templates/skills/orc-diy/SKILL.md +23 -74
- package/templates/skills/orc-diy/references/blocks/pattern.md +18 -18
- package/templates/skills/orc-fast/SKILL.md +44 -72
- package/templates/skills/orc-judge/SKILL.md +77 -82
- package/templates/skills/orc-mini/SKILL.md +61 -109
- package/templates/skills/orc-pattern/SKILL.md +27 -48
- package/templates/skills/orc-poly/SKILL.md +32 -61
- package/templates/skills/orc-pr-driver/SKILL.md +25 -51
- package/templates/skills/orc-pr-driver/references/green-gate.md +113 -105
- package/templates/skills/orc-pr-setup/SKILL.md +20 -45
- package/templates/skills/orc-quick/README.md +43 -2
- package/templates/skills/orc-quick/SKILL.md +76 -107
- package/templates/skills/orc-quick/references/dispatch-gate.md +16 -5
- package/templates/skills/orc-quick/references/gh-mode.md +48 -1
- package/templates/skills/orc-quick/references/look.md +3 -1
- package/templates/skills/orc-retro/SKILL.md +19 -18
- package/templates/skills/orc-retro/examples/retro-mock.md +1 -1
- package/templates/skills/orc-route/SKILL.md +25 -45
- package/templates/skills/orc-test/SKILL.md +16 -37
- package/templates/skills/orc-verify/SKILL.md +14 -32
- package/templates/skills/orc-wait/SKILL.md +156 -163
- package/templates/skills/orc-wiki/references/phases/phase-0.md +1 -6
- package/templates/skills/orc-wiki/references/phases/phase-1.md +1 -6
- package/templates/skills/orc-wiki/references/phases/phase-2.md +1 -6
- package/templates/skills/orc-wiki/references/phases/phase-3.md +1 -6
- package/templates/skills/orc-wiki/references/phases/phase-3c.md +1 -6
package/bin/webui/js/01-i18n.js
CHANGED
|
@@ -1,154 +1,155 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/* 01-i18n.js — orc ui client
|
|
3
|
-
LANGS, loadLang, setLang, t, applyStaticText, cycleLang.
|
|
4
|
-
|
|
5
|
-
Keys are written out IN FULL, never assembled from a fragment. The v0.48.1
|
|
6
|
-
file split is by key PREFIX only; `docs.ship.confirm` is still spelled
|
|
7
|
-
`docs.ship.confirm` at every call site.
|
|
8
|
-
|
|
9
|
-
Loaded by app.html in the order its numeric prefix names. Classic
|
|
10
|
-
script, no import/export: an ES module import carries no query string,
|
|
11
|
-
and every static request here needs the per-launch session token. */
|
|
12
|
-
|
|
13
|
-
/* ------------------------------------------------------------------- i18n -- */
|
|
14
|
-
/*
|
|
15
|
-
THE SCOPE RULE, and it is deliberately narrow: only the panel's OWN prose is
|
|
16
|
-
translated. Everything that arrives from `bin/cli.js --json` stays exactly as
|
|
17
|
-
the CLI wrote it — config keys and their descriptions, values, agent names,
|
|
18
|
-
model ids, file paths, commands, `orc doctor` messages, command output. Those
|
|
19
|
-
are identifiers, not sentences: a translated config key is a key that does not
|
|
20
|
-
exist, and a translated command is a command you cannot type. So `t()` is
|
|
21
|
-
never applied to a value read out of a payload, and neither string table
|
|
22
|
-
contains a single ORC key name.
|
|
23
|
-
|
|
24
|
-
The tables are plain JSON served as static assets. Adding a language is a
|
|
25
|
-
FOLDER in i18n/ plus one row in LANGS — no build step, no library, no
|
|
26
|
-
dependency, and no server change (serve.js walks i18n/ at boot).
|
|
27
|
-
*/
|
|
28
|
-
const LANGS = [
|
|
29
|
-
{ code: "en", label: "English" },
|
|
30
|
-
{ code: "id", label: "Bahasa Indonesia" },
|
|
31
|
-
];
|
|
32
|
-
const LANG_KEY = "orc-ui-lang";
|
|
33
|
-
|
|
34
|
-
// v0.48.1 — one file per namespace instead of one 53 KB table, so changing the
|
|
35
|
-
// Docs panel's wording means opening i18n/en/docs.json rather than paging
|
|
36
|
-
// through every string in the panel.
|
|
37
|
-
//
|
|
38
|
-
// A plain array, and deliberately NOT an index file to fetch: an index would be
|
|
39
|
-
// one more round trip and one more thing to forget to update. A namespace owns
|
|
40
|
-
// one or more key PREFIXES (`stats` owns `stats.*` and `cost.*`), which the
|
|
41
|
-
// test suite asserts — a key whose prefix belongs to no namespace would load
|
|
42
|
-
// nowhere and render as a raw dotted string.
|
|
43
|
-
const NAMESPACES = [
|
|
44
|
-
"common",
|
|
45
|
-
"nav",
|
|
46
|
-
"banner",
|
|
47
|
-
"overview",
|
|
48
|
-
"settings",
|
|
49
|
-
"lanes",
|
|
50
|
-
"rules",
|
|
51
|
-
"runs",
|
|
52
|
-
"knowledge",
|
|
53
|
-
"stats",
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
let
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (s === undefined) s = key;
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
//
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
//
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
/* 01-i18n.js — orc ui client
|
|
3
|
+
LANGS, loadLang, setLang, t, applyStaticText, cycleLang.
|
|
4
|
+
|
|
5
|
+
Keys are written out IN FULL, never assembled from a fragment. The v0.48.1
|
|
6
|
+
file split is by key PREFIX only; `docs.ship.confirm` is still spelled
|
|
7
|
+
`docs.ship.confirm` at every call site.
|
|
8
|
+
|
|
9
|
+
Loaded by app.html in the order its numeric prefix names. Classic
|
|
10
|
+
script, no import/export: an ES module import carries no query string,
|
|
11
|
+
and every static request here needs the per-launch session token. */
|
|
12
|
+
|
|
13
|
+
/* ------------------------------------------------------------------- i18n -- */
|
|
14
|
+
/*
|
|
15
|
+
THE SCOPE RULE, and it is deliberately narrow: only the panel's OWN prose is
|
|
16
|
+
translated. Everything that arrives from `bin/cli.js --json` stays exactly as
|
|
17
|
+
the CLI wrote it — config keys and their descriptions, values, agent names,
|
|
18
|
+
model ids, file paths, commands, `orc doctor` messages, command output. Those
|
|
19
|
+
are identifiers, not sentences: a translated config key is a key that does not
|
|
20
|
+
exist, and a translated command is a command you cannot type. So `t()` is
|
|
21
|
+
never applied to a value read out of a payload, and neither string table
|
|
22
|
+
contains a single ORC key name.
|
|
23
|
+
|
|
24
|
+
The tables are plain JSON served as static assets. Adding a language is a
|
|
25
|
+
FOLDER in i18n/ plus one row in LANGS — no build step, no library, no
|
|
26
|
+
dependency, and no server change (serve.js walks i18n/ at boot).
|
|
27
|
+
*/
|
|
28
|
+
const LANGS = [
|
|
29
|
+
{ code: "en", label: "English" },
|
|
30
|
+
{ code: "id", label: "Bahasa Indonesia" },
|
|
31
|
+
];
|
|
32
|
+
const LANG_KEY = "orc-ui-lang";
|
|
33
|
+
|
|
34
|
+
// v0.48.1 — one file per namespace instead of one 53 KB table, so changing the
|
|
35
|
+
// Docs panel's wording means opening i18n/en/docs.json rather than paging
|
|
36
|
+
// through every string in the panel.
|
|
37
|
+
//
|
|
38
|
+
// A plain array, and deliberately NOT an index file to fetch: an index would be
|
|
39
|
+
// one more round trip and one more thing to forget to update. A namespace owns
|
|
40
|
+
// one or more key PREFIXES (`stats` owns `stats.*` and `cost.*`), which the
|
|
41
|
+
// test suite asserts — a key whose prefix belongs to no namespace would load
|
|
42
|
+
// nowhere and render as a raw dotted string.
|
|
43
|
+
const NAMESPACES = [
|
|
44
|
+
"common",
|
|
45
|
+
"nav",
|
|
46
|
+
"banner",
|
|
47
|
+
"overview",
|
|
48
|
+
"settings",
|
|
49
|
+
"lanes",
|
|
50
|
+
"rules",
|
|
51
|
+
"runs",
|
|
52
|
+
"knowledge",
|
|
53
|
+
"stats",
|
|
54
|
+
"behaviour",
|
|
55
|
+
"flow",
|
|
56
|
+
"crosslink",
|
|
57
|
+
"learn",
|
|
58
|
+
"mockrun",
|
|
59
|
+
"maintenance",
|
|
60
|
+
"pact",
|
|
61
|
+
"boundary",
|
|
62
|
+
"wait",
|
|
63
|
+
"hookui",
|
|
64
|
+
"handoff",
|
|
65
|
+
"challenge",
|
|
66
|
+
"docs",
|
|
67
|
+
"test",
|
|
68
|
+
"extra",
|
|
69
|
+
"experiment",
|
|
70
|
+
"tour",
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
let lang = "en";
|
|
74
|
+
// English is loaded first and kept as the FALLBACK table: a key the other
|
|
75
|
+
// language has not translated yet renders in English rather than as a raw
|
|
76
|
+
// dotted key. A half-finished translation degrades to mixed prose, never to
|
|
77
|
+
// debug output on somebody's screen.
|
|
78
|
+
let DICT = {};
|
|
79
|
+
let DICT_EN = {};
|
|
80
|
+
|
|
81
|
+
// The namespaces are fetched in parallel and merged into ONE flat table, so
|
|
82
|
+
// `t()` is unchanged and no call site knows the split happened.
|
|
83
|
+
//
|
|
84
|
+
// A namespace that fails to load falls back to ENGLISH for its keys rather than
|
|
85
|
+
// rejecting the whole language: a network hiccup on one file should cost that
|
|
86
|
+
// file's prose, not the entire panel. English itself has no fallback below it,
|
|
87
|
+
// so a failure there rejects and boot() lands on raw keys — ugly, never blank.
|
|
88
|
+
function loadLang(code) {
|
|
89
|
+
return Promise.all(
|
|
90
|
+
NAMESPACES.map((ns) =>
|
|
91
|
+
fetch(`/i18n/${code}/${ns}.json`, { headers: { "x-orc-token": TOKEN }, cache: "no-store" })
|
|
92
|
+
.then((r) => {
|
|
93
|
+
if (!r.ok) throw new Error(`i18n ${code}/${ns} ${r.status}`);
|
|
94
|
+
return r.json();
|
|
95
|
+
})
|
|
96
|
+
.catch((e) => {
|
|
97
|
+
if (code === "en") throw e;
|
|
98
|
+
return null;
|
|
99
|
+
})
|
|
100
|
+
)
|
|
101
|
+
).then((parts) => Object.assign({}, ...parts.filter(Boolean)));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// A missing or broken table must never blank the UI. Every failure path here
|
|
105
|
+
// lands on English, so the worst case is untranslated text — never empty text.
|
|
106
|
+
async function setLang(code, opts) {
|
|
107
|
+
const rerender = !opts || opts.rerender !== false;
|
|
108
|
+
const want = LANGS.some((l) => l.code === code) ? code : "en";
|
|
109
|
+
try {
|
|
110
|
+
DICT = want === "en" ? DICT_EN : await loadLang(want);
|
|
111
|
+
lang = want;
|
|
112
|
+
} catch (_) {
|
|
113
|
+
DICT = DICT_EN;
|
|
114
|
+
lang = "en";
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
localStorage.setItem(LANG_KEY, lang);
|
|
118
|
+
} catch (_) {}
|
|
119
|
+
document.documentElement.setAttribute("lang", lang);
|
|
120
|
+
applyStaticText();
|
|
121
|
+
if (rerender) route();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function t(key, vars) {
|
|
125
|
+
let s = DICT[key];
|
|
126
|
+
if (s === undefined) s = DICT_EN[key];
|
|
127
|
+
if (s === undefined) s = key;
|
|
128
|
+
if (vars) for (const k of Object.keys(vars)) s = s.split("{" + k + "}").join(String(vars[k]));
|
|
129
|
+
return s;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// English has one plural form and Indonesian has none, so count-aware lookup is
|
|
133
|
+
// a second key rather than a plural-rules engine: `n === 1` picks the singular.
|
|
134
|
+
const tn = (n, key, vars) => t(n === 1 ? key : key + "Plural", Object.assign({ n }, vars || {}));
|
|
135
|
+
|
|
136
|
+
// The parts of the shell that are markup rather than a render function. Called
|
|
137
|
+
// on every language change; panels re-render themselves through `route()`.
|
|
138
|
+
function applyStaticText() {
|
|
139
|
+
for (const node of document.querySelectorAll("[data-i18n]")) node.textContent = t(node.dataset.i18n);
|
|
140
|
+
const tt = $("#theme-toggle");
|
|
141
|
+
if (tt) tt.textContent = document.documentElement.getAttribute("data-theme") === "light" ? t("rail.dark") : t("rail.light");
|
|
142
|
+
const hint = $("#shortcut-hint");
|
|
143
|
+
if (hint) hint.title = t("rail.shortcuts");
|
|
144
|
+
const label = $("#lang-label");
|
|
145
|
+
if (label) label.textContent = (LANGS.find((l) => l.code === lang) || LANGS[0]).label;
|
|
146
|
+
const btn = $("#lang-toggle");
|
|
147
|
+
if (btn) btn.title = t("lang.title");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Two languages, so the control is a TOGGLE rather than a menu: one click, no
|
|
151
|
+
// dropdown to open. A third language would make this a <select>; two do not.
|
|
152
|
+
function cycleLang() {
|
|
153
|
+
const i = LANGS.findIndex((l) => l.code === lang);
|
|
154
|
+
setLang(LANGS[(i + 1) % LANGS.length].code);
|
|
155
|
+
}
|