@luxalgo/vela 0.8.4 → 0.9.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 (139) hide show
  1. package/dist/{DataProvider-Byo8pEv0.d.ts → DataProvider-BGlB1zSc.d.ts} +1 -1
  2. package/dist/{DataProvider-Bw58CjYy.d.cts → DataProvider-zJGp58kb.d.cts} +1 -1
  3. package/dist/{chunk-MOJ4T26N.js → chunk-4WAHYL7Y.js} +1151 -474
  4. package/dist/chunk-O6L27KRB.js +1331 -0
  5. package/dist/{chunk-WY5H4S4I.js → chunk-PZN4RS4T.js} +91 -36
  6. package/dist/{chunk-AUOB7A5Y.js → chunk-WHPQQYH7.js} +29 -13
  7. package/dist/{chunk-UNUVPQFW.js → chunk-XIRSR3D6.js} +2837 -1604
  8. package/dist/{chunk-ALTGHKIM.js → chunk-YRCL3WMD.js} +510 -406
  9. package/dist/{contributions-BY3zSYiZ.d.ts → contributions-BjefWpxQ.d.ts} +106 -25
  10. package/dist/{contributions-DOm40g5-.d.cts → contributions-CpCJisTC.d.cts} +106 -25
  11. package/dist/index.cjs +4485 -2163
  12. package/dist/index.d.cts +67 -25
  13. package/dist/index.d.ts +67 -25
  14. package/dist/index.js +5 -5
  15. package/dist/{keymap-CGOz5F5f.d.ts → keymap-B9_FLhfJ.d.cts} +9 -6
  16. package/dist/{keymap-CGOz5F5f.d.cts → keymap-UolhuXH1.d.ts} +9 -6
  17. package/dist/locales/ar.cjs +2260 -0
  18. package/dist/locales/ar.d.cts +5 -0
  19. package/dist/locales/ar.d.ts +5 -0
  20. package/dist/locales/ar.js +2258 -0
  21. package/dist/locales/de.cjs +2260 -0
  22. package/dist/locales/de.d.cts +5 -0
  23. package/dist/locales/de.d.ts +5 -0
  24. package/dist/locales/de.js +2258 -0
  25. package/dist/locales/en.cjs +2260 -0
  26. package/dist/locales/en.d.cts +5 -0
  27. package/dist/locales/en.d.ts +5 -0
  28. package/dist/locales/en.js +2258 -0
  29. package/dist/locales/es.cjs +2260 -0
  30. package/dist/locales/es.d.cts +5 -0
  31. package/dist/locales/es.d.ts +5 -0
  32. package/dist/locales/es.js +2258 -0
  33. package/dist/locales/fr.cjs +2260 -0
  34. package/dist/locales/fr.d.cts +5 -0
  35. package/dist/locales/fr.d.ts +5 -0
  36. package/dist/locales/fr.js +2258 -0
  37. package/dist/locales/he.cjs +2260 -0
  38. package/dist/locales/he.d.cts +5 -0
  39. package/dist/locales/he.d.ts +5 -0
  40. package/dist/locales/he.js +2258 -0
  41. package/dist/locales/hi.cjs +2260 -0
  42. package/dist/locales/hi.d.cts +5 -0
  43. package/dist/locales/hi.d.ts +5 -0
  44. package/dist/locales/hi.js +2258 -0
  45. package/dist/locales/id.cjs +2260 -0
  46. package/dist/locales/id.d.cts +5 -0
  47. package/dist/locales/id.d.ts +5 -0
  48. package/dist/locales/id.js +2258 -0
  49. package/dist/locales/it.cjs +2260 -0
  50. package/dist/locales/it.d.cts +5 -0
  51. package/dist/locales/it.d.ts +5 -0
  52. package/dist/locales/it.js +2258 -0
  53. package/dist/locales/ja.cjs +2260 -0
  54. package/dist/locales/ja.d.cts +5 -0
  55. package/dist/locales/ja.d.ts +5 -0
  56. package/dist/locales/ja.js +2258 -0
  57. package/dist/locales/ko.cjs +2260 -0
  58. package/dist/locales/ko.d.cts +5 -0
  59. package/dist/locales/ko.d.ts +5 -0
  60. package/dist/locales/ko.js +2258 -0
  61. package/dist/locales/ms.cjs +2260 -0
  62. package/dist/locales/ms.d.cts +5 -0
  63. package/dist/locales/ms.d.ts +5 -0
  64. package/dist/locales/ms.js +2258 -0
  65. package/dist/locales/pl.cjs +2260 -0
  66. package/dist/locales/pl.d.cts +5 -0
  67. package/dist/locales/pl.d.ts +5 -0
  68. package/dist/locales/pl.js +2258 -0
  69. package/dist/locales/pt-BR.cjs +2260 -0
  70. package/dist/locales/pt-BR.d.cts +5 -0
  71. package/dist/locales/pt-BR.d.ts +5 -0
  72. package/dist/locales/pt-BR.js +2258 -0
  73. package/dist/locales/ru.cjs +2260 -0
  74. package/dist/locales/ru.d.cts +5 -0
  75. package/dist/locales/ru.d.ts +5 -0
  76. package/dist/locales/ru.js +2258 -0
  77. package/dist/locales/th.cjs +2260 -0
  78. package/dist/locales/th.d.cts +5 -0
  79. package/dist/locales/th.d.ts +5 -0
  80. package/dist/locales/th.js +2258 -0
  81. package/dist/locales/tr.cjs +2260 -0
  82. package/dist/locales/tr.d.cts +5 -0
  83. package/dist/locales/tr.d.ts +5 -0
  84. package/dist/locales/tr.js +2258 -0
  85. package/dist/locales/vi.cjs +2260 -0
  86. package/dist/locales/vi.d.cts +5 -0
  87. package/dist/locales/vi.d.ts +5 -0
  88. package/dist/locales/vi.js +2258 -0
  89. package/dist/locales/zh-Hans.cjs +2260 -0
  90. package/dist/locales/zh-Hans.d.cts +5 -0
  91. package/dist/locales/zh-Hans.d.ts +5 -0
  92. package/dist/locales/zh-Hans.js +2258 -0
  93. package/dist/locales/zh-Hant.cjs +2260 -0
  94. package/dist/locales/zh-Hant.d.cts +5 -0
  95. package/dist/locales/zh-Hant.d.ts +5 -0
  96. package/dist/locales/zh-Hant.js +2258 -0
  97. package/dist/{options-CSXbjMM5.d.cts → options-CpegHml_.d.cts} +110 -10
  98. package/dist/{options-CSXbjMM5.d.ts → options-D4L3_hv_.d.ts} +110 -10
  99. package/dist/{plugin-BDxUhGO3.d.ts → plugin-DTmulpKM.d.ts} +92 -40
  100. package/dist/{plugin-CiQVyETg.d.cts → plugin-DpNp4aBi.d.cts} +92 -40
  101. package/dist/plugin.cjs +1267 -319
  102. package/dist/plugin.d.cts +7 -6
  103. package/dist/plugin.d.ts +7 -6
  104. package/dist/plugin.js +3 -3
  105. package/dist/providers/binance.cjs +1 -1
  106. package/dist/providers/binance.d.cts +3 -2
  107. package/dist/providers/binance.d.ts +3 -2
  108. package/dist/providers/binance.js +1 -1
  109. package/dist/providers/coinbase.cjs +1 -1
  110. package/dist/providers/coinbase.d.cts +3 -2
  111. package/dist/providers/coinbase.d.ts +3 -2
  112. package/dist/providers/coinbase.js +1 -1
  113. package/dist/providers/hyperliquid.cjs +1 -1
  114. package/dist/providers/hyperliquid.d.cts +3 -2
  115. package/dist/providers/hyperliquid.d.ts +3 -2
  116. package/dist/providers/hyperliquid.js +1 -1
  117. package/dist/{side-panel-_2UK1gSm.d.ts → side-panel-BqUnpfev.d.cts} +13 -2
  118. package/dist/{side-panel-_2UK1gSm.d.cts → side-panel-CYmH1Opm.d.ts} +13 -2
  119. package/dist/{statusline-model-C9tYXuux.d.ts → statusline-model-C3yIY9WE.d.ts} +11 -3
  120. package/dist/{statusline-model-DUBX6Fib.d.cts → statusline-model-pGs3Xvp-.d.cts} +11 -3
  121. package/dist/types-BlrXRLIR.d.cts +2515 -0
  122. package/dist/types-BlrXRLIR.d.ts +2515 -0
  123. package/dist/ui.cjs +1008 -56
  124. package/dist/ui.d.cts +21 -2
  125. package/dist/ui.d.ts +21 -2
  126. package/dist/ui.js +3 -3
  127. package/dist/vela.global.js +4451 -2131
  128. package/dist/vela.global.min.js +57 -57
  129. package/dist/widget.cjs +5819 -2780
  130. package/dist/widget.d.cts +100 -26
  131. package/dist/widget.d.ts +100 -26
  132. package/dist/widget.js +19 -11
  133. package/dist/workspace.cjs +5808 -2787
  134. package/dist/workspace.d.cts +63 -15
  135. package/dist/workspace.d.ts +63 -15
  136. package/dist/workspace.js +6 -6
  137. package/package.json +9 -2
  138. package/dist/chunk-I2U4NZD2.js +0 -340
  139. /package/dist/{chunk-W5YPYZ2P.js → chunk-3EYCX2L4.js} +0 -0
package/dist/plugin.cjs CHANGED
@@ -1,6 +1,913 @@
1
1
  'use strict';
2
2
 
3
+ // src/core/i18n/message.ts
4
+ function msg(id, defaultMessage) {
5
+ return Object.freeze({ id, defaultMessage });
6
+ }
7
+ function withValues(message, values) {
8
+ return Object.freeze({ id: message.id, defaultMessage: message.defaultMessage, values: { ...message.values, ...values } });
9
+ }
10
+
11
+ // src/core/format/numbers.ts
12
+ var BIDI_MARKS = /[‎‏؜]/g;
13
+ function stripBidiMarks(text) {
14
+ return text.replace(BIDI_MARKS, "");
15
+ }
16
+ var numberFormats = /* @__PURE__ */ new Map();
17
+ function numberFormat(settings, options) {
18
+ const key = `${settings.locale}|${settings.numberingSystem}|${JSON.stringify(options)}`;
19
+ let nf = numberFormats.get(key);
20
+ if (!nf) {
21
+ try {
22
+ nf = new Intl.NumberFormat(settings.locale, { ...options, numberingSystem: settings.numberingSystem });
23
+ } catch {
24
+ nf = new Intl.NumberFormat("en", options);
25
+ }
26
+ numberFormats.set(key, nf);
27
+ }
28
+ return nf;
29
+ }
30
+ var symbolCache = /* @__PURE__ */ new Map();
31
+ function numberSymbols(settings) {
32
+ const key = `${settings.locale}|${settings.numberingSystem}`;
33
+ let sym = symbolCache.get(key);
34
+ if (sym) return sym;
35
+ const parts = numberFormat(settings, { useGrouping: false, minimumFractionDigits: 1, maximumFractionDigits: 1 }).formatToParts(-1.5);
36
+ const decimal = stripBidiMarks(parts.find((p) => p.type === "decimal")?.value ?? ".") || ".";
37
+ const minus = stripBidiMarks(parts.find((p) => p.type === "minusSign")?.value ?? "-") || "-";
38
+ const plain = numberFormat(settings, { useGrouping: false, maximumFractionDigits: 0 });
39
+ const digits = Array.from({ length: 10 }, (_, d) => stripBidiMarks(plain.format(d)));
40
+ const ascii = decimal === "." && minus === "-" && digits.every((d, i) => d === String(i));
41
+ sym = { ascii, decimal, minus, digits };
42
+ symbolCache.set(key, sym);
43
+ return sym;
44
+ }
45
+ function localizeAscii(text, settings) {
46
+ const sym = numberSymbols(settings);
47
+ if (sym.ascii) return text;
48
+ let out = "";
49
+ for (const ch of text) {
50
+ const code = ch.charCodeAt(0);
51
+ if (code >= 48 && code <= 57) out += sym.digits[code - 48];
52
+ else if (ch === ".") out += sym.decimal;
53
+ else if (ch === "-") out += sym.minus;
54
+ else out += ch;
55
+ }
56
+ return out;
57
+ }
58
+ function localizeDigits(text, settings) {
59
+ const sym = numberSymbols(settings);
60
+ if (sym.digits.every((d, i) => d === String(i))) return text;
61
+ return text.replace(/[0-9]/g, (d) => sym.digits[Number(d)]);
62
+ }
63
+ var clampDecimals = (d) => Number.isFinite(d) ? Math.max(0, Math.min(20, Math.trunc(d))) : 2;
64
+ function formatFixed(value, decimals, settings) {
65
+ return localizeAscii(value.toFixed(clampDecimals(decimals)), settings);
66
+ }
67
+ function formatGrouped(value, decimals, settings) {
68
+ const d = clampDecimals(decimals);
69
+ return stripBidiMarks(numberFormat(settings, { minimumFractionDigits: d, maximumFractionDigits: d }).format(value));
70
+ }
71
+ function formatMessageNumber(value, settings, style) {
72
+ if (style === "integer") return stripBidiMarks(numberFormat(settings, { maximumFractionDigits: 0 }).format(value));
73
+ if (style === "percent") return stripBidiMarks(numberFormat(settings, { style: "percent" }).format(value));
74
+ return stripBidiMarks(numberFormat(settings, {}).format(value));
75
+ }
76
+ function formatPercent(value, options, settings) {
77
+ const d = clampDecimals(options?.decimals ?? 2);
78
+ const signed2 = options?.signed ?? true;
79
+ if (settings.english) {
80
+ const text = signed2 ? `${value >= 0 ? "+" : "-"}${Math.abs(value).toFixed(d)}%` : `${value.toFixed(d)}%`;
81
+ return localizeAscii(text, settings);
82
+ }
83
+ const nf = numberFormat(settings, { style: "percent", minimumFractionDigits: d, maximumFractionDigits: d, signDisplay: signed2 ? "always" : "auto" });
84
+ return stripBidiMarks(nf.format(value / 100));
85
+ }
86
+ function formatPrice(value, options, settings) {
87
+ const mode = options.mode ?? "price";
88
+ if (mode === "percent") return formatPercent(value, { decimals: options.decimals, signed: true }, settings);
89
+ if (mode === "indexed" || !options.grouping) return formatFixed(value, options.decimals, settings);
90
+ return formatGrouped(value, options.decimals, settings);
91
+ }
92
+ var COMPACT_STEPS = [
93
+ [1e9, "B"],
94
+ [1e6, "M"],
95
+ [1e3, "K"]
96
+ ];
97
+ function formatCompact(value, options, settings) {
98
+ const d = clampDecimals(options?.decimals ?? 2);
99
+ const trim = options?.trimZeros ?? true;
100
+ if (settings.english) {
101
+ const a = Math.abs(value);
102
+ let div = 1;
103
+ let suffix = "";
104
+ for (const [step, s] of COMPACT_STEPS) {
105
+ if (a >= step) {
106
+ div = step;
107
+ suffix = s;
108
+ break;
109
+ }
110
+ }
111
+ const scaled = value / div;
112
+ const text = trim ? Number(scaled.toFixed(d)).toString() : scaled.toFixed(d);
113
+ return localizeAscii(text, settings) + suffix;
114
+ }
115
+ const nf = numberFormat(settings, { notation: "compact", compactDisplay: "short", maximumFractionDigits: d, minimumFractionDigits: trim ? 0 : d });
116
+ return stripBidiMarks(nf.format(value));
117
+ }
118
+
119
+ // src/core/format/dates.ts
120
+ var EN_MONTHS_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
121
+ var EN_WEEKDAYS_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
122
+ var pad2 = (n) => n < 10 ? `0${n}` : String(n);
123
+ var DAY_MS = 864e5;
124
+ var zoneParsers = /* @__PURE__ */ new Map();
125
+ function zoneOffsetMs(ms, timeZone) {
126
+ if (!timeZone || timeZone === "UTC") return 0;
127
+ let dtf = zoneParsers.get(timeZone);
128
+ if (dtf === void 0) {
129
+ try {
130
+ dtf = new Intl.DateTimeFormat("en-US", {
131
+ timeZone,
132
+ hourCycle: "h23",
133
+ year: "numeric",
134
+ month: "2-digit",
135
+ day: "2-digit",
136
+ hour: "2-digit",
137
+ minute: "2-digit",
138
+ second: "2-digit"
139
+ });
140
+ } catch {
141
+ dtf = null;
142
+ }
143
+ zoneParsers.set(timeZone, dtf);
144
+ }
145
+ if (!dtf) return 0;
146
+ try {
147
+ const parts = dtf.formatToParts(new Date(ms));
148
+ const get = (t) => Number(parts.find((p) => p.type === t)?.value);
149
+ const asUTC = Date.UTC(get("year"), get("month") - 1, get("day"), get("hour") % 24, get("minute"), get("second"));
150
+ return asUTC - ms;
151
+ } catch {
152
+ return 0;
153
+ }
154
+ }
155
+ var dateFormats = /* @__PURE__ */ new Map();
156
+ function dateFormat(settings, options) {
157
+ const key = `${settings.locale}|${settings.numberingSystem}|${JSON.stringify(options)}`;
158
+ let dtf = dateFormats.get(key);
159
+ if (!dtf) {
160
+ const full = { ...options, timeZone: "UTC", calendar: "gregory", numberingSystem: settings.numberingSystem };
161
+ try {
162
+ dtf = new Intl.DateTimeFormat(settings.locale, full);
163
+ } catch {
164
+ dtf = new Intl.DateTimeFormat("en", { ...options, timeZone: "UTC", calendar: "gregory" });
165
+ }
166
+ dateFormats.set(key, dtf);
167
+ }
168
+ return dtf;
169
+ }
170
+ function clockOptions(settings) {
171
+ if (settings.hourCycle === "h23") return { hour: "2-digit", minute: "2-digit", hourCycle: "h23" };
172
+ if (settings.hourCycle === "h12") return { hour: "numeric", minute: "2-digit", hourCycle: "h12" };
173
+ return { hour: "numeric", minute: "2-digit" };
174
+ }
175
+ function englishClock(wall, settings) {
176
+ if (settings.hourCycle === "h23") return localizeAscii(`${pad2(wall.getUTCHours())}:${pad2(wall.getUTCMinutes())}`, settings);
177
+ return stripBidiMarks(dateFormat(settings, clockOptions(settings)).format(wall));
178
+ }
179
+ var TICK_OPTIONS = {
180
+ year: { year: "numeric" },
181
+ month: { month: "short" },
182
+ day: { month: "short", day: "numeric" }
183
+ };
184
+ var isClockUnit = (unit) => unit === "hour" || unit === "minute" || unit === "second";
185
+ function formatTimeTick(ms, options, settings) {
186
+ const wall = new Date(ms + (options.offsetMs ?? 0));
187
+ const unit = options.unit;
188
+ if (settings.english) {
189
+ if (isClockUnit(unit)) return englishClock(wall, settings);
190
+ const month = EN_MONTHS_SHORT[wall.getUTCMonth()];
191
+ if (unit === "year") return localizeAscii(String(wall.getUTCFullYear()), settings);
192
+ if (unit === "month") return month;
193
+ return localizeAscii(`${month} ${wall.getUTCDate()}`, settings);
194
+ }
195
+ const opts = isClockUnit(unit) ? clockOptions(settings) : TICK_OPTIONS[unit];
196
+ return stripBidiMarks(dateFormat(settings, opts).format(wall));
197
+ }
198
+ function formatTimeStamp(ms, options, settings) {
199
+ const wall = new Date(ms + zoneOffsetMs(ms, options?.timeZone ?? "UTC"));
200
+ const withTime = options?.withTime ?? true;
201
+ if (settings.english) {
202
+ const date = localizeAscii(
203
+ `${EN_WEEKDAYS_SHORT[wall.getUTCDay()]} ${wall.getUTCDate()} ${EN_MONTHS_SHORT[wall.getUTCMonth()]} '${pad2(wall.getUTCFullYear() % 100)}`,
204
+ settings
205
+ );
206
+ return withTime ? `${date} ${englishClock(wall, settings)}` : date;
207
+ }
208
+ const opts = { weekday: "short", day: "numeric", month: "short", year: "2-digit", ...withTime ? clockOptions(settings) : {} };
209
+ return stripBidiMarks(dateFormat(settings, opts).format(wall));
210
+ }
211
+ function countdownText(ms) {
212
+ const total = Math.max(0, Math.ceil(ms / 1e3));
213
+ const s = total % 60;
214
+ const m = Math.floor(total / 60) % 60;
215
+ const h = Math.floor(total / 3600);
216
+ const pad = (v) => String(v).padStart(2, "0");
217
+ return h > 0 ? `${h}:${pad(m)}:${pad(s)}` : `${pad(m)}:${pad(s)}`;
218
+ }
219
+ function spanParts(ms) {
220
+ const m = Math.abs(ms);
221
+ const HR = 36e5;
222
+ const MIN2 = 6e4;
223
+ if (m >= DAY_MS) {
224
+ const d = Math.floor(m / DAY_MS);
225
+ const h = Math.round(m % DAY_MS / HR);
226
+ return h ? [[d, "day"], [h, "hour"]] : [[d, "day"]];
227
+ }
228
+ if (m >= HR) {
229
+ const h = Math.floor(m / HR);
230
+ const mn = Math.round(m % HR / MIN2);
231
+ return mn ? [[h, "hour"], [mn, "minute"]] : [[h, "hour"]];
232
+ }
233
+ if (m >= MIN2) return [[Math.round(m / MIN2), "minute"]];
234
+ return [[Math.round(m / 1e3), "second"]];
235
+ }
236
+ var EN_UNIT = { day: "d", hour: "h", minute: "m", second: "s" };
237
+ function formatDuration(ms, options, settings) {
238
+ if ((options?.style ?? "countdown") === "countdown") return localizeDigits(countdownText(ms), settings);
239
+ const parts = spanParts(ms);
240
+ if (settings.english) return localizeDigits(parts.map(([n, u]) => `${n}${EN_UNIT[u]}`).join(" "), settings);
241
+ return parts.map(([n, unit]) => stripBidiMarks(numberFormat(settings, { style: "unit", unit, unitDisplay: "narrow" }).format(n))).join(" ");
242
+ }
243
+ var clockFormats = /* @__PURE__ */ new Map();
244
+ function formatClock(ms, options, settings) {
245
+ const timeZone = options?.timeZone ?? "UTC";
246
+ const seconds = options?.seconds ?? true;
247
+ const english2 = settings.english && settings.hourCycle === "h23";
248
+ const key = `${english2 ? "en-GB" : settings.locale}|${settings.numberingSystem}|${settings.hourCycle}|${timeZone}|${seconds}`;
249
+ let dtf = clockFormats.get(key);
250
+ if (dtf === void 0) {
251
+ const base = { hour: "2-digit", minute: "2-digit", ...seconds ? { second: "2-digit" } : {}, timeZone };
252
+ try {
253
+ dtf = english2 ? new Intl.DateTimeFormat("en-GB", { ...base, hour12: false }) : new Intl.DateTimeFormat(settings.locale, {
254
+ ...base,
255
+ calendar: "gregory",
256
+ numberingSystem: settings.numberingSystem,
257
+ ...settings.hourCycle === "locale" ? {} : { hourCycle: settings.hourCycle }
258
+ });
259
+ } catch {
260
+ dtf = null;
261
+ }
262
+ clockFormats.set(key, dtf);
263
+ }
264
+ if (!dtf) return "";
265
+ try {
266
+ return stripBidiMarks(dtf.format(new Date(ms)));
267
+ } catch {
268
+ return "";
269
+ }
270
+ }
271
+
272
+ // src/core/format/formatters.ts
273
+ function builtinFormatters(settings) {
274
+ return {
275
+ price: (value, options) => formatPrice(value, options, settings),
276
+ percent: (value, options) => formatPercent(value, options, settings),
277
+ compact: (value, options) => formatCompact(value, options, settings),
278
+ timeTick: (ms, options) => formatTimeTick(ms, options, settings),
279
+ timeStamp: (ms, options) => formatTimeStamp(ms, options, settings),
280
+ duration: (ms, options) => formatDuration(ms, options, settings),
281
+ clock: (ms, options) => formatClock(ms, options, settings)
282
+ };
283
+ }
284
+ var ENGLISH_SETTINGS = Object.freeze({ locale: "en", numberingSystem: "latn", hourCycle: "h23", english: true });
285
+ var warned = false;
286
+ function viaHost(host, value, ctx, fallback) {
287
+ try {
288
+ const out = host(value, ctx);
289
+ if (typeof out === "string") return out;
290
+ } catch (err) {
291
+ if (!warned) {
292
+ warned = true;
293
+ console.warn("[vela] a host formatter threw; the built-in formatting is used instead.", err);
294
+ }
295
+ }
296
+ return fallback();
297
+ }
298
+ function resolveFormatters(settings, overrides) {
299
+ const base = builtinFormatters(settings);
300
+ if (!overrides) return base;
301
+ const ctx = (surface, defaultSurface, timeZone, fallback) => ({
302
+ locale: settings.locale,
303
+ timeZone: timeZone ?? "UTC",
304
+ surface: surface ?? defaultSurface,
305
+ fallback
306
+ });
307
+ const o = overrides;
308
+ return {
309
+ price(value, options) {
310
+ const fallback = () => base.price(value, options);
311
+ if (typeof o.price !== "function") return fallback();
312
+ return viaHost(o.price, value, { ...ctx(options.surface, "priceAxis", void 0, fallback), decimals: options.decimals, mintick: options.mintick, mode: options.mode ?? "price", paneId: options.paneId, grouping: options.grouping ?? false }, fallback);
313
+ },
314
+ percent(value, options) {
315
+ const fallback = () => base.percent(value, options);
316
+ if (typeof o.percent !== "function") return fallback();
317
+ return viaHost(o.percent, value, { ...ctx(options?.surface, "statusLine", void 0, fallback), decimals: options?.decimals ?? 2, signed: options?.signed ?? true }, fallback);
318
+ },
319
+ compact(value, options) {
320
+ const fallback = () => base.compact(value, options);
321
+ if (typeof o.compact !== "function") return fallback();
322
+ return viaHost(o.compact, value, { ...ctx(options?.surface, "priceAxis", void 0, fallback), decimals: options?.decimals ?? 2, trimZeros: options?.trimZeros ?? true }, fallback);
323
+ },
324
+ timeTick(ms, options) {
325
+ const fallback = () => base.timeTick(ms, options);
326
+ if (typeof o.timeTick !== "function") return fallback();
327
+ return viaHost(o.timeTick, ms, { ...ctx(options.surface, "timeAxis", options.timeZone, fallback), unit: options.unit, major: options.major, offsetMs: options.offsetMs ?? 0 }, fallback);
328
+ },
329
+ timeStamp(ms, options) {
330
+ const fallback = () => base.timeStamp(ms, options);
331
+ if (typeof o.timeStamp !== "function") return fallback();
332
+ return viaHost(o.timeStamp, ms, { ...ctx(options?.surface, "crosshair", options?.timeZone, fallback), withTime: options?.withTime ?? true }, fallback);
333
+ },
334
+ duration(ms, options) {
335
+ const fallback = () => base.duration(ms, options);
336
+ if (typeof o.duration !== "function") return fallback();
337
+ return viaHost(o.duration, ms, { ...ctx(options?.surface, "lastPrice", void 0, fallback), style: options?.style ?? "countdown" }, fallback);
338
+ },
339
+ clock(ms, options) {
340
+ const fallback = () => base.clock(ms, options);
341
+ if (typeof o.clock !== "function") return fallback();
342
+ return viaHost(o.clock, ms, { ...ctx(options?.surface, "clock", options?.timeZone, fallback), seconds: options?.seconds ?? true }, fallback);
343
+ }
344
+ };
345
+ }
346
+
347
+ // src/core/i18n/icu.ts
348
+ var Parser = class {
349
+ constructor(src) {
350
+ this.src = src;
351
+ this.i = 0;
352
+ }
353
+ parse() {
354
+ const nodes = this.message(false, 0);
355
+ if (this.i < this.src.length) throw this.error("unmatched }");
356
+ return nodes;
357
+ }
358
+ error(what) {
359
+ return new SyntaxError(`[vela] message syntax: ${what} at ${this.i} in "${this.src}"`);
360
+ }
361
+ /** Text and arguments up to an unmatched `}` (left unread) or the end. */
362
+ message(inPlural, depth) {
363
+ if (depth > 8) throw this.error("nesting too deep");
364
+ const src = this.src;
365
+ const out = [];
366
+ let text = "";
367
+ const flush = () => {
368
+ if (text) out.push(text);
369
+ text = "";
370
+ };
371
+ while (this.i < src.length) {
372
+ const ch = src[this.i];
373
+ if (ch === "'") {
374
+ const next = src[this.i + 1];
375
+ if (next === "'") {
376
+ text += "'";
377
+ this.i += 2;
378
+ } else if (next === "{" || next === "}" || inPlural && next === "#") {
379
+ this.i += 1;
380
+ while (this.i < src.length) {
381
+ const c = src[this.i];
382
+ if (c === "'") {
383
+ if (src[this.i + 1] === "'") {
384
+ text += "'";
385
+ this.i += 2;
386
+ continue;
387
+ }
388
+ this.i += 1;
389
+ break;
390
+ }
391
+ text += c;
392
+ this.i += 1;
393
+ }
394
+ } else {
395
+ text += "'";
396
+ this.i += 1;
397
+ }
398
+ } else if (ch === "{") {
399
+ flush();
400
+ this.i += 1;
401
+ out.push(this.argument(depth));
402
+ } else if (ch === "}") {
403
+ break;
404
+ } else if (ch === "#" && inPlural) {
405
+ flush();
406
+ out.push({ kind: "pound" });
407
+ this.i += 1;
408
+ } else {
409
+ text += ch;
410
+ this.i += 1;
411
+ }
412
+ }
413
+ flush();
414
+ return out;
415
+ }
416
+ skipSpace() {
417
+ while (this.i < this.src.length && /\s/.test(this.src[this.i])) this.i += 1;
418
+ }
419
+ word() {
420
+ this.skipSpace();
421
+ const start = this.i;
422
+ while (this.i < this.src.length && !/[\s,{}]/.test(this.src[this.i])) this.i += 1;
423
+ return this.src.slice(start, this.i);
424
+ }
425
+ expect(ch) {
426
+ this.skipSpace();
427
+ if (this.src[this.i] !== ch) throw this.error(`expected "${ch}"`);
428
+ this.i += 1;
429
+ }
430
+ /** After a `{`: the argument through its closing `}`. */
431
+ argument(depth) {
432
+ const name = this.word();
433
+ if (!name) throw this.error("empty argument name");
434
+ this.skipSpace();
435
+ if (this.src[this.i] === "}") {
436
+ this.i += 1;
437
+ return { kind: "arg", name };
438
+ }
439
+ this.expect(",");
440
+ const type = this.word();
441
+ this.skipSpace();
442
+ if (type === "number") {
443
+ let style;
444
+ if (this.src[this.i] === ",") {
445
+ this.i += 1;
446
+ style = this.word() || void 0;
447
+ }
448
+ this.expect("}");
449
+ return { kind: "arg", name, format: "number", style };
450
+ }
451
+ if (type === "plural" || type === "selectordinal" || type === "select") {
452
+ this.expect(",");
453
+ let offset = 0;
454
+ this.skipSpace();
455
+ if (type !== "select" && this.src.startsWith("offset:", this.i)) {
456
+ this.i += "offset:".length;
457
+ offset = Number(this.word());
458
+ if (!Number.isFinite(offset)) throw this.error("bad offset");
459
+ }
460
+ const options = {};
461
+ for (; ; ) {
462
+ this.skipSpace();
463
+ if (this.src[this.i] === "}") {
464
+ this.i += 1;
465
+ break;
466
+ }
467
+ const key = this.word();
468
+ if (!key) throw this.error("expected a selector");
469
+ this.expect("{");
470
+ options[key] = this.message(type !== "select", depth + 1);
471
+ this.expect("}");
472
+ }
473
+ if (!options.other) throw this.error(`"${name}" has no "other" option`);
474
+ return type === "select" ? { kind: "select", name, options } : { kind: "plural", name, ordinal: type === "selectordinal", offset, options };
475
+ }
476
+ throw this.error(`unknown argument type "${type}"`);
477
+ }
478
+ };
479
+ var parsed = /* @__PURE__ */ new Map();
480
+ var PARSE_CACHE_CAP = 2e3;
481
+ function parseMessage(source) {
482
+ let nodes = parsed.get(source);
483
+ if (!nodes) {
484
+ nodes = new Parser(source).parse();
485
+ if (parsed.size >= PARSE_CACHE_CAP) parsed.clear();
486
+ parsed.set(source, nodes);
487
+ }
488
+ return nodes;
489
+ }
490
+ var pluralRules = /* @__PURE__ */ new Map();
491
+ function rulesFor(locale, ordinal) {
492
+ const key = `${locale}|${ordinal ? "o" : "c"}`;
493
+ let pr = pluralRules.get(key);
494
+ if (!pr) {
495
+ try {
496
+ pr = new Intl.PluralRules(locale, { type: ordinal ? "ordinal" : "cardinal" });
497
+ } catch {
498
+ pr = new Intl.PluralRules("en", { type: ordinal ? "ordinal" : "cardinal" });
499
+ }
500
+ pluralRules.set(key, pr);
501
+ }
502
+ return pr;
503
+ }
504
+ function render(nodes, values, rt, pound) {
505
+ let out = "";
506
+ for (const node of nodes) {
507
+ if (typeof node === "string") {
508
+ out += node;
509
+ continue;
510
+ }
511
+ if (node.kind === "pound") {
512
+ out += pound == null ? "#" : rt.formatNumber(pound);
513
+ continue;
514
+ }
515
+ const raw = values?.[node.name];
516
+ if (node.kind === "arg") {
517
+ if (raw === void 0) out += `{${node.name}}`;
518
+ else if (typeof raw === "number") out += rt.formatNumber(raw, node.format === "number" ? node.style : void 0);
519
+ else if (node.format === "number" && raw.trim() !== "" && Number.isFinite(Number(raw))) out += rt.formatNumber(Number(raw), node.style);
520
+ else out += raw;
521
+ continue;
522
+ }
523
+ if (node.kind === "select") {
524
+ const branch2 = node.options[String(raw)] ?? node.options.other;
525
+ out += render(branch2, values, rt, pound);
526
+ continue;
527
+ }
528
+ const n = typeof raw === "number" ? raw : Number(raw);
529
+ let branch;
530
+ if (Number.isFinite(n)) {
531
+ branch = node.options[`=${n}`] ?? node.options[rulesFor(rt.locale, node.ordinal).select(n - node.offset)];
532
+ }
533
+ out += render(branch ?? node.options.other, values, rt, Number.isFinite(n) ? n - node.offset : null);
534
+ }
535
+ return out;
536
+ }
537
+ function formatMessage(source, values, rt) {
538
+ if (source.indexOf("{") < 0 && source.indexOf("'") < 0) return source;
539
+ return render(parseMessage(source), values, rt, null);
540
+ }
541
+
542
+ // src/core/format/calendar.ts
543
+ var SUNDAY_REGIONS = /* @__PURE__ */ new Set([
544
+ "AG",
545
+ "AS",
546
+ "BD",
547
+ "BR",
548
+ "BS",
549
+ "BT",
550
+ "BW",
551
+ "BZ",
552
+ "CA",
553
+ "CN",
554
+ "CO",
555
+ "DM",
556
+ "DO",
557
+ "ET",
558
+ "GT",
559
+ "GU",
560
+ "HK",
561
+ "HN",
562
+ "ID",
563
+ "IL",
564
+ "IN",
565
+ "JM",
566
+ "JP",
567
+ "KE",
568
+ "KH",
569
+ "KR",
570
+ "LA",
571
+ "MH",
572
+ "MM",
573
+ "MO",
574
+ "MT",
575
+ "MX",
576
+ "MZ",
577
+ "NI",
578
+ "NP",
579
+ "PA",
580
+ "PE",
581
+ "PH",
582
+ "PK",
583
+ "PR",
584
+ "PT",
585
+ "PY",
586
+ "SA",
587
+ "SG",
588
+ "SV",
589
+ "TH",
590
+ "TT",
591
+ "TW",
592
+ "UM",
593
+ "US",
594
+ "VE",
595
+ "VI",
596
+ "WS",
597
+ "YE",
598
+ "ZA",
599
+ "ZW"
600
+ ]);
601
+ var SATURDAY_REGIONS = /* @__PURE__ */ new Set(["AE", "AF", "BH", "DJ", "DZ", "EG", "IQ", "IR", "JO", "KW", "LY", "OM", "QA", "SD", "SY"]);
602
+ function localeWeekStart(locale) {
603
+ let loc;
604
+ try {
605
+ loc = new Intl.Locale(locale);
606
+ } catch {
607
+ return 1;
608
+ }
609
+ try {
610
+ const wl = loc;
611
+ const info = typeof wl.getWeekInfo === "function" ? wl.getWeekInfo() : wl.weekInfo;
612
+ const firstDay = info?.firstDay;
613
+ if (typeof firstDay === "number") return firstDay === 7 ? 0 : firstDay === 6 ? 6 : 1;
614
+ } catch {
615
+ }
616
+ let region = loc.region;
617
+ if (!region) {
618
+ try {
619
+ region = loc.maximize().region;
620
+ } catch {
621
+ region = void 0;
622
+ }
623
+ }
624
+ if (region && SUNDAY_REGIONS.has(region)) return 0;
625
+ if (region && SATURDAY_REGIONS.has(region)) return 6;
626
+ return 1;
627
+ }
628
+
629
+ // src/core/i18n/locale.ts
630
+ function canonicalLocale(tag) {
631
+ const raw = typeof tag === "string" ? tag.trim() : "";
632
+ if (!raw) return "en";
633
+ try {
634
+ return Intl.getCanonicalLocales(raw)[0] ?? raw;
635
+ } catch {
636
+ return raw;
637
+ }
638
+ }
639
+ function parseLocale(tag) {
640
+ try {
641
+ return new Intl.Locale(tag);
642
+ } catch {
643
+ return null;
644
+ }
645
+ }
646
+ function languageOf(tag) {
647
+ return (parseLocale(tag)?.language ?? tag.split(/[-_]/)[0] ?? tag).toLowerCase();
648
+ }
649
+ function fallbackChain(tag) {
650
+ const out = [];
651
+ const add = (t) => {
652
+ if (t && !out.includes(t)) out.push(t);
653
+ };
654
+ add(tag);
655
+ const loc = parseLocale(tag);
656
+ if (loc) {
657
+ const base = loc.baseName;
658
+ add(base);
659
+ const parts = base.split("-");
660
+ let impliedScript;
661
+ if (!loc.script) {
662
+ try {
663
+ impliedScript = loc.maximize().script;
664
+ } catch {
665
+ impliedScript = void 0;
666
+ }
667
+ }
668
+ for (let i = parts.length - 1; i >= 1; i -= 1) {
669
+ if (i === 1 && impliedScript && loc.region) add(`${loc.language}-${impliedScript}`);
670
+ add(parts.slice(0, i).join("-"));
671
+ }
672
+ if (impliedScript && !loc.region) add(`${loc.language}-${impliedScript}`);
673
+ try {
674
+ const usual = new Intl.Locale(loc.language).maximize();
675
+ if (usual.region && usual.script === (loc.script ?? impliedScript)) add(`${loc.language}-${usual.region}`);
676
+ } catch {
677
+ }
678
+ }
679
+ add("en");
680
+ return out;
681
+ }
682
+ var RTL_SCRIPTS = /* @__PURE__ */ new Set(["Arab", "Hebr", "Thaa", "Syrc", "Nkoo", "Adlm", "Rohg", "Mand", "Samr", "Yezi"]);
683
+ var RTL_LANGUAGES = /* @__PURE__ */ new Set(["ar", "he", "iw", "fa", "ur", "ps", "sd", "ug", "yi", "dv", "ckb", "ks"]);
684
+ function localeDirection(tag) {
685
+ const loc = parseLocale(tag);
686
+ if (loc) {
687
+ try {
688
+ const tl = loc;
689
+ const info = typeof tl.getTextInfo === "function" ? tl.getTextInfo() : tl.textInfo;
690
+ if (info?.direction === "rtl" || info?.direction === "ltr") return info.direction;
691
+ } catch {
692
+ }
693
+ try {
694
+ const script = loc.script ?? loc.maximize().script;
695
+ if (script) return RTL_SCRIPTS.has(script) ? "rtl" : "ltr";
696
+ } catch {
697
+ }
698
+ }
699
+ return RTL_LANGUAGES.has(languageOf(tag)) ? "rtl" : "ltr";
700
+ }
701
+ var numberingCache = /* @__PURE__ */ new Map();
702
+ function resolveNumberingSystem(tag, requested) {
703
+ const key = `${tag}|${requested ?? ""}`;
704
+ const cached = numberingCache.get(key);
705
+ if (cached) return cached;
706
+ let nu = "latn";
707
+ try {
708
+ if (requested === "locale") nu = new Intl.NumberFormat(tag).resolvedOptions().numberingSystem;
709
+ else if (requested) nu = new Intl.NumberFormat(tag, { numberingSystem: requested }).resolvedOptions().numberingSystem;
710
+ else {
711
+ const ext = parseLocale(tag)?.numberingSystem;
712
+ if (ext) nu = new Intl.NumberFormat(tag).resolvedOptions().numberingSystem;
713
+ }
714
+ } catch {
715
+ nu = "latn";
716
+ }
717
+ numberingCache.set(key, nu);
718
+ return nu;
719
+ }
720
+
721
+ // src/core/i18n/registry.ts
722
+ var entries = [];
723
+ var version = 0;
724
+ var merged = /* @__PURE__ */ new Map();
725
+ function registerLocale(pack) {
726
+ if (!pack || typeof pack.locale !== "string" || !pack.messages || typeof pack.messages !== "object") {
727
+ throw new TypeError("[vela] registerLocale expects { locale: string, messages: Record<string, string> }");
728
+ }
729
+ const entry = { tag: canonicalLocale(pack.locale), messages: pack.messages };
730
+ entries.push(entry);
731
+ version += 1;
732
+ let disposed = false;
733
+ return () => {
734
+ if (disposed) return;
735
+ disposed = true;
736
+ const i = entries.indexOf(entry);
737
+ if (i >= 0) {
738
+ entries.splice(i, 1);
739
+ version += 1;
740
+ }
741
+ };
742
+ }
743
+ function registeredLocales() {
744
+ return [...new Set(entries.map((e) => e.tag))];
745
+ }
746
+ function messagesFor(chain) {
747
+ const key = chain.join("|");
748
+ const hit = merged.get(key);
749
+ if (hit && hit.version === version) return hit.map;
750
+ const map = /* @__PURE__ */ new Map();
751
+ for (let c = chain.length - 1; c >= 0; c -= 1) {
752
+ const tag = chain[c];
753
+ for (const e of entries) {
754
+ if (e.tag !== tag) continue;
755
+ for (const [id, text] of Object.entries(e.messages)) {
756
+ if (typeof text === "string") map.set(id, text);
757
+ }
758
+ }
759
+ }
760
+ merged.set(key, { version, map });
761
+ return map;
762
+ }
763
+
764
+ // src/core/i18n/translator.ts
765
+ function isMessageDescriptor(m) {
766
+ return typeof m === "object" && m !== null && typeof m.id === "string" && typeof m.defaultMessage === "string";
767
+ }
768
+ var warnedSyntax = false;
769
+ function resolveArgs(args, resolve) {
770
+ if (!args) return void 0;
771
+ let out = null;
772
+ for (const key of Object.keys(args)) {
773
+ const v = args[key];
774
+ if (typeof v === "object" && v !== null) {
775
+ out ?? (out = { ...args });
776
+ out[key] = resolve(v);
777
+ }
778
+ }
779
+ return out ?? args;
780
+ }
781
+ var LocaleState = class {
782
+ constructor(options = {}) {
783
+ this.runtime = {
784
+ locale: "en",
785
+ formatNumber: (value, style) => formatMessageNumber(value, this.settings, style)
786
+ };
787
+ this.opts = { ...options };
788
+ this.resolve();
789
+ }
790
+ /** The options as last set (unresolved). */
791
+ get options() {
792
+ return this.opts;
793
+ }
794
+ /** Whether the host chose a locale; Vela stamps `lang` only then. */
795
+ get localeExplicit() {
796
+ return this.opts.locale !== void 0;
797
+ }
798
+ /** Whether the host chose a direction; Vela stamps `dir` only then. */
799
+ get directionExplicit() {
800
+ return this.opts.direction !== void 0;
801
+ }
802
+ /** Apply a change: fields present in `next` replace (an explicit `undefined` restores
803
+ * the default), absent fields keep their current value. */
804
+ update(next) {
805
+ const patch = typeof next === "string" ? { locale: next } : next;
806
+ this.opts = { ...this.opts, ...patch };
807
+ for (const key of Object.keys(this.opts)) {
808
+ if (this.opts[key] === void 0) delete this.opts[key];
809
+ }
810
+ this.resolve();
811
+ }
812
+ resolve() {
813
+ const o = this.opts;
814
+ const locale = canonicalLocale(o.locale);
815
+ const numberingSystem = resolveNumberingSystem(locale, o.numberingSystem);
816
+ const hourCycle = o.hourCycle === "h12" || o.hourCycle === "locale" ? o.hourCycle : "h23";
817
+ this.settings = { locale, numberingSystem, hourCycle, english: languageOf(locale) === "en" };
818
+ this.chain = fallbackChain(locale);
819
+ this.resolvedDirection = o.direction === "rtl" || o.direction === "ltr" ? o.direction : o.direction === "auto" ? localeDirection(locale) : "ltr";
820
+ this.resolvedWeekStart = o.weekStart === 0 || o.weekStart === 1 || o.weekStart === 6 ? o.weekStart : localeWeekStart(locale);
821
+ this.runtime.locale = locale;
822
+ this.formatters = resolveFormatters(this.settings, o.formatters);
823
+ }
824
+ get locale() {
825
+ return this.settings.locale;
826
+ }
827
+ get direction() {
828
+ return this.resolvedDirection;
829
+ }
830
+ get numberingSystem() {
831
+ return this.settings.numberingSystem;
832
+ }
833
+ get hourCycle() {
834
+ return this.settings.hourCycle;
835
+ }
836
+ get weekStart() {
837
+ return this.resolvedWeekStart;
838
+ }
839
+ get format() {
840
+ return this.formatters;
841
+ }
842
+ /** The resolved settings the built-in formatters and calendar helpers read. */
843
+ get formatSettings() {
844
+ return this.settings;
845
+ }
846
+ t(message, args) {
847
+ if (typeof message === "string") return message;
848
+ if (!isMessageDescriptor(message)) return message == null ? "" : String(message);
849
+ const { id, defaultMessage } = message;
850
+ const bound = message.values;
851
+ const values = resolveArgs(bound ? args ? { ...bound, ...args } : bound : args, (m) => this.t(m));
852
+ const override = this.opts.messages?.[id];
853
+ const source = typeof override === "string" ? override : messagesFor(this.chain).get(id) ?? defaultMessage;
854
+ try {
855
+ return formatMessage(source, values, this.runtime);
856
+ } catch (err) {
857
+ if (!warnedSyntax) {
858
+ warnedSyntax = true;
859
+ console.warn(`[vela] message "${id}" could not be formatted; the English text is used instead.`, err);
860
+ }
861
+ if (source === defaultMessage) return defaultMessage;
862
+ try {
863
+ return formatMessage(defaultMessage, values, this.runtime);
864
+ } catch {
865
+ return defaultMessage;
866
+ }
867
+ }
868
+ }
869
+ };
870
+ function createTranslator(options) {
871
+ return new LocaleState(options);
872
+ }
873
+ var english = null;
874
+ function englishTranslator() {
875
+ english ?? (english = new LocaleState());
876
+ return english;
877
+ }
878
+ function formatSettingsOf(i18n) {
879
+ if (i18n instanceof LocaleState) return i18n.formatSettings;
880
+ if (!i18n) return englishTranslator().formatSettings;
881
+ return { locale: i18n.locale, numberingSystem: i18n.numberingSystem, hourCycle: i18n.hourCycle, english: languageOf(i18n.locale) === "en" };
882
+ }
883
+
884
+ // src/core/i18n/text.ts
885
+ var ENGLISH_RUNTIME = {
886
+ locale: "en",
887
+ formatNumber: (value, style) => formatMessageNumber(value, ENGLISH_SETTINGS, style)
888
+ };
889
+ function sourceText(message, values) {
890
+ if (message == null) return "";
891
+ if (typeof message === "string") return message;
892
+ if (!isMessageDescriptor(message)) return String(message);
893
+ const bound = message.values;
894
+ const all = resolveArgs(bound ? bound : values, (m) => sourceText(m));
895
+ try {
896
+ return formatMessage(message.defaultMessage, all, ENGLISH_RUNTIME);
897
+ } catch {
898
+ return message.defaultMessage;
899
+ }
900
+ }
901
+ function textOf(i18n, message, values) {
902
+ return (i18n ?? englishTranslator()).t(message, values);
903
+ }
904
+ function localizeNumberText(text, i18n) {
905
+ return localizeAscii(text, formatSettingsOf(i18n));
906
+ }
907
+
3
908
  // src/chart-types/registry.ts
909
+ var RANGE_MIN = msg("chart.settings.rangeMin", "{label} — min");
910
+ var RANGE_MAX = msg("chart.settings.rangeMax", "{label} — max");
4
911
  function normalizeSettingsRow(r) {
5
912
  switch (r.kind) {
6
913
  case "row":
@@ -22,9 +929,9 @@ function normalizeSettingsRow(r) {
22
929
  return {
23
930
  label: r.label,
24
931
  controls: [
25
- { kind: "number", key: r.minKey, label: `${r.label} \u2014 min`, defval: r.defval, min: r.min, max: r.max, step: r.step, placeholder: r.placeholder },
26
- { kind: "hint", text: "\u2013" },
27
- { kind: "number", key: r.maxKey, label: `${r.label} \u2014 max`, defval: r.defval, min: r.min, max: r.max, step: r.step, placeholder: r.placeholder }
932
+ { kind: "number", key: r.minKey, label: withValues(RANGE_MIN, { label: r.label }), defval: r.defval, min: r.min, max: r.max, step: r.step, placeholder: r.placeholder },
933
+ { kind: "hint", text: "–" },
934
+ { kind: "number", key: r.maxKey, label: withValues(RANGE_MAX, { label: r.label }), defval: r.defval, min: r.min, max: r.max, step: r.step, placeholder: r.placeholder }
28
935
  ],
29
936
  when: r.when
30
937
  };
@@ -84,8 +991,15 @@ function registerNativeIndicator(descriptor) {
84
991
  function unregisterNativeIndicator(type) {
85
992
  REGISTRY.delete(type);
86
993
  }
87
- function getNativeIndicator(type) {
88
- return REGISTRY.get(type);
994
+ function resolved(d, i18n) {
995
+ if (typeof d.title === "string" && (d.shortTitle === void 0 || typeof d.shortTitle === "string")) return d;
996
+ const names = { title: textOf(i18n, d.title) };
997
+ if (d.shortTitle !== void 0) names.shortTitle = textOf(i18n, d.shortTitle);
998
+ return Object.assign(Object.create(d), names);
999
+ }
1000
+ function getNativeIndicator(type, i18n) {
1001
+ const d = REGISTRY.get(type);
1002
+ return d ? resolved(d, i18n) : void 0;
89
1003
  }
90
1004
  function nativeIndicatorTypes() {
91
1005
  return [...REGISTRY.keys()];
@@ -144,7 +1058,7 @@ function topbarActionOverride(id) {
144
1058
  }
145
1059
  function registerWidgetAction(desc) {
146
1060
  if (builtinTopbarSet.has(desc.id) && !overridableSet.has(desc.id)) {
147
- console.warn(`[vela] widget action "${desc.id}": this built-in topbar slot is a stateful control and cannot be overridden \u2014 ignored. Overridable slots: ${OVERRIDABLE_TOPBAR_IDS.join(", ")}.`);
1061
+ console.warn(`[vela] widget action "${desc.id}": this built-in topbar slot is a stateful control and cannot be overridden — ignored. Overridable slots: ${OVERRIDABLE_TOPBAR_IDS.join(", ")}.`);
148
1062
  return () => void 0;
149
1063
  }
150
1064
  registry3.set(desc.id, desc);
@@ -222,8 +1136,6 @@ function unregisterDefaultEngine(language) {
222
1136
  function resolveEngines(overrides) {
223
1137
  return { ...Object.fromEntries(defaultEngines), ...overrides };
224
1138
  }
225
-
226
- // src/widget/context-menu-model.ts
227
1139
  var CONTEXT_MENU_BUILTIN_ORDER = {
228
1140
  body: { "reset-view": -30, "remove-drawings": -20, "remove-indicators": -10, settings: 1e3 },
229
1141
  "price-axis": {
@@ -397,13 +1309,11 @@ registerIcon(
397
1309
  "send-back",
398
1310
  svg24('<rect x="8.5" y="8.5" width="7" height="7" rx="1.5" fill="currentColor" stroke="none" opacity="0.35"/><path d="M4.5 10.5V6a1.5 1.5 0 0 1 1.5-1.5h4.5"/><path d="M19.5 13.5V18a1.5 1.5 0 0 1-1.5 1.5h-4.5"/><rect x="8.5" y="8.5" width="7" height="7" rx="1.5"/>')
399
1311
  );
400
- registerIcon("r-squared", '<svg viewBox="0 0 24 24" width="1em" height="1em" fill="currentColor" stroke="none"><text x="2.5" y="17.5" font-size="14" font-family="serif">R\xB2</text></svg>');
1312
+ registerIcon("r-squared", '<svg viewBox="0 0 24 24" width="1em" height="1em" fill="currentColor" stroke="none"><text x="2.5" y="17.5" font-size="14" font-family="serif">R²</text></svg>');
401
1313
  registerIcon("bands", svg24('<path d="M3 6h18"/><path d="M3 18h18"/><path d="M3 12h18" stroke-dasharray="3 3"/>'));
402
1314
  registerIcon("dedekind", svg24('<path d="M2 20h20"/><path d="M4 20a8 8 0 0 1 16 0"/><path d="M8 20a4 4 0 0 1 8 0"/><path d="M12 4v16"/>'));
403
1315
  registerIcon("sonic", svg24('<circle cx="15" cy="12" r="4"/><circle cx="12" cy="12" r="2.5"/><path d="M8 5v14"/>'));
404
1316
  registerIcon("supersonic", svg24('<circle cx="16" cy="12" r="3.5"/><path d="M6 12 15 6M6 12 15 18"/>'));
405
-
406
- // src/widget/side-panel.ts
407
1317
  var DEFAULT_PANEL_WIDTH = 280;
408
1318
  var DEFAULT_PANEL_MIN_WIDTH = 200;
409
1319
  var DEFAULT_PANEL_MAX_WIDTH = 640;
@@ -458,15 +1368,15 @@ var MIN = 6e4;
458
1368
  var HOUR = 60 * MIN;
459
1369
  var DAY = 24 * HOUR;
460
1370
  var TIMEFRAME_BANDS = [
461
- { key: "s", label: "Sec", fromMs: 0 },
462
- { key: "1", label: "1m", fromMs: MIN },
463
- { key: "5", label: "5m", fromMs: 5 * MIN },
464
- { key: "15", label: "15m", fromMs: 15 * MIN },
465
- { key: "60", label: "1H", fromMs: HOUR },
466
- { key: "240", label: "4H", fromMs: 4 * HOUR },
467
- { key: "D", label: "D", fromMs: DAY },
468
- { key: "W", label: "W", fromMs: 7 * DAY },
469
- { key: "M", label: "M", fromMs: 28 * DAY }
1371
+ { key: "s", label: msg("drawing.showOn.seconds", "Sec"), fromMs: 0 },
1372
+ { key: "1", label: msg("drawing.showOn.minute1", "1m"), fromMs: MIN },
1373
+ { key: "5", label: msg("drawing.showOn.minute5", "5m"), fromMs: 5 * MIN },
1374
+ { key: "15", label: msg("drawing.showOn.minute15", "15m"), fromMs: 15 * MIN },
1375
+ { key: "60", label: msg("drawing.showOn.hour1", "1H"), fromMs: HOUR },
1376
+ { key: "240", label: msg("drawing.showOn.hour4", "4H"), fromMs: 4 * HOUR },
1377
+ { key: "D", label: msg("drawing.showOn.day", "D"), fromMs: DAY },
1378
+ { key: "W", label: msg("drawing.showOn.week", "W"), fromMs: 7 * DAY },
1379
+ { key: "M", label: msg("drawing.showOn.month", "M"), fromMs: 28 * DAY }
470
1380
  ];
471
1381
  var BAND_KEYS = new Set(TIMEFRAME_BANDS.map((b) => b.key));
472
1382
  function sanitizeShowOn(v) {
@@ -546,6 +1456,12 @@ var _Drawing = class _Drawing {
546
1456
  }
547
1457
  return { min: lo, max: hi };
548
1458
  }
1459
+ /** The text a fresh drawing of this type starts with ("Note", "Callout"), as a message,
1460
+ * or null for a type that seeds none. A new drawing stores its English source; the chart
1461
+ * that places one interactively writes it in its own language instead. */
1462
+ placeholderText() {
1463
+ return null;
1464
+ }
549
1465
  /**
550
1466
  * Editable per-level config for a rich "gear" settings panel (Fibonacci levels):
551
1467
  * each entry's `color` / `enabled` / `label` is mutated via a `levels.<i>.<field>`
@@ -612,28 +1528,33 @@ function setByPath(obj, path, value) {
612
1528
 
613
1529
  // src/core/drawings/schema.ts
614
1530
  var LINE_STYLE_OPTIONS = [
615
- { value: "solid", label: "Solid" },
616
- { value: "dashed", label: "Dashed" },
617
- { value: "dotted", label: "Dotted" }
1531
+ { value: "solid", label: msg("drawing.option.solid", "Solid") },
1532
+ { value: "dashed", label: msg("drawing.option.dashed", "Dashed") },
1533
+ { value: "dotted", label: msg("drawing.option.dotted", "Dotted") }
618
1534
  ];
619
1535
  var LINE_FIELDS = [
620
- { path: "style.lineColor", label: "Line color", kind: "color", group: "line" },
621
- { path: "style.lineWidth", label: "Line width", kind: "number", min: 1, max: 10, step: 1, group: "line" },
622
- { path: "style.lineStyle", label: "Line style", kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" }
1536
+ { path: "style.lineColor", label: msg("drawing.field.lineColor", "Line color"), kind: "color", group: "line" },
1537
+ { path: "style.lineWidth", label: msg("drawing.field.lineWidth", "Line width"), kind: "number", min: 1, max: 10, step: 1, group: "line" },
1538
+ { path: "style.lineStyle", label: msg("drawing.field.lineStyle", "Line style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" }
1539
+ ];
1540
+ var BORDER_FIELDS = [
1541
+ { path: "style.lineColor", label: msg("drawing.field.borderColor", "Border color"), kind: "color", group: "line" },
1542
+ { path: "style.lineWidth", label: msg("drawing.field.borderWidth", "Border width"), kind: "number", min: 1, max: 10, step: 1, group: "line" },
1543
+ { path: "style.lineStyle", label: msg("drawing.field.borderStyle", "Border style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" }
623
1544
  ];
624
- var FILL_FIELDS = [{ path: "style.fillColor", label: "Fill color", kind: "color", group: "fill" }];
1545
+ var FILL_FIELDS = [{ path: "style.fillColor", label: msg("drawing.field.fillColor", "Fill color"), kind: "color", group: "fill" }];
625
1546
  var TEXT_SIZE_OPTIONS = [
626
- { value: "small", label: "Small" },
627
- { value: "normal", label: "Normal" },
628
- { value: "large", label: "Large" },
629
- { value: "huge", label: "Huge" }
1547
+ { value: "small", label: msg("drawing.option.small", "Small") },
1548
+ { value: "normal", label: msg("drawing.option.normal", "Normal") },
1549
+ { value: "large", label: msg("drawing.option.large", "Large") },
1550
+ { value: "huge", label: msg("drawing.option.huge", "Huge") }
630
1551
  ];
631
1552
  var TEXT_FIELDS = [
632
- { path: "text.value", label: "Text", kind: "text", group: "text" },
633
- { path: "text.color", label: "Text color", kind: "color", group: "text" },
634
- { path: "text.size", label: "Text size", kind: "select", options: TEXT_SIZE_OPTIONS, group: "text" },
635
- { path: "text.bold", label: "Bold", kind: "boolean", group: "text" },
636
- { path: "text.italic", label: "Italic", kind: "boolean", group: "text" }
1553
+ { path: "text.value", label: msg("drawing.field.text", "Text"), kind: "text", group: "text" },
1554
+ { path: "text.color", label: msg("drawing.field.textColor", "Text color"), kind: "color", group: "text" },
1555
+ { path: "text.size", label: msg("drawing.field.textSize", "Text size"), kind: "select", options: TEXT_SIZE_OPTIONS, group: "text" },
1556
+ { path: "text.bold", label: msg("drawing.field.bold", "Bold"), kind: "boolean", group: "text" },
1557
+ { path: "text.italic", label: msg("drawing.field.italic", "Italic"), kind: "boolean", group: "text" }
637
1558
  ];
638
1559
 
639
1560
  // src/core/drawings/hittest.ts
@@ -751,9 +1672,9 @@ var TrendLine = class extends Drawing {
751
1672
  return {
752
1673
  fields: [
753
1674
  ...LINE_FIELDS,
754
- { path: "style.arrowRight", label: "Arrow", kind: "boolean", group: "line" },
755
- { path: "style.extendLeft", label: "Extend left", kind: "boolean", group: "line" },
756
- { path: "style.extendRight", label: "Extend right", kind: "boolean", group: "line" },
1675
+ { path: "style.arrowRight", label: msg("drawing.trendline.arrowRight", "Arrow"), kind: "boolean", group: "line" },
1676
+ { path: "style.extendLeft", label: msg("drawing.trendline.extendLeft", "Extend left"), kind: "boolean", group: "line" },
1677
+ { path: "style.extendRight", label: msg("drawing.trendline.extendRight", "Extend right"), kind: "boolean", group: "line" },
757
1678
  ...TEXT_FIELDS
758
1679
  ]
759
1680
  };
@@ -1102,8 +2023,8 @@ var Box = class extends Drawing {
1102
2023
  schema() {
1103
2024
  return {
1104
2025
  fields: [
1105
- ...LINE_FIELDS.map((f) => ({ ...f, label: f.label.replace("Line", "Border") })),
1106
- { path: "style.fillColor", label: "Fill color", kind: "color", group: "fill" },
2026
+ ...BORDER_FIELDS,
2027
+ { path: "style.fillColor", label: msg("drawing.box.fillColor", "Fill color"), kind: "color", group: "fill" },
1107
2028
  ...TEXT_FIELDS
1108
2029
  ]
1109
2030
  };
@@ -1113,13 +2034,16 @@ var Box = class extends Drawing {
1113
2034
  // src/core/drawings/types/PinnedLabel.ts
1114
2035
  var SIZE_PX = { tiny: 10, small: 12, normal: 14, large: 18, huge: 24, auto: 14 };
1115
2036
  var PinnedLabel = class extends Drawing {
1116
- /** The placeholder string when no text has been entered yet. */
2037
+ /** The placeholder text when no text has been entered yet. */
1117
2038
  defaultLabel() {
1118
- return "Text";
2039
+ return msg("drawing.text.placeholder", "Text");
2040
+ }
2041
+ placeholderText() {
2042
+ return this.defaultLabel();
1119
2043
  }
1120
2044
  /** The string used to size the approximate hit box (subclasses with computed text override it). */
1121
2045
  labelText() {
1122
- return this.text?.value ?? this.defaultLabel();
2046
+ return this.text?.value ?? sourceText(this.defaultLabel());
1123
2047
  }
1124
2048
  anchorSchema() {
1125
2049
  return { min: 1, max: 1, slots: [{ role: "p", free: "both" }] };
@@ -1173,10 +2097,10 @@ var Note = class extends PinnedLabel {
1173
2097
  constructor(init) {
1174
2098
  super(init);
1175
2099
  this.type = "note";
1176
- if (!this.text) this.text = defaultText("Note");
2100
+ if (!this.text) this.text = defaultText(sourceText(this.defaultLabel()));
1177
2101
  }
1178
2102
  defaultLabel() {
1179
- return "Note";
2103
+ return msg("drawing.note.placeholder", "Note");
1180
2104
  }
1181
2105
  schema() {
1182
2106
  return { fields: [...LINE_FIELDS, ...FILL_FIELDS, ...TEXT_FIELDS], textIsContent: true };
@@ -1205,15 +2129,19 @@ var SIZE_PX2 = { tiny: 10, small: 12, normal: 14, large: 18, huge: 24, auto: 14
1205
2129
  var CalloutBase = class extends Drawing {
1206
2130
  constructor(init) {
1207
2131
  super(init);
1208
- if (!this.text) this.text = defaultText(this.defaultLabel());
2132
+ if (!this.text) this.text = defaultText(sourceText(this.defaultLabel()));
1209
2133
  }
1210
2134
  /** The placeholder text seeded for a fresh annotation. */
1211
2135
  defaultLabel() {
1212
- return "Callout";
2136
+ return msg("drawing.callout.placeholder", "Callout");
2137
+ }
2138
+ placeholderText() {
2139
+ const label = this.defaultLabel();
2140
+ return sourceText(label) === "" ? null : label;
1213
2141
  }
1214
2142
  /** The string used to size the approximate hit box (auto-text subclasses override it). */
1215
2143
  labelText() {
1216
- return this.text?.value ?? this.defaultLabel();
2144
+ return this.text?.value ?? sourceText(this.defaultLabel());
1217
2145
  }
1218
2146
  anchorSchema() {
1219
2147
  return { min: 2, max: 2, slots: [{ role: "target", free: "both" }, { role: "box", free: "both" }] };
@@ -1318,7 +2246,7 @@ var Comment = class extends CalloutBase {
1318
2246
  this.type = "comment";
1319
2247
  }
1320
2248
  defaultLabel() {
1321
- return "Comment";
2249
+ return msg("drawing.comment.placeholder", "Comment");
1322
2250
  }
1323
2251
  };
1324
2252
 
@@ -1329,7 +2257,7 @@ var Signpost = class extends CalloutBase {
1329
2257
  this.type = "signpost";
1330
2258
  }
1331
2259
  defaultLabel() {
1332
- return "Signpost";
2260
+ return msg("drawing.signpost.placeholder", "Signpost");
1333
2261
  }
1334
2262
  };
1335
2263
 
@@ -1758,15 +2686,15 @@ var RegressionChannel = class extends Drawing {
1758
2686
  schema() {
1759
2687
  return {
1760
2688
  fields: [
1761
- { path: "reg.midColor", label: "Midline color", kind: "color", group: "line" },
1762
- { path: "reg.midStyle", label: "Midline style", kind: "lineStyle", group: "line" },
1763
- { path: "reg.upperColor", label: "Upper line color", kind: "color", group: "line" },
1764
- { path: "reg.upperStyle", label: "Upper line style", kind: "lineStyle", group: "line" },
1765
- { path: "reg.lowerColor", label: "Lower line color", kind: "color", group: "line" },
1766
- { path: "reg.lowerStyle", label: "Lower line style", kind: "lineStyle", group: "line" },
1767
- { path: "reg.upperFill", label: "Upper fill", kind: "color", group: "fill" },
1768
- { path: "reg.lowerFill", label: "Lower fill", kind: "color", group: "fill" },
1769
- { path: "reg.showR2", label: "Show R\xB2", kind: "boolean", group: "behavior" }
2689
+ { path: "reg.midColor", label: msg("drawing.regressionchannel.regMidColor", "Midline color"), kind: "color", group: "line" },
2690
+ { path: "reg.midStyle", label: msg("drawing.regressionchannel.regMidStyle", "Midline style"), kind: "lineStyle", group: "line" },
2691
+ { path: "reg.upperColor", label: msg("drawing.regressionchannel.regUpperColor", "Upper line color"), kind: "color", group: "line" },
2692
+ { path: "reg.upperStyle", label: msg("drawing.regressionchannel.regUpperStyle", "Upper line style"), kind: "lineStyle", group: "line" },
2693
+ { path: "reg.lowerColor", label: msg("drawing.regressionchannel.regLowerColor", "Lower line color"), kind: "color", group: "line" },
2694
+ { path: "reg.lowerStyle", label: msg("drawing.regressionchannel.regLowerStyle", "Lower line style"), kind: "lineStyle", group: "line" },
2695
+ { path: "reg.upperFill", label: msg("drawing.regressionchannel.regUpperFill", "Upper fill"), kind: "color", group: "fill" },
2696
+ { path: "reg.lowerFill", label: msg("drawing.regressionchannel.regLowerFill", "Lower fill"), kind: "color", group: "fill" },
2697
+ { path: "reg.showR2", label: msg("drawing.regressionchannel.regShowR2", "Show R²"), kind: "boolean", group: "behavior" }
1770
2698
  ]
1771
2699
  };
1772
2700
  }
@@ -1916,12 +2844,12 @@ var AnchoredVwap = class extends Drawing {
1916
2844
  schema() {
1917
2845
  return {
1918
2846
  fields: [
1919
- { path: "vwap.midColor", label: "VWAP color", kind: "color", group: "line" },
1920
- { path: "vwap.midStyle", label: "VWAP style", kind: "lineStyle", group: "line" },
1921
- { path: "vwap.multiplier", label: "Band multiplier", kind: "number", min: 0.5, max: 5, step: 0.5, group: "behavior" },
1922
- { path: "vwap.upperColor", label: "Upper band color", kind: "color", group: "line" },
1923
- { path: "vwap.lowerColor", label: "Lower band color", kind: "color", group: "line" },
1924
- { path: "vwap.bandFill", label: "Band fill", kind: "color", group: "fill" }
2847
+ { path: "vwap.midColor", label: msg("drawing.anchoredvwap.vwapMidColor", "VWAP color"), kind: "color", group: "line" },
2848
+ { path: "vwap.midStyle", label: msg("drawing.anchoredvwap.vwapMidStyle", "VWAP style"), kind: "lineStyle", group: "line" },
2849
+ { path: "vwap.multiplier", label: msg("drawing.anchoredvwap.vwapMultiplier", "Band multiplier"), kind: "number", min: 0.5, max: 5, step: 0.5, group: "behavior" },
2850
+ { path: "vwap.upperColor", label: msg("drawing.anchoredvwap.vwapUpperColor", "Upper band color"), kind: "color", group: "line" },
2851
+ { path: "vwap.lowerColor", label: msg("drawing.anchoredvwap.vwapLowerColor", "Lower band color"), kind: "color", group: "line" },
2852
+ { path: "vwap.bandFill", label: msg("drawing.anchoredvwap.vwapBandFill", "Band fill"), kind: "color", group: "fill" }
1925
2853
  ]
1926
2854
  };
1927
2855
  }
@@ -2224,38 +3152,38 @@ var FixedRangeVolumeProfile = class extends Drawing {
2224
3152
  schema() {
2225
3153
  return {
2226
3154
  fields: [
2227
- { path: "frvp.rows", label: "Rows", kind: "number", min: 1, max: 500, step: 1, group: "behavior" },
2228
- { path: "frvp.valueAreaPct", label: "Value Area", kind: "number", min: 0, max: 100, step: 1, group: "behavior" },
2229
- { path: "frvp.widthPct", label: "Width %", kind: "number", min: 0, max: 100, step: 1, group: "behavior" },
3155
+ { path: "frvp.rows", label: msg("drawing.fixedrangevp.frvpRows", "Rows"), kind: "number", min: 1, max: 500, step: 1, group: "behavior" },
3156
+ { path: "frvp.valueAreaPct", label: msg("drawing.fixedrangevp.frvpValueAreaPct", "Value Area"), kind: "number", min: 0, max: 100, step: 1, group: "behavior" },
3157
+ { path: "frvp.widthPct", label: msg("drawing.fixedrangevp.frvpWidthPct", "Width %"), kind: "number", min: 0, max: 100, step: 1, group: "behavior" },
2230
3158
  {
2231
3159
  path: "frvp.anchor",
2232
- label: "Anchor",
3160
+ label: msg("drawing.fixedrangevp.frvpAnchor", "Anchor"),
2233
3161
  kind: "select",
2234
3162
  options: [
2235
- { value: "right", label: "Right" },
2236
- { value: "left", label: "Left" }
3163
+ { value: "right", label: msg("drawing.fixedrangevp.option.right", "Right") },
3164
+ { value: "left", label: msg("drawing.fixedrangevp.option.left", "Left") }
2237
3165
  ],
2238
3166
  group: "behavior"
2239
3167
  },
2240
- { path: "frvp.upColor", label: "Up Volume", kind: "color", group: "fill" },
2241
- { path: "frvp.downColor", label: "Down Volume", kind: "color", group: "fill" },
2242
- { path: "frvp.vaUpColor", label: "Value Area Up", kind: "color", group: "fill" },
2243
- { path: "frvp.vaDownColor", label: "Value Area Down", kind: "color", group: "fill" },
2244
- { path: "frvp.showVah", label: "VAH", kind: "boolean", group: "line" },
2245
- { path: "frvp.vahColor", label: "VAH color", kind: "color", group: "line" },
2246
- { path: "frvp.vahStyle", label: "VAH style", kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
2247
- { path: "frvp.showVal", label: "VAL", kind: "boolean", group: "line" },
2248
- { path: "frvp.valColor", label: "VAL color", kind: "color", group: "line" },
2249
- { path: "frvp.valStyle", label: "VAL style", kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
2250
- { path: "frvp.showPoc", label: "POC", kind: "boolean", group: "line" },
2251
- { path: "frvp.pocColor", label: "POC color", kind: "color", group: "line" },
2252
- { path: "frvp.pocStyle", label: "POC style", kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
2253
- { path: "frvp.showDevelopingPoc", label: "Developing POC", kind: "boolean", group: "line" },
2254
- { path: "frvp.developingPocColor", label: "Developing POC color", kind: "color", group: "line" },
2255
- { path: "frvp.developingPocStyle", label: "Developing POC style", kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
2256
- { path: "frvp.showDevelopingVa", label: "Developing VA", kind: "boolean", group: "line" },
2257
- { path: "frvp.developingVaColor", label: "Developing VA color", kind: "color", group: "line" },
2258
- { path: "frvp.developingVaStyle", label: "Developing VA style", kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" }
3168
+ { path: "frvp.upColor", label: msg("drawing.fixedrangevp.frvpUpColor", "Up Volume"), kind: "color", group: "fill" },
3169
+ { path: "frvp.downColor", label: msg("drawing.fixedrangevp.frvpDownColor", "Down Volume"), kind: "color", group: "fill" },
3170
+ { path: "frvp.vaUpColor", label: msg("drawing.fixedrangevp.frvpVaUpColor", "Value Area Up"), kind: "color", group: "fill" },
3171
+ { path: "frvp.vaDownColor", label: msg("drawing.fixedrangevp.frvpVaDownColor", "Value Area Down"), kind: "color", group: "fill" },
3172
+ { path: "frvp.showVah", label: msg("drawing.fixedrangevp.frvpShowVah", "VAH"), kind: "boolean", group: "line" },
3173
+ { path: "frvp.vahColor", label: msg("drawing.fixedrangevp.frvpVahColor", "VAH color"), kind: "color", group: "line" },
3174
+ { path: "frvp.vahStyle", label: msg("drawing.fixedrangevp.frvpVahStyle", "VAH style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
3175
+ { path: "frvp.showVal", label: msg("drawing.fixedrangevp.frvpShowVal", "VAL"), kind: "boolean", group: "line" },
3176
+ { path: "frvp.valColor", label: msg("drawing.fixedrangevp.frvpValColor", "VAL color"), kind: "color", group: "line" },
3177
+ { path: "frvp.valStyle", label: msg("drawing.fixedrangevp.frvpValStyle", "VAL style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
3178
+ { path: "frvp.showPoc", label: msg("drawing.fixedrangevp.frvpShowPoc", "POC"), kind: "boolean", group: "line" },
3179
+ { path: "frvp.pocColor", label: msg("drawing.fixedrangevp.frvpPocColor", "POC color"), kind: "color", group: "line" },
3180
+ { path: "frvp.pocStyle", label: msg("drawing.fixedrangevp.frvpPocStyle", "POC style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
3181
+ { path: "frvp.showDevelopingPoc", label: msg("drawing.fixedrangevp.frvpShowDevelopingPoc", "Developing POC"), kind: "boolean", group: "line" },
3182
+ { path: "frvp.developingPocColor", label: msg("drawing.fixedrangevp.frvpDevelopingPocColor", "Developing POC color"), kind: "color", group: "line" },
3183
+ { path: "frvp.developingPocStyle", label: msg("drawing.fixedrangevp.frvpDevelopingPocStyle", "Developing POC style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
3184
+ { path: "frvp.showDevelopingVa", label: msg("drawing.fixedrangevp.frvpShowDevelopingVa", "Developing VA"), kind: "boolean", group: "line" },
3185
+ { path: "frvp.developingVaColor", label: msg("drawing.fixedrangevp.frvpDevelopingVaColor", "Developing VA color"), kind: "color", group: "line" },
3186
+ { path: "frvp.developingVaStyle", label: msg("drawing.fixedrangevp.frvpDevelopingVaStyle", "Developing VA style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" }
2259
3187
  ]
2260
3188
  };
2261
3189
  }
@@ -2525,8 +3453,8 @@ var Arrow = class extends Drawing {
2525
3453
  return {
2526
3454
  fields: [
2527
3455
  ...LINE_FIELDS,
2528
- { path: "style.arrowRight", label: "Head (end)", kind: "boolean", group: "line" },
2529
- { path: "style.arrowLeft", label: "Head (start)", kind: "boolean", group: "line" },
3456
+ { path: "style.arrowRight", label: msg("drawing.arrow.arrowRight", "Head (end)"), kind: "boolean", group: "line" },
3457
+ { path: "style.arrowLeft", label: msg("drawing.arrow.arrowLeft", "Head (start)"), kind: "boolean", group: "line" },
2530
3458
  ...TEXT_FIELDS
2531
3459
  ]
2532
3460
  };
@@ -2716,8 +3644,8 @@ var Freehand = class extends BrushStroke {
2716
3644
 
2717
3645
  // src/core/drawings/types/Highlighter.ts
2718
3646
  var HIGHLIGHTER_FIELDS = [
2719
- { path: "style.lineColor", label: "Color", kind: "color", group: "line" },
2720
- { path: "style.lineWidth", label: "Width", kind: "number", min: 4, max: 60, step: 1, group: "line" }
3647
+ { path: "style.lineColor", label: msg("drawing.highlighter.lineColor", "Color"), kind: "color", group: "line" },
3648
+ { path: "style.lineWidth", label: msg("drawing.highlighter.lineWidth", "Width"), kind: "number", min: 4, max: 60, step: 1, group: "line" }
2721
3649
  ];
2722
3650
  var Highlighter = class extends BrushStroke {
2723
3651
  constructor() {
@@ -2836,7 +3764,7 @@ var RotatedRect = class extends SegmentDrawing {
2836
3764
  return { min: Math.min(...ps), max: Math.max(...ps) };
2837
3765
  }
2838
3766
  schema() {
2839
- return { fields: [...LINE_FIELDS.map((f) => ({ ...f, label: f.label.replace("Line", "Border") })), ...FILL_FIELDS, ...TEXT_FIELDS] };
3767
+ return { fields: [...BORDER_FIELDS, ...FILL_FIELDS, ...TEXT_FIELDS] };
2840
3768
  }
2841
3769
  };
2842
3770
 
@@ -2918,7 +3846,7 @@ var Arc = class extends SegmentDrawing {
2918
3846
  return { min: Math.min(...ps), max: Math.max(...ps) };
2919
3847
  }
2920
3848
  schema() {
2921
- return { fields: [...LINE_FIELDS.map((f) => ({ ...f, label: f.label.replace("Line", "Border") })), ...FILL_FIELDS, ...TEXT_FIELDS] };
3849
+ return { fields: [...BORDER_FIELDS, ...FILL_FIELDS, ...TEXT_FIELDS] };
2922
3850
  }
2923
3851
  };
2924
3852
 
@@ -3034,7 +3962,7 @@ var ArrowMark = class extends Drawing {
3034
3962
  return a ? { min: a.price, max: a.price } : null;
3035
3963
  }
3036
3964
  schema() {
3037
- return { fields: [{ path: "style.lineColor", label: "Color", kind: "color", group: "line" }, ...TEXT_FIELDS] };
3965
+ return { fields: [{ path: "style.lineColor", label: msg("drawing.arrowmarkup.lineColor", "Color"), kind: "color", group: "line" }, ...TEXT_FIELDS] };
3038
3966
  }
3039
3967
  };
3040
3968
  var ArrowMarkUp = class extends ArrowMark {
@@ -3057,7 +3985,7 @@ var ArrowMarkDown = class extends ArrowMark {
3057
3985
  };
3058
3986
 
3059
3987
  // src/core/drawings/types/GlyphStamp.ts
3060
- var GLYPH_OPTIONS = ["\u2605", "\u2606", "\u25CF", "\u25C6", "\u25B2", "\u25BC", "\u27A4", "\u2691", "\u271A", "\u2715", "\u2764", "\u2666"];
3988
+ var GLYPH_OPTIONS = ["★", "☆", "●", "◆", "▲", "▼", "➤", "⚑", "✚", "✕", "❤", "♦"];
3061
3989
  var STAMP_SIZE_OPTIONS = ["small", "normal", "large", "huge"];
3062
3990
  var STAMP_PX = { small: 16, normal: 22, large: 32, huge: 44 };
3063
3991
  var GlyphStamp = class extends Drawing {
@@ -3106,9 +4034,9 @@ var GlyphStamp = class extends Drawing {
3106
4034
  schema() {
3107
4035
  return {
3108
4036
  fields: [
3109
- { path: "glyph", label: "Icon", kind: "select", options: GLYPH_OPTIONS.map((g) => ({ value: g, label: g })), group: "line" },
3110
- { path: "size", label: "Size", kind: "select", options: STAMP_SIZE_OPTIONS.map((s) => ({ value: s, label: s })), group: "line" },
3111
- { path: "style.lineColor", label: "Color", kind: "color", group: "line" },
4037
+ { path: "glyph", label: msg("drawing.flagmark.glyph", "Icon"), kind: "select", options: GLYPH_OPTIONS.map((g) => ({ value: g, label: g })), group: "line" },
4038
+ { path: "size", label: msg("drawing.flagmark.size", "Size"), kind: "select", options: STAMP_SIZE_OPTIONS.map((s) => ({ value: s, label: s })), group: "line" },
4039
+ { path: "style.lineColor", label: msg("drawing.flagmark.lineColor", "Color"), kind: "color", group: "line" },
3112
4040
  ...TEXT_FIELDS
3113
4041
  ]
3114
4042
  };
@@ -3127,7 +4055,7 @@ var FlagMark = class extends GlyphStamp {
3127
4055
  this.type = "flagmark";
3128
4056
  }
3129
4057
  defaultGlyph() {
3130
- return "\u2691";
4058
+ return "⚑";
3131
4059
  }
3132
4060
  };
3133
4061
  var IconStamp = class extends GlyphStamp {
@@ -3136,7 +4064,7 @@ var IconStamp = class extends GlyphStamp {
3136
4064
  this.type = "iconstamp";
3137
4065
  }
3138
4066
  defaultGlyph() {
3139
- return "\u2605";
4067
+ return "★";
3140
4068
  }
3141
4069
  };
3142
4070
 
@@ -3203,8 +4131,8 @@ var FibRatios = class extends Drawing {
3203
4131
  }
3204
4132
  readProps(props) {
3205
4133
  if (Array.isArray(props.levels)) {
3206
- const parsed = props.levels.map(sanitizeLevel).filter((l) => l != null);
3207
- if (parsed.length) this.levels = parsed;
4134
+ const parsed2 = props.levels.map(sanitizeLevel).filter((l) => l != null);
4135
+ if (parsed2.length) this.levels = parsed2;
3208
4136
  }
3209
4137
  if (isFibSize(props.numbersSize)) this.numbersSize = props.numbersSize;
3210
4138
  if (isFibSize(props.labelsSize)) this.labelsSize = props.labelsSize;
@@ -3295,8 +4223,8 @@ var FibLevels = class extends FibRatios {
3295
4223
  return {
3296
4224
  fields: [
3297
4225
  ...base.fields,
3298
- { path: "style.extendLeft", label: "Extend left", kind: "boolean", group: "line" },
3299
- { path: "style.extendRight", label: "Extend right", kind: "boolean", group: "line" }
4226
+ { path: "style.extendLeft", label: msg("drawing.field.extendLeft", "Extend left"), kind: "boolean", group: "line" },
4227
+ { path: "style.extendRight", label: msg("drawing.field.extendRight", "Extend right"), kind: "boolean", group: "line" }
3300
4228
  ]
3301
4229
  };
3302
4230
  }
@@ -3415,19 +4343,19 @@ function ladder(ratios, on, colors = {}) {
3415
4343
  var FIB_PRESETS = [
3416
4344
  {
3417
4345
  key: "classic",
3418
- label: "Classic",
4346
+ label: msg("drawing.fibPreset.classic", "Classic"),
3419
4347
  reverse: false,
3420
4348
  levels: ladder(LADDER, [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1])
3421
4349
  },
3422
4350
  {
3423
4351
  key: "extension",
3424
- label: "Extension",
4352
+ label: msg("drawing.fibPreset.extension", "Extension"),
3425
4353
  reverse: true,
3426
4354
  levels: ladder(LADDER, [0, 1, 1.272, 1.414, 1.618, 2, 2.618, 3.618, 4.236])
3427
4355
  },
3428
4356
  {
3429
4357
  key: "ote",
3430
- label: "OTE",
4358
+ label: msg("drawing.fibPreset.ote", "OTE"),
3431
4359
  reverse: false,
3432
4360
  // The entry zone reads as one band.
3433
4361
  levels: ladder(OTE_LADDER, [0, 0.5, 0.62, 0.705, 0.79, 1, -0.27, -0.62], { "0.62": LEVEL_AMBER, "0.79": LEVEL_AMBER })
@@ -4376,7 +5304,7 @@ var DedekindTessellation = class extends Drawing {
4376
5304
  ...LINE_FIELDS,
4377
5305
  {
4378
5306
  path: "maxCurvature",
4379
- label: "Max curvature",
5307
+ label: msg("drawing.dedekind.maxCurvature", "Max curvature"),
4380
5308
  kind: "number",
4381
5309
  min: 4,
4382
5310
  max: 64,
@@ -4416,7 +5344,7 @@ function sanitizeLevel2(v) {
4416
5344
  }
4417
5345
  var SHOW_RATIOS_FIELD = {
4418
5346
  path: "showRatios",
4419
- label: "Show ratios",
5347
+ label: msg("drawing.sonic.showRatios", "Show ratios"),
4420
5348
  kind: "boolean",
4421
5349
  group: "behavior"
4422
5350
  };
@@ -4568,7 +5496,7 @@ var MachFigure = class extends Drawing {
4568
5496
  ...LINE_FIELDS,
4569
5497
  {
4570
5498
  path: "waveCount",
4571
- label: "Waves",
5499
+ label: msg("drawing.sonic.waveCount", "Waves"),
4572
5500
  kind: "number",
4573
5501
  min: 3,
4574
5502
  max: 12,
@@ -4593,8 +5521,8 @@ var MachFigure = class extends Drawing {
4593
5521
  }
4594
5522
  if (typeof props.showRatios === "boolean") this.showRatios = props.showRatios;
4595
5523
  if (Array.isArray(props.levels)) {
4596
- const parsed = props.levels.map(sanitizeLevel2).filter((l) => l != null);
4597
- if (parsed.length) this.levels = parsed;
5524
+ const parsed2 = props.levels.map(sanitizeLevel2).filter((l) => l != null);
5525
+ if (parsed2.length) this.levels = parsed2;
4598
5526
  }
4599
5527
  }
4600
5528
  };
@@ -4628,7 +5556,7 @@ var Supersonic = class extends MachFigure {
4628
5556
  ...LINE_FIELDS,
4629
5557
  {
4630
5558
  path: "mach",
4631
- label: "Mach number",
5559
+ label: msg("drawing.supersonic.mach", "Mach number"),
4632
5560
  kind: "number",
4633
5561
  min: 1.5,
4634
5562
  max: 5,
@@ -4637,7 +5565,7 @@ var Supersonic = class extends MachFigure {
4637
5565
  },
4638
5566
  {
4639
5567
  path: "waveCount",
4640
- label: "Waves",
5568
+ label: msg("drawing.supersonic.waveCount", "Waves"),
4641
5569
  kind: "number",
4642
5570
  min: 3,
4643
5571
  max: 12,
@@ -4702,7 +5630,7 @@ var GoldenSupersonic = class extends MachFigure {
4702
5630
  ...LINE_FIELDS,
4703
5631
  {
4704
5632
  path: "mach",
4705
- label: "Mach number",
5633
+ label: msg("drawing.goldensupersonic.mach", "Mach number"),
4706
5634
  kind: "number",
4707
5635
  min: 1.5,
4708
5636
  max: 5,
@@ -4859,13 +5787,16 @@ var ElliottCorrection = class extends PatternDrawing {
4859
5787
  };
4860
5788
 
4861
5789
  // src/core/drawings/types/HeadShoulders.ts
5790
+ var LEFT_SHOULDER = msg("drawing.headshoulders.leftShoulder", "LS");
5791
+ var HEAD = msg("drawing.headshoulders.head", "H");
5792
+ var RIGHT_SHOULDER = msg("drawing.headshoulders.rightShoulder", "RS");
4862
5793
  var HeadShoulders = class extends PatternDrawing {
4863
5794
  constructor() {
4864
5795
  super(...arguments);
4865
5796
  this.type = "headshoulders";
4866
5797
  }
4867
5798
  vertexLabels() {
4868
- return ["", "LS", "", "H", "", "RS", ""];
5799
+ return ["", LEFT_SHOULDER, "", HEAD, "", RIGHT_SHOULDER, ""];
4869
5800
  }
4870
5801
  necklineIndices() {
4871
5802
  return [2, 4];
@@ -4929,7 +5860,7 @@ var Gartley = class extends HarmonicPattern {
4929
5860
  this.type = "gartley";
4930
5861
  }
4931
5862
  patternName() {
4932
- return "Gartley";
5863
+ return msg("drawing.gartley.patternName", "Gartley");
4933
5864
  }
4934
5865
  ranges() {
4935
5866
  return { ab: { min: 0.55, max: 0.68 }, bc: { min: 0.382, max: 0.886 }, cd: { min: 1.13, max: 1.618 }, ad: { min: 0.74, max: 0.83 } };
@@ -4943,7 +5874,7 @@ var Bat = class extends HarmonicPattern {
4943
5874
  this.type = "bat";
4944
5875
  }
4945
5876
  patternName() {
4946
- return "Bat";
5877
+ return msg("drawing.bat.patternName", "Bat");
4947
5878
  }
4948
5879
  ranges() {
4949
5880
  return { ab: { min: 0.382, max: 0.5 }, bc: { min: 0.382, max: 0.886 }, cd: { min: 1.618, max: 2.618 }, ad: { min: 0.84, max: 0.92 } };
@@ -4957,7 +5888,7 @@ var Butterfly = class extends HarmonicPattern {
4957
5888
  this.type = "butterfly";
4958
5889
  }
4959
5890
  patternName() {
4960
- return "Butterfly";
5891
+ return msg("drawing.butterfly.patternName", "Butterfly");
4961
5892
  }
4962
5893
  ranges() {
4963
5894
  return { ab: { min: 0.74, max: 0.83 }, bc: { min: 0.382, max: 0.886 }, cd: { min: 1.618, max: 2.618 }, ad: { min: 1.272, max: 1.618 } };
@@ -4971,7 +5902,7 @@ var Crab = class extends HarmonicPattern {
4971
5902
  this.type = "crab";
4972
5903
  }
4973
5904
  patternName() {
4974
- return "Crab";
5905
+ return msg("drawing.crab.patternName", "Crab");
4975
5906
  }
4976
5907
  ranges() {
4977
5908
  return { ab: { min: 0.382, max: 0.618 }, bc: { min: 0.382, max: 0.886 }, cd: { min: 2.618, max: 3.618 }, ad: { min: 1.55, max: 1.69 } };
@@ -4985,7 +5916,7 @@ var Shark = class extends HarmonicPattern {
4985
5916
  this.type = "shark";
4986
5917
  }
4987
5918
  patternName() {
4988
- return "Shark";
5919
+ return msg("drawing.shark.patternName", "Shark");
4989
5920
  }
4990
5921
  ranges() {
4991
5922
  return { ab: { min: 0.382, max: 0.618 }, bc: { min: 1.13, max: 1.618 }, cd: { min: 1.618, max: 2.24 }, ad: { min: 0.886, max: 1.13 } };
@@ -5001,7 +5932,7 @@ var Cypher = class extends HarmonicPattern {
5001
5932
  this.type = "cypher";
5002
5933
  }
5003
5934
  patternName() {
5004
- return "Cypher";
5935
+ return msg("drawing.cypher.patternName", "Cypher");
5005
5936
  }
5006
5937
  ranges() {
5007
5938
  return { ab: { min: 0.382, max: 0.618 }, bc: { min: 0, max: Infinity }, cd: { min: 0, max: Infinity }, ad: { min: 0, max: Infinity } };
@@ -5035,27 +5966,13 @@ var Cypher = class extends HarmonicPattern {
5035
5966
  };
5036
5967
 
5037
5968
  // src/core/drawings/types/MeasureBox.ts
5969
+ var MEASURE_TEXT = {
5970
+ priceChange: msg("drawing.measure.priceChange", "{change} ({percent}%)"),
5971
+ barsAndDuration: msg("drawing.measure.barsAndDuration", "{count, plural, one {{bars} bar} other {{bars} bars}}, {duration}")
5972
+ };
5038
5973
  function signed(n) {
5039
5974
  return `${n >= 0 ? "+" : ""}${n.toFixed(2)}`;
5040
5975
  }
5041
- function formatDuration(ms) {
5042
- const m = Math.abs(ms);
5043
- const DAY2 = 864e5;
5044
- const HR = 36e5;
5045
- const MIN2 = 6e4;
5046
- if (m >= DAY2) {
5047
- const d = Math.floor(m / DAY2);
5048
- const h = Math.round(m % DAY2 / HR);
5049
- return h ? `${d}d ${h}h` : `${d}d`;
5050
- }
5051
- if (m >= HR) {
5052
- const h = Math.floor(m / HR);
5053
- const mn = Math.round(m % HR / MIN2);
5054
- return mn ? `${h}h ${mn}m` : `${h}h`;
5055
- }
5056
- if (m >= MIN2) return `${Math.round(m / MIN2)}m`;
5057
- return `${Math.round(m / 1e3)}s`;
5058
- }
5059
5976
  var MeasureBox = class extends Drawing {
5060
5977
  constructor(init) {
5061
5978
  super(init);
@@ -5067,11 +5984,12 @@ var MeasureBox = class extends Drawing {
5067
5984
  }
5068
5985
  // Placed click-move-click (the inherited 'click' mode): first click sets a corner, the second
5069
5986
  // sets the opposite one — consistent with the box/Gann tools.
5070
- /** The measurement lines, filtered by the enabled toggles. */
5071
- measureLabel(proj) {
5987
+ /** The measurement lines, filtered by the enabled toggles, in `i18n`'s language
5988
+ * (English without one). */
5989
+ measureLabel(proj, i18n) {
5072
5990
  const lines = [];
5073
- if (this.showPrice) lines.push(this.priceLabel());
5074
- if (this.showDate) lines.push(this.timeLabel(proj));
5991
+ if (this.showPrice) lines.push(this.priceLabel(i18n));
5992
+ if (this.showDate) lines.push(this.timeLabel(proj, i18n));
5075
5993
  return lines;
5076
5994
  }
5077
5995
  /** Up (later price ≥ earlier) → green; else red. */
@@ -5081,22 +5999,22 @@ var MeasureBox = class extends Drawing {
5081
5999
  return a != null && b != null && b.price >= a.price;
5082
6000
  }
5083
6001
  /** Formatted `Δprice (Δ%)` between the two anchors. */
5084
- priceLabel() {
6002
+ priceLabel(i18n) {
5085
6003
  const a = this.anchors[0];
5086
6004
  const b = this.anchors[1];
5087
6005
  if (!a || !b) return "";
5088
6006
  const delta = b.price - a.price;
5089
6007
  const percent = a.price !== 0 ? delta / a.price * 100 : 0;
5090
- return `${signed(delta)} (${signed(percent)}%)`;
6008
+ return textOf(i18n, MEASURE_TEXT.priceChange, { change: localizeNumberText(signed(delta), i18n), percent: localizeNumberText(signed(percent), i18n) });
5091
6009
  }
5092
6010
  /** Formatted `N bars, duration` between the two anchors (bars only when the projector knows). */
5093
- timeLabel(proj) {
6011
+ timeLabel(proj, i18n) {
5094
6012
  const a = this.anchors[0];
5095
6013
  const b = this.anchors[1];
5096
6014
  if (!a || !b) return "";
5097
- const duration = formatDuration(b.time - a.time);
6015
+ const duration = (i18n ?? englishTranslator()).format.duration(b.time - a.time, { style: "span", surface: "drawing" });
5098
6016
  const bars = proj.barsBetween ? Math.round(proj.barsBetween(a.time, b.time)) : null;
5099
- return bars != null ? `${bars} bars, ${duration}` : duration;
6017
+ return bars != null ? textOf(i18n, MEASURE_TEXT.barsAndDuration, { count: bars, bars: localizeNumberText(String(bars), i18n), duration }) : duration;
5100
6018
  }
5101
6019
  rect(proj) {
5102
6020
  const a = this.anchors[0];
@@ -5132,12 +6050,12 @@ var MeasureBox = class extends Drawing {
5132
6050
  schema() {
5133
6051
  return {
5134
6052
  fields: [
5135
- { path: "showPrice", label: "Show price", kind: "boolean", group: "behavior" },
5136
- { path: "showDate", label: "Show date", kind: "boolean", group: "behavior" },
6053
+ { path: "showPrice", label: msg("drawing.measure.showPrice", "Show price"), kind: "boolean", group: "behavior" },
6054
+ { path: "showDate", label: msg("drawing.measure.showDate", "Show date"), kind: "boolean", group: "behavior" },
5137
6055
  ...LINE_FIELDS.filter((f) => f.path !== "style.lineColor"),
5138
6056
  // box border (the fill is direction-tinted)
5139
- { path: "text.color", label: "Text color", kind: "color", group: "text" },
5140
- { path: "text.size", label: "Text size", kind: "select", options: TEXT_SIZE_OPTIONS, group: "text" }
6057
+ { path: "text.color", label: msg("drawing.field.textColor", "Text color"), kind: "color", group: "text" },
6058
+ { path: "text.size", label: msg("drawing.field.textSize", "Text size"), kind: "select", options: TEXT_SIZE_OPTIONS, group: "text" }
5141
6059
  ]
5142
6060
  };
5143
6061
  }
@@ -5159,9 +6077,17 @@ var DatePriceRange = class extends MeasureBox {
5159
6077
  };
5160
6078
 
5161
6079
  // src/core/drawings/types/PositionTool.ts
6080
+ var POSITION_TEXT = {
6081
+ header: msg("drawing.position.header", "{direction, select, long {LONG} other {SHORT}} · R:R {ratio}"),
6082
+ lossSize: msg("drawing.position.lossSize", "Loss {loss} · Size {size}"),
6083
+ target: msg("drawing.position.targetLabel", "Target +{percent}%"),
6084
+ targetAt: msg("drawing.position.targetLabelAt", "Target +{percent}% @ {price}"),
6085
+ stop: msg("drawing.position.stopLabel", "Stop −{percent}%"),
6086
+ stopAt: msg("drawing.position.stopLabelAt", "Stop −{percent}% @ {price}")
6087
+ };
5162
6088
  var DIRECTION_OPTIONS = [
5163
- { value: "long", label: "Long" },
5164
- { value: "short", label: "Short" }
6089
+ { value: "long", label: msg("drawing.position.option.long", "Long") },
6090
+ { value: "short", label: msg("drawing.position.option.short", "Short") }
5165
6091
  ];
5166
6092
  var _PositionTool = class _PositionTool extends Drawing {
5167
6093
  constructor(init) {
@@ -5339,7 +6265,7 @@ var _PositionTool = class _PositionTool extends Drawing {
5339
6265
  const p = this.prices();
5340
6266
  return p && p.entry !== 0 ? Math.abs(p.entry - p.stop) / p.entry * 100 : 0;
5341
6267
  }
5342
- /** Dollar amount risked at the stop = accountBalance × riskPercent / 100. */
6268
+ /** Amount risked at the stop, in the balance's units = accountBalance × riskPercent / 100. */
5343
6269
  dollarLoss() {
5344
6270
  return Math.max(0, this.accountBalance) * (Math.max(0, this.riskPercent) / 100);
5345
6271
  }
@@ -5351,25 +6277,34 @@ var _PositionTool = class _PositionTool extends Drawing {
5351
6277
  return risk < 1e-9 ? 0 : this.dollarLoss() / risk;
5352
6278
  }
5353
6279
  // ── painted label lines (each respects its own toggle; the painter checks showText) ──
5354
- /** `DIR · R:R x.xx` — the always-on header when text is shown. */
5355
- headerLabel() {
5356
- return `${this.directionLabel()} \xB7 R:R ${this.rr().toFixed(2)}`;
6280
+ /** `DIR · R:R x.xx` — the always-on header when text is shown, in `i18n`'s language
6281
+ * (English without one). */
6282
+ headerLabel(i18n) {
6283
+ return textOf(i18n, POSITION_TEXT.header, {
6284
+ direction: this.directionLabel() === "LONG" ? "long" : "short",
6285
+ ratio: localizeNumberText(this.rr().toFixed(2), i18n)
6286
+ });
5357
6287
  }
5358
- /** `Loss $… · Size …` — the painter hides it when showLossSize is off. */
5359
- lossSizeLabel() {
5360
- return `Loss $${formatMoney(this.dollarLoss())} \xB7 Size ${formatQty(this.positionSize())}`;
6288
+ /** `Loss … · Size …` — the painter hides it when showLossSize is off. */
6289
+ lossSizeLabel(i18n) {
6290
+ return textOf(i18n, POSITION_TEXT.lossSize, {
6291
+ loss: localizeNumberText(formatMoney(this.dollarLoss()), i18n),
6292
+ size: localizeNumberText(formatQty(this.positionSize()), i18n)
6293
+ });
5361
6294
  }
5362
6295
  /** `Target +x.xx%`, with the level price appended when showPrices is on. */
5363
- targetLabel() {
6296
+ targetLabel(i18n) {
5364
6297
  const p = this.prices();
5365
- const at = this.showPrices && p ? ` @ ${formatPrice(p.target)}` : "";
5366
- return `Target +${this.rewardPct().toFixed(2)}%${at}`;
6298
+ const percent = localizeNumberText(this.rewardPct().toFixed(2), i18n);
6299
+ if (this.showPrices && p) return textOf(i18n, POSITION_TEXT.targetAt, { percent, price: localizeNumberText(formatPrice2(p.target), i18n) });
6300
+ return textOf(i18n, POSITION_TEXT.target, { percent });
5367
6301
  }
5368
6302
  /** `Stop −x.xx%`, with the level price appended when showPrices is on. */
5369
- stopLabel() {
6303
+ stopLabel(i18n) {
5370
6304
  const p = this.prices();
5371
- const at = this.showPrices && p ? ` @ ${formatPrice(p.stop)}` : "";
5372
- return `Stop \u2212${this.riskPct().toFixed(2)}%${at}`;
6305
+ const percent = localizeNumberText(this.riskPct().toFixed(2), i18n);
6306
+ if (this.showPrices && p) return textOf(i18n, POSITION_TEXT.stopAt, { percent, price: localizeNumberText(formatPrice2(p.stop), i18n) });
6307
+ return textOf(i18n, POSITION_TEXT.stop, { percent });
5373
6308
  }
5374
6309
  // ── stop/target input units (the gear panel's Price / Points dropdowns) ──
5375
6310
  /** The stop or target expressed in the given unit: the absolute price, or the distance from
@@ -5438,24 +6373,24 @@ var _PositionTool = class _PositionTool extends Drawing {
5438
6373
  schema() {
5439
6374
  return {
5440
6375
  fields: [
5441
- { path: "riskPercent", label: "Risk %", kind: "number", min: 0, max: 100, step: 0.1, group: "behavior" },
5442
- { path: "accountBalance", label: "Account balance", kind: "number", min: 0, max: 1e12, step: 1, group: "behavior" },
5443
- { path: "quantity", label: "Position size", kind: "number", group: "behavior" },
5444
- { path: "direction", label: "Direction", kind: "select", options: DIRECTION_OPTIONS, group: "behavior" },
5445
- { path: "entryPrice", label: "Entry price", kind: "number", group: "behavior" },
5446
- { path: "stopPrice", label: "Stop price", kind: "number", group: "behavior" },
5447
- { path: "targetPrice", label: "Target price", kind: "number", group: "behavior" },
5448
- { path: "showText", label: "Show text", kind: "boolean", group: "behavior" },
5449
- { path: "showHeader", label: "Show direction & ratio", kind: "boolean", group: "behavior" },
5450
- { path: "showLossSize", label: "Show loss & size", kind: "boolean", group: "behavior" },
5451
- { path: "showTargetLabel", label: "Show target label", kind: "boolean", group: "behavior" },
5452
- { path: "showStopLabel", label: "Show stop label", kind: "boolean", group: "behavior" },
5453
- { path: "showPrices", label: "Show level prices", kind: "boolean", group: "behavior" },
5454
- { path: "profitColor", label: "Profit zone", kind: "color", group: "fill" },
5455
- { path: "lossColor", label: "Loss zone", kind: "color", group: "fill" },
6376
+ { path: "riskPercent", label: msg("drawing.position.riskPercent", "Risk %"), kind: "number", min: 0, max: 100, step: 0.1, group: "behavior" },
6377
+ { path: "accountBalance", label: msg("drawing.position.accountBalance", "Account balance"), kind: "number", min: 0, max: 1e12, step: 1, group: "behavior" },
6378
+ { path: "quantity", label: msg("drawing.position.quantity", "Position size"), kind: "number", group: "behavior" },
6379
+ { path: "direction", label: msg("drawing.position.direction", "Direction"), kind: "select", options: DIRECTION_OPTIONS, group: "behavior" },
6380
+ { path: "entryPrice", label: msg("drawing.position.entryPrice", "Entry price"), kind: "number", group: "behavior" },
6381
+ { path: "stopPrice", label: msg("drawing.position.stopPrice", "Stop price"), kind: "number", group: "behavior" },
6382
+ { path: "targetPrice", label: msg("drawing.position.targetPrice", "Target price"), kind: "number", group: "behavior" },
6383
+ { path: "showText", label: msg("drawing.position.showText", "Show text"), kind: "boolean", group: "behavior" },
6384
+ { path: "showHeader", label: msg("drawing.position.showHeader", "Show direction & ratio"), kind: "boolean", group: "behavior" },
6385
+ { path: "showLossSize", label: msg("drawing.position.showLossSize", "Show loss & size"), kind: "boolean", group: "behavior" },
6386
+ { path: "showTargetLabel", label: msg("drawing.position.showTargetLabel", "Show target label"), kind: "boolean", group: "behavior" },
6387
+ { path: "showStopLabel", label: msg("drawing.position.showStopLabel", "Show stop label"), kind: "boolean", group: "behavior" },
6388
+ { path: "showPrices", label: msg("drawing.position.showPrices", "Show level prices"), kind: "boolean", group: "behavior" },
6389
+ { path: "profitColor", label: msg("drawing.position.profitColor", "Profit zone"), kind: "color", group: "fill" },
6390
+ { path: "lossColor", label: msg("drawing.position.lossColor", "Loss zone"), kind: "color", group: "fill" },
5456
6391
  ...LINE_FIELDS.filter((f) => f.path !== "style.lineColor"),
5457
- { path: "text.color", label: "Text color", kind: "color", group: "text" },
5458
- { path: "text.size", label: "Text size", kind: "select", options: TEXT_SIZE_OPTIONS, group: "text" }
6392
+ { path: "text.color", label: msg("drawing.position.textColor", "Text color"), kind: "color", group: "text" },
6393
+ { path: "text.size", label: msg("drawing.position.textSize", "Text size"), kind: "select", options: TEXT_SIZE_OPTIONS, group: "text" }
5459
6394
  ]
5460
6395
  };
5461
6396
  }
@@ -5513,7 +6448,7 @@ function formatQty(n) {
5513
6448
  if (n >= 1) return n.toFixed(4).replace(/\.?0+$/, "");
5514
6449
  return n.toPrecision(4).replace(/\.?0+$/, "");
5515
6450
  }
5516
- function formatPrice(n) {
6451
+ function formatPrice2(n) {
5517
6452
  if (!Number.isFinite(n)) return "0";
5518
6453
  if (Math.abs(n) >= 1) return n.toFixed(2);
5519
6454
  return n.toPrecision(4).replace(/\.?0+$/, "");
@@ -5524,14 +6459,14 @@ function roundFloat(n) {
5524
6459
 
5525
6460
  // src/core/drawings/types/Magnifier.ts
5526
6461
  var MAGNIFIER_TIMEFRAME_OPTIONS = [
5527
- { value: "auto", label: "Auto", ms: 0 },
5528
- { value: "1", label: "1m", ms: 6e4 },
5529
- { value: "5", label: "5m", ms: 3e5 },
5530
- { value: "15", label: "15m", ms: 9e5 },
5531
- { value: "30", label: "30m", ms: 18e5 },
5532
- { value: "60", label: "1h", ms: 36e5 },
5533
- { value: "240", label: "4h", ms: 144e5 },
5534
- { value: "D", label: "1D", ms: 864e5 }
6462
+ { value: "auto", label: msg("drawing.magnifier.option.auto", "Auto"), ms: 0 },
6463
+ { value: "1", label: msg("drawing.magnifier.option.n1", "1m"), ms: 6e4 },
6464
+ { value: "5", label: msg("drawing.magnifier.option.n5", "5m"), ms: 3e5 },
6465
+ { value: "15", label: msg("drawing.magnifier.option.n15", "15m"), ms: 9e5 },
6466
+ { value: "30", label: msg("drawing.magnifier.option.n30", "30m"), ms: 18e5 },
6467
+ { value: "60", label: msg("drawing.magnifier.option.n60", "1h"), ms: 36e5 },
6468
+ { value: "240", label: msg("drawing.magnifier.option.n240", "4h"), ms: 144e5 },
6469
+ { value: "D", label: msg("drawing.magnifier.option.d", "1D"), ms: 864e5 }
5535
6470
  ];
5536
6471
  function defaultMagnifierStyle() {
5537
6472
  return { timeframe: "auto", upColor: "", downColor: "" };
@@ -5597,14 +6532,14 @@ var Magnifier = class extends Drawing {
5597
6532
  fields: [
5598
6533
  {
5599
6534
  path: "magnifier.timeframe",
5600
- label: "Timeframe",
6535
+ label: msg("drawing.magnifier.magnifierTimeframe", "Timeframe"),
5601
6536
  kind: "select",
5602
6537
  options: MAGNIFIER_TIMEFRAME_OPTIONS,
5603
6538
  group: "behavior"
5604
6539
  },
5605
- ...LINE_FIELDS.map((f) => ({ ...f, label: f.label.replace("Line", "Border") })),
5606
- { path: "magnifier.upColor", label: "Up candles", kind: "color", group: "fill" },
5607
- { path: "magnifier.downColor", label: "Down candles", kind: "color", group: "fill" }
6540
+ ...BORDER_FIELDS,
6541
+ { path: "magnifier.upColor", label: msg("drawing.magnifier.magnifierUpColor", "Up candles"), kind: "color", group: "fill" },
6542
+ { path: "magnifier.downColor", label: msg("drawing.magnifier.magnifierDownColor", "Down candles"), kind: "color", group: "fill" }
5608
6543
  ]
5609
6544
  };
5610
6545
  }
@@ -5807,10 +6742,10 @@ var PriceActionZone = class extends PriceActionTool {
5807
6742
 
5808
6743
  // src/core/drawings/types/FairValueGap.ts
5809
6744
  var EXTEND_OPTIONS = [
5810
- { value: "tested", label: "Until tested" },
5811
- { value: "half", label: "Until 50%" },
5812
- { value: "filled", label: "Until filled" },
5813
- { value: "always", label: "Always" }
6745
+ { value: "tested", label: msg("drawing.fairvaluegap.option.tested", "Until tested") },
6746
+ { value: "half", label: msg("drawing.fairvaluegap.option.half", "Until 50%") },
6747
+ { value: "filled", label: msg("drawing.fairvaluegap.option.filled", "Until filled") },
6748
+ { value: "always", label: msg("drawing.fairvaluegap.option.always", "Always") }
5814
6749
  ];
5815
6750
  function defaults2() {
5816
6751
  return { extend: "filled", upColor: `${BULLISH}33`, downColor: `${BEARISH}33`, midline: true, border: false, fade: true, inverse: false };
@@ -5834,13 +6769,13 @@ var FairValueGap = class extends PriceActionZone {
5834
6769
  schema() {
5835
6770
  return {
5836
6771
  fields: [
5837
- { path: "gap.extend", label: "Extend right", kind: "select", options: EXTEND_OPTIONS, group: "behavior" },
5838
- { path: "gap.upColor", label: "Bullish", kind: "color", group: "fill" },
5839
- { path: "gap.downColor", label: "Bearish", kind: "color", group: "fill" },
5840
- { path: "gap.midline", label: "Midline", kind: "boolean", group: "line" },
5841
- { path: "gap.border", label: "Border", kind: "boolean", group: "line" },
5842
- { path: "gap.fade", label: "Fade at end", kind: "boolean", group: "behavior", when: { path: "gap.extend", in: ["tested", "half", "filled"] } },
5843
- { path: "gap.inverse", label: "Flip on close", kind: "boolean", group: "behavior", when: { path: "gap.extend", in: ["filled"] } }
6772
+ { path: "gap.extend", label: msg("drawing.fairvaluegap.gapExtend", "Extend right"), kind: "select", options: EXTEND_OPTIONS, group: "behavior" },
6773
+ { path: "gap.upColor", label: msg("drawing.fairvaluegap.gapUpColor", "Bullish"), kind: "color", group: "fill" },
6774
+ { path: "gap.downColor", label: msg("drawing.fairvaluegap.gapDownColor", "Bearish"), kind: "color", group: "fill" },
6775
+ { path: "gap.midline", label: msg("drawing.fairvaluegap.gapMidline", "Midline"), kind: "boolean", group: "line" },
6776
+ { path: "gap.border", label: msg("drawing.fairvaluegap.gapBorder", "Border"), kind: "boolean", group: "line" },
6777
+ { path: "gap.fade", label: msg("drawing.fairvaluegap.gapFade", "Fade at end"), kind: "boolean", group: "behavior", when: { path: "gap.extend", in: ["tested", "half", "filled"] } },
6778
+ { path: "gap.inverse", label: msg("drawing.fairvaluegap.gapInverse", "Flip on close"), kind: "boolean", group: "behavior", when: { path: "gap.extend", in: ["filled"] } }
5844
6779
  ]
5845
6780
  };
5846
6781
  }
@@ -5864,14 +6799,14 @@ var FairValueGap = class extends PriceActionZone {
5864
6799
 
5865
6800
  // src/core/drawings/types/OrderBlock.ts
5866
6801
  var RANGE_OPTIONS = [
5867
- { value: "body", label: "Body" },
5868
- { value: "wick", label: "Full range" }
6802
+ { value: "body", label: msg("drawing.orderblock.option.body", "Body") },
6803
+ { value: "wick", label: msg("drawing.orderblock.option.wick", "Full range") }
5869
6804
  ];
5870
6805
  var EXTEND_OPTIONS2 = [
5871
- { value: "tested", label: "Until tested" },
5872
- { value: "half", label: "Until 50%" },
5873
- { value: "broken", label: "Until broken" },
5874
- { value: "always", label: "Always" }
6806
+ { value: "tested", label: msg("drawing.orderblock.option.tested", "Until tested") },
6807
+ { value: "half", label: msg("drawing.orderblock.option.half", "Until 50%") },
6808
+ { value: "broken", label: msg("drawing.orderblock.option.broken", "Until broken") },
6809
+ { value: "always", label: msg("drawing.orderblock.option.always", "Always") }
5875
6810
  ];
5876
6811
  function defaults3() {
5877
6812
  return { range: "body", extend: "broken", upColor: `${BULLISH}29`, downColor: `${BEARISH}29`, midline: true, border: true, fade: true, breaker: true };
@@ -5895,14 +6830,14 @@ var OrderBlock = class extends PriceActionZone {
5895
6830
  schema() {
5896
6831
  return {
5897
6832
  fields: [
5898
- { path: "block.range", label: "Zone", kind: "select", options: RANGE_OPTIONS, group: "behavior" },
5899
- { path: "block.extend", label: "Extend right", kind: "select", options: EXTEND_OPTIONS2, group: "behavior" },
5900
- { path: "block.upColor", label: "Bullish", kind: "color", group: "fill" },
5901
- { path: "block.downColor", label: "Bearish", kind: "color", group: "fill" },
5902
- { path: "block.midline", label: "Midline", kind: "boolean", group: "line" },
5903
- { path: "block.border", label: "Border", kind: "boolean", group: "line" },
5904
- { path: "block.fade", label: "Fade at end", kind: "boolean", group: "behavior", when: { path: "block.extend", in: ["tested", "half", "broken"] } },
5905
- { path: "block.breaker", label: "Breaker", kind: "boolean", group: "behavior", when: { path: "block.extend", in: ["broken"] } }
6833
+ { path: "block.range", label: msg("drawing.orderblock.blockRange", "Zone"), kind: "select", options: RANGE_OPTIONS, group: "behavior" },
6834
+ { path: "block.extend", label: msg("drawing.orderblock.blockExtend", "Extend right"), kind: "select", options: EXTEND_OPTIONS2, group: "behavior" },
6835
+ { path: "block.upColor", label: msg("drawing.orderblock.blockUpColor", "Bullish"), kind: "color", group: "fill" },
6836
+ { path: "block.downColor", label: msg("drawing.orderblock.blockDownColor", "Bearish"), kind: "color", group: "fill" },
6837
+ { path: "block.midline", label: msg("drawing.orderblock.blockMidline", "Midline"), kind: "boolean", group: "line" },
6838
+ { path: "block.border", label: msg("drawing.orderblock.blockBorder", "Border"), kind: "boolean", group: "line" },
6839
+ { path: "block.fade", label: msg("drawing.orderblock.blockFade", "Fade at end"), kind: "boolean", group: "behavior", when: { path: "block.extend", in: ["tested", "half", "broken"] } },
6840
+ { path: "block.breaker", label: msg("drawing.orderblock.blockBreaker", "Breaker"), kind: "boolean", group: "behavior", when: { path: "block.extend", in: ["broken"] } }
5906
6841
  ]
5907
6842
  };
5908
6843
  }
@@ -5927,9 +6862,9 @@ var OrderBlock = class extends PriceActionZone {
5927
6862
 
5928
6863
  // src/core/drawings/types/Liquidity.ts
5929
6864
  var EXTEND_OPTIONS3 = [
5930
- { value: "swept", label: "Until swept" },
5931
- { value: "broken", label: "Until broken" },
5932
- { value: "always", label: "Always" }
6865
+ { value: "swept", label: msg("drawing.liquidity.option.swept", "Until swept") },
6866
+ { value: "broken", label: msg("drawing.liquidity.option.broken", "Until broken") },
6867
+ { value: "always", label: msg("drawing.liquidity.option.always", "Always") }
5933
6868
  ];
5934
6869
  function defaults4() {
5935
6870
  return { extend: "swept", markSweep: true };
@@ -5985,8 +6920,8 @@ var Liquidity = class extends PriceActionTool {
5985
6920
  return {
5986
6921
  fields: [
5987
6922
  ...LINE_FIELDS,
5988
- { path: "liq.extend", label: "Extend right", kind: "select", options: EXTEND_OPTIONS3, group: "behavior" },
5989
- { path: "liq.markSweep", label: "Mark sweep", kind: "boolean", group: "behavior" }
6923
+ { path: "liq.extend", label: msg("drawing.liquidity.liqExtend", "Extend right"), kind: "select", options: EXTEND_OPTIONS3, group: "behavior" },
6924
+ { path: "liq.markSweep", label: msg("drawing.liquidity.liqMarkSweep", "Mark sweep"), kind: "boolean", group: "behavior" }
5990
6925
  ]
5991
6926
  };
5992
6927
  }
@@ -6008,18 +6943,26 @@ var REGISTRY2 = /* @__PURE__ */ new Map();
6008
6943
  function registerDrawingType(meta) {
6009
6944
  REGISTRY2.set(meta.type, meta);
6010
6945
  }
6011
- function getDrawingType(type) {
6012
- return REGISTRY2.get(type);
6946
+ function resolved2(meta, i18n) {
6947
+ if (typeof meta.label === "string" && (meta.placementHint === void 0 || typeof meta.placementHint === "string")) return meta;
6948
+ const out = { ...meta, label: textOf(i18n, meta.label), placementHint: void 0 };
6949
+ if (meta.placementHint !== void 0) out.placementHint = textOf(i18n, meta.placementHint);
6950
+ else delete out.placementHint;
6951
+ return out;
6952
+ }
6953
+ function getDrawingType(type, i18n) {
6954
+ const meta = REGISTRY2.get(type);
6955
+ return meta ? resolved2(meta, i18n) : void 0;
6013
6956
  }
6014
- function drawingTypes() {
6015
- return [...REGISTRY2.values()];
6957
+ function drawingTypes(i18n) {
6958
+ return [...REGISTRY2.values()].map((meta) => resolved2(meta, i18n));
6016
6959
  }
6017
6960
  var LINE_ICON = svg24('<line x1="4" y1="19" x2="20" y2="5"/>');
6018
6961
  var HLINE_ICON = svg24('<line x1="3" y1="12" x2="21" y2="12"/>');
6019
6962
  registerDrawingType({
6020
6963
  type: "trendline",
6021
6964
  group: "lines",
6022
- label: "Trend Line",
6965
+ label: msg("drawing.trendline.label", "Trend Line"),
6023
6966
  icon: LINE_ICON,
6024
6967
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6025
6968
  create: (init) => new TrendLine(init)
@@ -6027,7 +6970,7 @@ registerDrawingType({
6027
6970
  registerDrawingType({
6028
6971
  type: "hline",
6029
6972
  group: "lines",
6030
- label: "Horizontal Line",
6973
+ label: msg("drawing.hline.label", "Horizontal Line"),
6031
6974
  icon: HLINE_ICON,
6032
6975
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "dashed" },
6033
6976
  create: (init) => new HorizontalLine(init)
@@ -6038,7 +6981,7 @@ var TEXT_ICON = svg24('<path d="M5 6h14M12 6v13"/>');
6038
6981
  registerDrawingType({
6039
6982
  type: "ray",
6040
6983
  group: "lines",
6041
- label: "Ray",
6984
+ label: msg("drawing.ray.label", "Ray"),
6042
6985
  icon: RAY_ICON,
6043
6986
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6044
6987
  create: (init) => new Ray(init)
@@ -6052,7 +6995,7 @@ var TRENDANGLE_ICON = svg24('<path d="M4 20 20 6"/><path d="M4 20 15 20"/><path
6052
6995
  registerDrawingType({
6053
6996
  type: "extendedline",
6054
6997
  group: "lines",
6055
- label: "Extended Line",
6998
+ label: msg("drawing.extendedline.label", "Extended Line"),
6056
6999
  icon: EXTLINE_ICON,
6057
7000
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6058
7001
  create: (init) => new ExtendedLine(init)
@@ -6060,7 +7003,7 @@ registerDrawingType({
6060
7003
  registerDrawingType({
6061
7004
  type: "vline",
6062
7005
  group: "lines",
6063
- label: "Vertical Line",
7006
+ label: msg("drawing.vline.label", "Vertical Line"),
6064
7007
  icon: VLINE_ICON,
6065
7008
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6066
7009
  create: (init) => new VerticalLine(init)
@@ -6068,7 +7011,7 @@ registerDrawingType({
6068
7011
  registerDrawingType({
6069
7012
  type: "hray",
6070
7013
  group: "lines",
6071
- label: "Horizontal Ray",
7014
+ label: msg("drawing.hray.label", "Horizontal Ray"),
6072
7015
  icon: HRAY_ICON,
6073
7016
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6074
7017
  create: (init) => new HorizontalRay(init)
@@ -6076,7 +7019,7 @@ registerDrawingType({
6076
7019
  registerDrawingType({
6077
7020
  type: "crossline",
6078
7021
  group: "lines",
6079
- label: "Cross Line",
7022
+ label: msg("drawing.crossline.label", "Cross Line"),
6080
7023
  icon: CROSSLINE_ICON,
6081
7024
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6082
7025
  create: (init) => new CrossLine(init)
@@ -6084,7 +7027,7 @@ registerDrawingType({
6084
7027
  registerDrawingType({
6085
7028
  type: "infoline",
6086
7029
  group: "lines",
6087
- label: "Info Line",
7030
+ label: msg("drawing.infoline.label", "Info Line"),
6088
7031
  icon: INFOLINE_ICON,
6089
7032
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6090
7033
  create: (init) => new InfoLine(init)
@@ -6092,7 +7035,7 @@ registerDrawingType({
6092
7035
  registerDrawingType({
6093
7036
  type: "trendangle",
6094
7037
  group: "lines",
6095
- label: "Trend Angle",
7038
+ label: msg("drawing.trendangle.label", "Trend Angle"),
6096
7039
  icon: TRENDANGLE_ICON,
6097
7040
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6098
7041
  create: (init) => new TrendAngle(init)
@@ -6100,7 +7043,7 @@ registerDrawingType({
6100
7043
  registerDrawingType({
6101
7044
  type: "box",
6102
7045
  group: "shapes",
6103
- label: "Rectangle",
7046
+ label: msg("drawing.box.label", "Rectangle"),
6104
7047
  icon: BOX_ICON,
6105
7048
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}26` },
6106
7049
  create: (init) => new Box(init)
@@ -6108,7 +7051,7 @@ registerDrawingType({
6108
7051
  registerDrawingType({
6109
7052
  type: "text",
6110
7053
  group: "annotations",
6111
- label: "Text",
7054
+ label: msg("drawing.text.label", "Text"),
6112
7055
  icon: TEXT_ICON,
6113
7056
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6114
7057
  create: (init) => new TextLabel(init)
@@ -6117,7 +7060,7 @@ var CALLOUT_ICON = svg24('<path d="M5 4h14a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-6l-5 5
6117
7060
  registerDrawingType({
6118
7061
  type: "callout",
6119
7062
  group: "annotations",
6120
- label: "Callout",
7063
+ label: msg("drawing.callout.label", "Callout"),
6121
7064
  icon: CALLOUT_ICON,
6122
7065
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}d9` },
6123
7066
  create: (init) => new Callout(init)
@@ -6130,7 +7073,7 @@ var SIGNPOST_ICON = svg24('<path d="M12 11.5V21"/><rect x="5" y="4" width="14" h
6130
7073
  registerDrawingType({
6131
7074
  type: "note",
6132
7075
  group: "annotations",
6133
- label: "Note",
7076
+ label: msg("drawing.note.label", "Note"),
6134
7077
  icon: NOTE_ICON,
6135
7078
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}d9` },
6136
7079
  create: (init) => new Note(init)
@@ -6138,7 +7081,7 @@ registerDrawingType({
6138
7081
  registerDrawingType({
6139
7082
  type: "pricenote",
6140
7083
  group: "annotations",
6141
- label: "Price Note",
7084
+ label: msg("drawing.pricenote.label", "Price Note"),
6142
7085
  icon: PRICE_NOTE_ICON,
6143
7086
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}d9` },
6144
7087
  create: (init) => new PriceNote(init)
@@ -6146,7 +7089,7 @@ registerDrawingType({
6146
7089
  registerDrawingType({
6147
7090
  type: "comment",
6148
7091
  group: "annotations",
6149
- label: "Comment",
7092
+ label: msg("drawing.comment.label", "Comment"),
6150
7093
  icon: COMMENT_ICON,
6151
7094
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}d9` },
6152
7095
  create: (init) => new Comment(init)
@@ -6154,7 +7097,7 @@ registerDrawingType({
6154
7097
  registerDrawingType({
6155
7098
  type: "pricelabel",
6156
7099
  group: "annotations",
6157
- label: "Price Label",
7100
+ label: msg("drawing.pricelabel.label", "Price Label"),
6158
7101
  icon: PRICE_LABEL_ICON,
6159
7102
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}d9` },
6160
7103
  create: (init) => new PriceLabel(init)
@@ -6162,7 +7105,7 @@ registerDrawingType({
6162
7105
  registerDrawingType({
6163
7106
  type: "signpost",
6164
7107
  group: "annotations",
6165
- label: "Signpost",
7108
+ label: msg("drawing.signpost.label", "Signpost"),
6166
7109
  icon: SIGNPOST_ICON,
6167
7110
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}d9` },
6168
7111
  create: (init) => new Signpost(init)
@@ -6173,7 +7116,7 @@ var PITCHFORK_ICON = svg24('<circle cx="4" cy="12" r="1.6" fill="currentColor"/>
6173
7116
  registerDrawingType({
6174
7117
  type: "parallelchannel",
6175
7118
  group: "channels",
6176
- label: "Parallel Channel",
7119
+ label: msg("drawing.parallelchannel.label", "Parallel Channel"),
6177
7120
  icon: PARALLEL_ICON,
6178
7121
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}1a` },
6179
7122
  create: (init) => new ParallelChannel(init)
@@ -6181,7 +7124,7 @@ registerDrawingType({
6181
7124
  registerDrawingType({
6182
7125
  type: "disjointchannel",
6183
7126
  group: "channels",
6184
- label: "Disjoint Channel",
7127
+ label: msg("drawing.disjointchannel.label", "Disjoint Channel"),
6185
7128
  icon: DISJOINT_ICON,
6186
7129
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}1a` },
6187
7130
  create: (init) => new DisjointChannel(init)
@@ -6190,7 +7133,7 @@ var FLATTOP_ICON = svg24('<line x1="3" y1="7" x2="21" y2="7"/><line x1="3" y1="1
6190
7133
  registerDrawingType({
6191
7134
  type: "flattopbottom",
6192
7135
  group: "channels",
6193
- label: "Flat Top/Bottom",
7136
+ label: msg("drawing.flattopbottom.label", "Flat Top/Bottom"),
6194
7137
  icon: FLATTOP_ICON,
6195
7138
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}1a` },
6196
7139
  create: (init) => new FlatTopBottom(init)
@@ -6199,7 +7142,7 @@ var REGRESSION_ICON = svg24('<line x1="3" y1="8" x2="21" y2="4"/><line x1="3" y1
6199
7142
  registerDrawingType({
6200
7143
  type: "regressionchannel",
6201
7144
  group: "channels",
6202
- label: "Linear Regression",
7145
+ label: msg("drawing.regressionchannel.label", "Linear Regression"),
6203
7146
  icon: REGRESSION_ICON,
6204
7147
  defaultStyle: { lineColor: NEUTRAL, lineWidth: 1, lineStyle: "solid" },
6205
7148
  create: (init) => new RegressionChannel(init)
@@ -6207,7 +7150,7 @@ registerDrawingType({
6207
7150
  registerDrawingType({
6208
7151
  type: "pitchfork",
6209
7152
  group: "pitchforks",
6210
- label: "Pitchfork",
7153
+ label: msg("drawing.pitchfork.label", "Pitchfork"),
6211
7154
  icon: PITCHFORK_ICON,
6212
7155
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6213
7156
  create: (init) => new Pitchfork(init)
@@ -6218,7 +7161,7 @@ var INSIDE_ICON = svg24('<line x1="4" y1="12" x2="10" y2="12"/><line x1="10" y1=
6218
7161
  registerDrawingType({
6219
7162
  type: "schiffpitchfork",
6220
7163
  group: "pitchforks",
6221
- label: "Schiff Pitchfork",
7164
+ label: msg("drawing.schiffpitchfork.label", "Schiff Pitchfork"),
6222
7165
  icon: SCHIFF_ICON,
6223
7166
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6224
7167
  create: (init) => new SchiffPitchfork(init)
@@ -6226,7 +7169,7 @@ registerDrawingType({
6226
7169
  registerDrawingType({
6227
7170
  type: "modifiedschiffpitchfork",
6228
7171
  group: "pitchforks",
6229
- label: "Modified Schiff Pitchfork",
7172
+ label: msg("drawing.modifiedschiffpitchfork.label", "Modified Schiff Pitchfork"),
6230
7173
  icon: MODSCHIFF_ICON,
6231
7174
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6232
7175
  create: (init) => new ModifiedSchiffPitchfork(init)
@@ -6234,7 +7177,7 @@ registerDrawingType({
6234
7177
  registerDrawingType({
6235
7178
  type: "insidepitchfork",
6236
7179
  group: "pitchforks",
6237
- label: "Inside Pitchfork",
7180
+ label: msg("drawing.insidepitchfork.label", "Inside Pitchfork"),
6238
7181
  icon: INSIDE_ICON,
6239
7182
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6240
7183
  create: (init) => new InsidePitchfork(init)
@@ -6245,7 +7188,7 @@ var TRIANGLE_ICON = svg24('<path d="M12 4 20 19 4 19Z"/>');
6245
7188
  registerDrawingType({
6246
7189
  type: "arrow",
6247
7190
  group: "shapes",
6248
- label: "Arrow",
7191
+ label: msg("drawing.arrow.label", "Arrow"),
6249
7192
  icon: ARROW_ICON,
6250
7193
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", arrowRight: true },
6251
7194
  create: (init) => new Arrow(init)
@@ -6253,7 +7196,7 @@ registerDrawingType({
6253
7196
  registerDrawingType({
6254
7197
  type: "ellipse",
6255
7198
  group: "shapes",
6256
- label: "Ellipse",
7199
+ label: msg("drawing.ellipse.label", "Ellipse"),
6257
7200
  icon: ELLIPSE_ICON,
6258
7201
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}1a` },
6259
7202
  create: (init) => new Ellipse(init)
@@ -6261,7 +7204,7 @@ registerDrawingType({
6261
7204
  registerDrawingType({
6262
7205
  type: "triangle",
6263
7206
  group: "shapes",
6264
- label: "Triangle",
7207
+ label: msg("drawing.triangle.label", "Triangle"),
6265
7208
  icon: TRIANGLE_ICON,
6266
7209
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}1a` },
6267
7210
  create: (init) => new Triangle(init)
@@ -6272,7 +7215,7 @@ var HIGHLIGHTER_ICON = svg24('<path d="M9 11 15 5l4 4-6 6H9Z"/><path d="M9 15l-2
6272
7215
  registerDrawingType({
6273
7216
  type: "polyline",
6274
7217
  group: "shapes",
6275
- label: "Polyline",
7218
+ label: msg("drawing.polyline.label", "Polyline"),
6276
7219
  icon: POLYLINE_ICON,
6277
7220
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6278
7221
  create: (init) => new Polyline(init)
@@ -6280,7 +7223,7 @@ registerDrawingType({
6280
7223
  registerDrawingType({
6281
7224
  type: "freehand",
6282
7225
  group: "shapes",
6283
- label: "Brush",
7226
+ label: msg("drawing.freehand.label", "Brush"),
6284
7227
  icon: FREEHAND_ICON,
6285
7228
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6286
7229
  create: (init) => new Freehand(init)
@@ -6288,7 +7231,7 @@ registerDrawingType({
6288
7231
  registerDrawingType({
6289
7232
  type: "highlighter",
6290
7233
  group: "shapes",
6291
- label: "Highlighter",
7234
+ label: msg("drawing.highlighter.label", "Highlighter"),
6292
7235
  icon: HIGHLIGHTER_ICON,
6293
7236
  // A marker: wide + translucent by default (the alpha in the color is the highlight's see-through).
6294
7237
  defaultStyle: { lineColor: `${MARKER}59`, lineWidth: 14, lineStyle: "solid" },
@@ -6304,7 +7247,7 @@ var ARROW_DOWN_ICON = svg24('<path d="M12 5 12 19"/><path d="M6 13 12 19 18 13"/
6304
7247
  registerDrawingType({
6305
7248
  type: "circle",
6306
7249
  group: "shapes",
6307
- label: "Circle",
7250
+ label: msg("drawing.circle.label", "Circle"),
6308
7251
  icon: CIRCLE_ICON,
6309
7252
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}1a` },
6310
7253
  create: (init) => new Circle(init)
@@ -6312,7 +7255,7 @@ registerDrawingType({
6312
7255
  registerDrawingType({
6313
7256
  type: "rotatedrect",
6314
7257
  group: "shapes",
6315
- label: "Rotated Rectangle",
7258
+ label: msg("drawing.rotatedrect.label", "Rotated Rectangle"),
6316
7259
  icon: ROTRECT_ICON,
6317
7260
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}26` },
6318
7261
  create: (init) => new RotatedRect(init)
@@ -6320,7 +7263,7 @@ registerDrawingType({
6320
7263
  registerDrawingType({
6321
7264
  type: "path",
6322
7265
  group: "shapes",
6323
- label: "Path",
7266
+ label: msg("drawing.path.label", "Path"),
6324
7267
  icon: PATH_ICON,
6325
7268
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6326
7269
  create: (init) => new Path(init)
@@ -6328,7 +7271,7 @@ registerDrawingType({
6328
7271
  registerDrawingType({
6329
7272
  type: "arc",
6330
7273
  group: "shapes",
6331
- label: "Arc",
7274
+ label: msg("drawing.arc.label", "Arc"),
6332
7275
  icon: ARC_ICON,
6333
7276
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}26` },
6334
7277
  create: (init) => new Arc(init)
@@ -6336,7 +7279,7 @@ registerDrawingType({
6336
7279
  registerDrawingType({
6337
7280
  type: "curve",
6338
7281
  group: "shapes",
6339
- label: "Curve",
7282
+ label: msg("drawing.curve.label", "Curve"),
6340
7283
  icon: CURVE_ICON,
6341
7284
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6342
7285
  create: (init) => new Curve(init)
@@ -6344,7 +7287,7 @@ registerDrawingType({
6344
7287
  registerDrawingType({
6345
7288
  type: "arrowmarkup",
6346
7289
  group: "shapes",
6347
- label: "Arrow Mark Up",
7290
+ label: msg("drawing.arrowmarkup.label", "Arrow Mark Up"),
6348
7291
  icon: ARROW_UP_ICON,
6349
7292
  defaultStyle: { lineColor: BULLISH, lineWidth: 1, lineStyle: "solid" },
6350
7293
  create: (init) => new ArrowMarkUp(init)
@@ -6352,7 +7295,7 @@ registerDrawingType({
6352
7295
  registerDrawingType({
6353
7296
  type: "arrowmarkdown",
6354
7297
  group: "shapes",
6355
- label: "Arrow Mark Down",
7298
+ label: msg("drawing.arrowmarkdown.label", "Arrow Mark Down"),
6356
7299
  icon: ARROW_DOWN_ICON,
6357
7300
  defaultStyle: { lineColor: BEARISH, lineWidth: 1, lineStyle: "solid" },
6358
7301
  create: (init) => new ArrowMarkDown(init)
@@ -6362,7 +7305,7 @@ var ICON_STAMP_ICON = svg24('<path d="m12 3 2.6 5.8 6.4.6-4.8 4.2 1.4 6.2L12 16.
6362
7305
  registerDrawingType({
6363
7306
  type: "flagmark",
6364
7307
  group: "stamps",
6365
- label: "Flag",
7308
+ label: msg("drawing.flagmark.label", "Flag"),
6366
7309
  icon: FLAG_MARK_ICON,
6367
7310
  defaultStyle: { lineColor: ACCENT, lineWidth: 1, lineStyle: "solid" },
6368
7311
  create: (init) => new FlagMark(init)
@@ -6370,7 +7313,7 @@ registerDrawingType({
6370
7313
  registerDrawingType({
6371
7314
  type: "iconstamp",
6372
7315
  group: "stamps",
6373
- label: "Icon",
7316
+ label: msg("drawing.iconstamp.label", "Icon"),
6374
7317
  icon: ICON_STAMP_ICON,
6375
7318
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6376
7319
  create: (init) => new IconStamp(init)
@@ -6380,7 +7323,7 @@ var FIB_EXTEND_ICON = svg24('<line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1
6380
7323
  registerDrawingType({
6381
7324
  type: "fibretracement",
6382
7325
  group: "fibonacci",
6383
- label: "Fib Retracement",
7326
+ label: msg("drawing.fibretracement.label", "Fib Retracement"),
6384
7327
  icon: FIB_RETRACE_ICON,
6385
7328
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6386
7329
  create: (init) => new FibRetracement(init)
@@ -6388,7 +7331,7 @@ registerDrawingType({
6388
7331
  registerDrawingType({
6389
7332
  type: "fibextension",
6390
7333
  group: "fibonacci",
6391
- label: "Fib Extension",
7334
+ label: msg("drawing.fibextension.label", "Fib Extension"),
6392
7335
  icon: FIB_EXTEND_ICON,
6393
7336
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6394
7337
  create: (init) => new FibExtension(init)
@@ -6397,7 +7340,7 @@ var FIB_TREND_ICON = svg24('<path d="M3 20 10 9l4 5"/><path d="M14 14h7M14 9h7M1
6397
7340
  registerDrawingType({
6398
7341
  type: "fibextensiontrend",
6399
7342
  group: "fibonacci",
6400
- label: "Trend-Based Fib Extension",
7343
+ label: msg("drawing.fibextensiontrend.label", "Trend-Based Fib Extension"),
6401
7344
  icon: FIB_TREND_ICON,
6402
7345
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6403
7346
  create: (init) => new FibExtensionTrend(init)
@@ -6407,7 +7350,7 @@ var FIB_TZ_ICON = svg24('<path d="M3 5v14M6 5v14M11 5v14M19 5v14"/>');
6407
7350
  registerDrawingType({
6408
7351
  type: "fibfan",
6409
7352
  group: "fibonacci",
6410
- label: "Fib Fan",
7353
+ label: msg("drawing.fibfan.label", "Fib Fan"),
6411
7354
  icon: FIB_FAN_ICON,
6412
7355
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6413
7356
  create: (init) => new FibFan(init)
@@ -6415,7 +7358,7 @@ registerDrawingType({
6415
7358
  registerDrawingType({
6416
7359
  type: "fibtimezones",
6417
7360
  group: "fibonacci",
6418
- label: "Fib Time Zones",
7361
+ label: msg("drawing.fibtimezones.label", "Fib Time Zones"),
6419
7362
  icon: FIB_TZ_ICON,
6420
7363
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "dashed" },
6421
7364
  create: (init) => new FibTimeZones(init)
@@ -6426,7 +7369,7 @@ var FIB_TRENDTIME_ICON = svg24('<path d="M3 19 9 8M9 8 12 5v14M14 5v14M18 5v14M2
6426
7369
  registerDrawingType({
6427
7370
  type: "fibchannel",
6428
7371
  group: "fibonacci",
6429
- label: "Fib Channel",
7372
+ label: msg("drawing.fibchannel.label", "Fib Channel"),
6430
7373
  icon: FIB_CHANNEL_ICON,
6431
7374
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6432
7375
  create: (init) => new FibChannel(init)
@@ -6434,7 +7377,7 @@ registerDrawingType({
6434
7377
  registerDrawingType({
6435
7378
  type: "fibspeedfan",
6436
7379
  group: "fibonacci",
6437
- label: "Fib Speed Resistance Fan",
7380
+ label: msg("drawing.fibspeedfan.label", "Fib Speed Resistance Fan"),
6438
7381
  icon: FIB_SPEEDFAN_ICON,
6439
7382
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6440
7383
  create: (init) => new FibSpeedFan(init)
@@ -6442,7 +7385,7 @@ registerDrawingType({
6442
7385
  registerDrawingType({
6443
7386
  type: "trendfibtime",
6444
7387
  group: "fibonacci",
6445
- label: "Trend-Based Fib Time",
7388
+ label: msg("drawing.trendfibtime.label", "Trend-Based Fib Time"),
6446
7389
  icon: FIB_TRENDTIME_ICON,
6447
7390
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "dashed" },
6448
7391
  create: (init) => new TrendFibTime(init)
@@ -6454,7 +7397,7 @@ var FIB_SPIRAL_ICON = svg24('<path d="M13 12a2 2 0 1 1-2-2 4 4 0 0 1 4 4 6 6 0 0
6454
7397
  registerDrawingType({
6455
7398
  type: "fibcircles",
6456
7399
  group: "fibonacci",
6457
- label: "Fib Circles",
7400
+ label: msg("drawing.fibcircles.label", "Fib Circles"),
6458
7401
  icon: FIB_CIRCLES_ICON,
6459
7402
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6460
7403
  create: (init) => new FibCircles(init)
@@ -6462,7 +7405,7 @@ registerDrawingType({
6462
7405
  registerDrawingType({
6463
7406
  type: "fibarcs",
6464
7407
  group: "fibonacci",
6465
- label: "Fib Speed Resistance Arcs",
7408
+ label: msg("drawing.fibarcs.label", "Fib Speed Resistance Arcs"),
6466
7409
  icon: FIB_ARCS_ICON,
6467
7410
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6468
7411
  create: (init) => new FibArcs(init)
@@ -6470,7 +7413,7 @@ registerDrawingType({
6470
7413
  registerDrawingType({
6471
7414
  type: "fibwedge",
6472
7415
  group: "fibonacci",
6473
- label: "Fib Wedge",
7416
+ label: msg("drawing.fibwedge.label", "Fib Wedge"),
6474
7417
  icon: FIB_WEDGE_ICON,
6475
7418
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6476
7419
  create: (init) => new FibWedge(init)
@@ -6478,7 +7421,7 @@ registerDrawingType({
6478
7421
  registerDrawingType({
6479
7422
  type: "fibspiral",
6480
7423
  group: "fibonacci",
6481
- label: "Fib Spiral",
7424
+ label: msg("drawing.fibspiral.label", "Fib Spiral"),
6482
7425
  icon: FIB_SPIRAL_ICON,
6483
7426
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6484
7427
  create: (init) => new FibSpiral(init)
@@ -6488,7 +7431,7 @@ var GANN_BOX_ICON = svg24('<rect x="4" y="4" width="16" height="16" rx="1"/><pat
6488
7431
  registerDrawingType({
6489
7432
  type: "gannfan",
6490
7433
  group: "fibonacci",
6491
- label: "Gann Fan",
7434
+ label: msg("drawing.gannfan.label", "Gann Fan"),
6492
7435
  icon: GANN_FAN_ICON,
6493
7436
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6494
7437
  create: (init) => new GannFan(init)
@@ -6496,7 +7439,7 @@ registerDrawingType({
6496
7439
  registerDrawingType({
6497
7440
  type: "gannbox",
6498
7441
  group: "fibonacci",
6499
- label: "Gann Box",
7442
+ label: msg("drawing.gannbox.label", "Gann Box"),
6500
7443
  icon: GANN_BOX_ICON,
6501
7444
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6502
7445
  create: (init) => new GannBox(init)
@@ -6505,7 +7448,7 @@ var GANN_SQUARE_ICON = svg24('<rect x="4" y="4" width="16" height="16" rx="1"/><
6505
7448
  registerDrawingType({
6506
7449
  type: "gannsquare",
6507
7450
  group: "fibonacci",
6508
- label: "Gann Square",
7451
+ label: msg("drawing.gannsquare.label", "Gann Square"),
6509
7452
  icon: GANN_SQUARE_ICON,
6510
7453
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6511
7454
  create: (init) => new GannSquare(init)
@@ -6516,7 +7459,7 @@ var DEDEKIND_ICON = svg24(
6516
7459
  registerDrawingType({
6517
7460
  type: "dedekind",
6518
7461
  group: "geometry",
6519
- label: "Dedekind Tessellation",
7462
+ label: msg("drawing.dedekind.label", "Dedekind Tessellation"),
6520
7463
  icon: DEDEKIND_ICON,
6521
7464
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6522
7465
  create: (init) => new DedekindTessellation(init)
@@ -6530,7 +7473,7 @@ var SUPERSONIC_ICON = svg24(
6530
7473
  registerDrawingType({
6531
7474
  type: "sonic",
6532
7475
  group: "geometry",
6533
- label: "Sonic",
7476
+ label: msg("drawing.sonic.label", "Sonic"),
6534
7477
  icon: SONIC_ICON,
6535
7478
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6536
7479
  create: (init) => new Sonic(init)
@@ -6538,7 +7481,7 @@ registerDrawingType({
6538
7481
  registerDrawingType({
6539
7482
  type: "supersonic",
6540
7483
  group: "geometry",
6541
- label: "Supersonic",
7484
+ label: msg("drawing.supersonic.label", "Supersonic"),
6542
7485
  icon: SUPERSONIC_ICON,
6543
7486
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6544
7487
  create: (init) => new Supersonic(init)
@@ -6552,7 +7495,7 @@ var GOLDEN_SUPERSONIC_ICON = svg24(
6552
7495
  registerDrawingType({
6553
7496
  type: "goldensonic",
6554
7497
  group: "geometry",
6555
- label: "Golden Sonic",
7498
+ label: msg("drawing.goldensonic.label", "Golden Sonic"),
6556
7499
  icon: GOLDEN_SONIC_ICON,
6557
7500
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6558
7501
  create: (init) => new GoldenSonic(init)
@@ -6560,7 +7503,7 @@ registerDrawingType({
6560
7503
  registerDrawingType({
6561
7504
  type: "goldensupersonic",
6562
7505
  group: "geometry",
6563
- label: "Golden Supersonic",
7506
+ label: msg("drawing.goldensupersonic.label", "Golden Supersonic"),
6564
7507
  icon: GOLDEN_SUPERSONIC_ICON,
6565
7508
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6566
7509
  create: (init) => new GoldenSupersonic(init)
@@ -6573,7 +7516,7 @@ var HEAD_SHOULDERS_ICON = svg24('<path d="M3 18 6 12 9 16 12 5 15 16 18 12 21 18
6573
7516
  registerDrawingType({
6574
7517
  type: "xabcd",
6575
7518
  group: "patterns",
6576
- label: "XABCD Pattern",
7519
+ label: msg("drawing.xabcd.label", "XABCD Pattern"),
6577
7520
  icon: XABCD_ICON,
6578
7521
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6579
7522
  create: (init) => new XABCD(init)
@@ -6581,7 +7524,7 @@ registerDrawingType({
6581
7524
  registerDrawingType({
6582
7525
  type: "abcd",
6583
7526
  group: "patterns",
6584
- label: "ABCD Pattern",
7527
+ label: msg("drawing.abcd.label", "ABCD Pattern"),
6585
7528
  icon: ABCD_ICON,
6586
7529
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6587
7530
  create: (init) => new ABCDPattern(init)
@@ -6589,7 +7532,7 @@ registerDrawingType({
6589
7532
  registerDrawingType({
6590
7533
  type: "elliottimpulse",
6591
7534
  group: "patterns",
6592
- label: "Elliott Impulse Wave (1-5)",
7535
+ label: msg("drawing.elliottimpulse.label", "Elliott Impulse Wave (1-5)"),
6593
7536
  icon: ELLIOTT_IMPULSE_ICON,
6594
7537
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6595
7538
  create: (init) => new ElliottImpulse(init)
@@ -6597,7 +7540,7 @@ registerDrawingType({
6597
7540
  registerDrawingType({
6598
7541
  type: "elliottcorrection",
6599
7542
  group: "patterns",
6600
- label: "Elliott Correction Wave (ABC)",
7543
+ label: msg("drawing.elliottcorrection.label", "Elliott Correction Wave (ABC)"),
6601
7544
  icon: ELLIOTT_CORRECTION_ICON,
6602
7545
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6603
7546
  create: (init) => new ElliottCorrection(init)
@@ -6605,24 +7548,24 @@ registerDrawingType({
6605
7548
  registerDrawingType({
6606
7549
  type: "headshoulders",
6607
7550
  group: "patterns",
6608
- label: "Head & Shoulders",
7551
+ label: msg("drawing.headshoulders.label", "Head & Shoulders"),
6609
7552
  icon: HEAD_SHOULDERS_ICON,
6610
7553
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6611
7554
  create: (init) => new HeadShoulders(init)
6612
7555
  });
6613
7556
  var HARMONIC_ICON = svg24('<path d="M3 17 7 6 12 14 17 5 21 16"/><path d="M3 17 21 16" opacity="0.45"/>');
6614
7557
  var harmonic = { group: "patterns", icon: HARMONIC_ICON, defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" } };
6615
- registerDrawingType({ type: "gartley", label: "Gartley", ...harmonic, create: (init) => new Gartley(init) });
6616
- registerDrawingType({ type: "bat", label: "Bat", ...harmonic, create: (init) => new Bat(init) });
6617
- registerDrawingType({ type: "butterfly", label: "Butterfly", ...harmonic, create: (init) => new Butterfly(init) });
6618
- registerDrawingType({ type: "crab", label: "Crab", ...harmonic, create: (init) => new Crab(init) });
6619
- registerDrawingType({ type: "shark", label: "Shark", ...harmonic, create: (init) => new Shark(init) });
6620
- registerDrawingType({ type: "cypher", label: "Cypher", ...harmonic, create: (init) => new Cypher(init) });
7558
+ registerDrawingType({ type: "gartley", label: msg("drawing.gartley.label", "Gartley"), ...harmonic, create: (init) => new Gartley(init) });
7559
+ registerDrawingType({ type: "bat", label: msg("drawing.bat.label", "Bat"), ...harmonic, create: (init) => new Bat(init) });
7560
+ registerDrawingType({ type: "butterfly", label: msg("drawing.butterfly.label", "Butterfly"), ...harmonic, create: (init) => new Butterfly(init) });
7561
+ registerDrawingType({ type: "crab", label: msg("drawing.crab.label", "Crab"), ...harmonic, create: (init) => new Crab(init) });
7562
+ registerDrawingType({ type: "shark", label: msg("drawing.shark.label", "Shark"), ...harmonic, create: (init) => new Shark(init) });
7563
+ registerDrawingType({ type: "cypher", label: msg("drawing.cypher.label", "Cypher"), ...harmonic, create: (init) => new Cypher(init) });
6621
7564
  var MEASURE_ICON = svg24('<rect x="4" y="6" width="16" height="12" rx="1"/><path d="M4 18 20 6" opacity="0.5"/>');
6622
7565
  registerDrawingType({
6623
7566
  type: "datepricerange",
6624
7567
  group: "measure",
6625
- label: "Date & Price Range",
7568
+ label: msg("drawing.datepricerange.label", "Date & Price Range"),
6626
7569
  icon: MEASURE_ICON,
6627
7570
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6628
7571
  create: (init) => new DatePriceRange(init)
@@ -6633,7 +7576,7 @@ var POSITION_ICON = svg24(
6633
7576
  registerDrawingType({
6634
7577
  type: "position",
6635
7578
  group: "measure",
6636
- label: "Long/Short Position",
7579
+ label: msg("drawing.position.label", "Long/Short Position"),
6637
7580
  icon: POSITION_ICON,
6638
7581
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6639
7582
  create: (init) => new PositionTool(init)
@@ -6644,21 +7587,21 @@ var MAGNIFIER_ICON = svg24(
6644
7587
  registerDrawingType({
6645
7588
  type: "magnifier",
6646
7589
  group: "measure",
6647
- label: "Magnifier",
7590
+ label: msg("drawing.magnifier.label", "Magnifier"),
6648
7591
  icon: MAGNIFIER_ICON,
6649
7592
  // An empty border color means the THEME's contrast ink (white on dark, black on
6650
7593
  // light), resolved at paint time so it follows theme switches; a user pick wins.
6651
7594
  defaultStyle: { lineColor: "", lineWidth: 1, lineStyle: "solid" },
6652
7595
  coversSeries: true,
6653
7596
  // the inset's backdrop must sit over the base candles it replaces
6654
- placementHint: "Drag an area on the chart to view it at a lower timeframe",
7597
+ placementHint: msg("drawing.magnifier.placementHint", "Drag an area on the chart to view it at a lower timeframe"),
6655
7598
  create: (init) => new Magnifier(init)
6656
7599
  });
6657
7600
  var VWAP_ICON = svg24('<line x1="5" y1="3" x2="5" y2="21"/><path d="M5 16c4 0 5-9 8-9s3 5 8 3"/>');
6658
7601
  registerDrawingType({
6659
7602
  type: "anchoredvwap",
6660
7603
  group: "measure",
6661
- label: "Anchored VWAP",
7604
+ label: msg("drawing.anchoredvwap.label", "Anchored VWAP"),
6662
7605
  icon: VWAP_ICON,
6663
7606
  defaultStyle: { lineColor: INFO, lineWidth: 2, lineStyle: "solid" },
6664
7607
  create: (init) => new AnchoredVwap(init)
@@ -6667,7 +7610,7 @@ var FRVP_ICON = svg24('<path d="M4 4v16"/><path d="M4 8h10"/><path d="M4 12h14"/
6667
7610
  registerDrawingType({
6668
7611
  type: "fixedrangevp",
6669
7612
  group: "measure",
6670
- label: "Fixed Range Volume Profile",
7613
+ label: msg("drawing.fixedrangevp.label", "Fixed Range Volume Profile"),
6671
7614
  icon: FRVP_ICON,
6672
7615
  defaultStyle: { lineColor: BULLISH, lineWidth: 1, lineStyle: "solid" },
6673
7616
  create: (init) => new FixedRangeVolumeProfile(init)
@@ -6678,28 +7621,28 @@ var LIQUIDITY_ICON = svg24('<path d="M3 8h12" stroke-dasharray="2.5 2.5"/><path
6678
7621
  registerDrawingType({
6679
7622
  type: "fairvaluegap",
6680
7623
  group: "priceaction",
6681
- label: "Fair Value Gap",
7624
+ label: msg("drawing.fairvaluegap.label", "Fair Value Gap"),
6682
7625
  icon: FVG_ICON,
6683
7626
  defaultStyle: { lineColor: BULLISH, lineWidth: 1, lineStyle: "solid" },
6684
- placementHint: "Click the middle candle of a gap",
7627
+ placementHint: msg("drawing.fairvaluegap.placementHint", "Click the middle candle of a gap"),
6685
7628
  create: (init) => new FairValueGap(init)
6686
7629
  });
6687
7630
  registerDrawingType({
6688
7631
  type: "orderblock",
6689
7632
  group: "priceaction",
6690
- label: "Order Block",
7633
+ label: msg("drawing.orderblock.label", "Order Block"),
6691
7634
  icon: ORDER_BLOCK_ICON,
6692
7635
  defaultStyle: { lineColor: BULLISH, lineWidth: 1, lineStyle: "solid" },
6693
- placementHint: "Click the candle that forms the block",
7636
+ placementHint: msg("drawing.orderblock.placementHint", "Click the candle that forms the block"),
6694
7637
  create: (init) => new OrderBlock(init)
6695
7638
  });
6696
7639
  registerDrawingType({
6697
7640
  type: "liquidity",
6698
7641
  group: "priceaction",
6699
- label: "Liquidity",
7642
+ label: msg("drawing.liquidity.label", "Liquidity"),
6700
7643
  icon: LIQUIDITY_ICON,
6701
7644
  defaultStyle: { lineColor: WARNING, lineWidth: 1, lineStyle: "solid" },
6702
- placementHint: "Click near a candle's high or low",
7645
+ placementHint: msg("drawing.liquidity.placementHint", "Click near a candle's high or low"),
6703
7646
  create: (init) => new Liquidity(init)
6704
7647
  });
6705
7648
 
@@ -6765,6 +7708,7 @@ exports.categoricalColor = categoricalColor;
6765
7708
  exports.chartType = chartType;
6766
7709
  exports.chartTypes = chartTypes;
6767
7710
  exports.clampPanelWidth = clampPanelWidth;
7711
+ exports.createTranslator = createTranslator;
6768
7712
  exports.drawingTypes = drawingTypes;
6769
7713
  exports.getDrawingType = getDrawingType;
6770
7714
  exports.getNativeIndicator = getNativeIndicator;
@@ -6773,6 +7717,7 @@ exports.inputDeltas = inputDeltas;
6773
7717
  exports.inputVisible = inputVisible;
6774
7718
  exports.legendActions = legendActions;
6775
7719
  exports.legendCallouts = legendCallouts;
7720
+ exports.msg = msg;
6776
7721
  exports.nativeIndicatorTypes = nativeIndicatorTypes;
6777
7722
  exports.normalizeSettingsRow = normalizeSettingsRow;
6778
7723
  exports.registerChartType = registerChartType;
@@ -6780,6 +7725,7 @@ exports.registerDefaultEngine = registerDefaultEngine;
6780
7725
  exports.registerIcon = registerIcon;
6781
7726
  exports.registerLegendAction = registerLegendAction;
6782
7727
  exports.registerLegendCallout = registerLegendCallout;
7728
+ exports.registerLocale = registerLocale;
6783
7729
  exports.registerNativeIndicator = registerNativeIndicator;
6784
7730
  exports.registerRendererDefaults = registerRendererDefaults;
6785
7731
  exports.registerRendererLayer = registerRendererLayer;
@@ -6788,6 +7734,7 @@ exports.registerStatePersistence = registerStatePersistence;
6788
7734
  exports.registerSymbolRanking = registerSymbolRanking;
6789
7735
  exports.registerWidgetAction = registerWidgetAction;
6790
7736
  exports.registerWidgetAttachment = registerWidgetAttachment;
7737
+ exports.registeredLocales = registeredLocales;
6791
7738
  exports.rendererDefaults = rendererDefaults;
6792
7739
  exports.rendererLayers = rendererLayers;
6793
7740
  exports.resolveEngines = resolveEngines;
@@ -6813,3 +7760,4 @@ exports.unregisterWidgetAction = unregisterWidgetAction;
6813
7760
  exports.unregisterWidgetAttachment = unregisterWidgetAttachment;
6814
7761
  exports.widgetActions = widgetActions;
6815
7762
  exports.widgetAttachments = widgetAttachments;
7763
+ exports.withValues = withValues;