@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
@@ -1,4 +1,4 @@
1
- import { svg24, NEUTRAL, BEARISH, WARNING, BULLISH, INFO, ACCENT_BRIGHT, VALID, INVALID, MARKER, ACCENT, injectStyles, iconEl, announceSurface, holdForExit } from './chunk-I2U4NZD2.js';
1
+ import { msg, svg24, sourceText, NEUTRAL, BEARISH, WARNING, BULLISH, INFO, ACCENT_BRIGHT, textOf, localizeNumberText, englishTranslator, VALID, INVALID, MARKER, ACCENT, withValues, injectStyles, iconEl, announceSurface, holdForExit } from './chunk-O6L27KRB.js';
2
2
 
3
3
  // src/core/model/series.ts
4
4
  function isLineLikeSeries(spec) {
@@ -23,13 +23,26 @@ function registerNativeIndicator(descriptor) {
23
23
  function unregisterNativeIndicator(type) {
24
24
  REGISTRY.delete(type);
25
25
  }
26
- function getNativeIndicator(type) {
27
- return REGISTRY.get(type);
26
+ function resolved(d, i18n) {
27
+ if (typeof d.title === "string" && (d.shortTitle === void 0 || typeof d.shortTitle === "string")) return d;
28
+ const names = { title: textOf(i18n, d.title) };
29
+ if (d.shortTitle !== void 0) names.shortTitle = textOf(i18n, d.shortTitle);
30
+ return Object.assign(Object.create(d), names);
31
+ }
32
+ function getNativeIndicator(type, i18n) {
33
+ const d = REGISTRY.get(type);
34
+ return d ? resolved(d, i18n) : void 0;
28
35
  }
29
36
  function nativeIndicatorTypes() {
30
37
  return [...REGISTRY.keys()];
31
38
  }
32
- function nativeIndicatorDescriptors() {
39
+ function nativeIndicatorDescriptors(i18n) {
40
+ return [...REGISTRY.values()].map((d) => resolved(d, i18n));
41
+ }
42
+ function nativeIndicatorEntry(type) {
43
+ return REGISTRY.get(type);
44
+ }
45
+ function nativeIndicatorEntries() {
33
46
  return [...REGISTRY.values()];
34
47
  }
35
48
 
@@ -47,15 +60,15 @@ var MIN = 6e4;
47
60
  var HOUR = 60 * MIN;
48
61
  var DAY = 24 * HOUR;
49
62
  var TIMEFRAME_BANDS = [
50
- { key: "s", label: "Sec", fromMs: 0 },
51
- { key: "1", label: "1m", fromMs: MIN },
52
- { key: "5", label: "5m", fromMs: 5 * MIN },
53
- { key: "15", label: "15m", fromMs: 15 * MIN },
54
- { key: "60", label: "1H", fromMs: HOUR },
55
- { key: "240", label: "4H", fromMs: 4 * HOUR },
56
- { key: "D", label: "D", fromMs: DAY },
57
- { key: "W", label: "W", fromMs: 7 * DAY },
58
- { key: "M", label: "M", fromMs: 28 * DAY }
63
+ { key: "s", label: msg("drawing.showOn.seconds", "Sec"), fromMs: 0 },
64
+ { key: "1", label: msg("drawing.showOn.minute1", "1m"), fromMs: MIN },
65
+ { key: "5", label: msg("drawing.showOn.minute5", "5m"), fromMs: 5 * MIN },
66
+ { key: "15", label: msg("drawing.showOn.minute15", "15m"), fromMs: 15 * MIN },
67
+ { key: "60", label: msg("drawing.showOn.hour1", "1H"), fromMs: HOUR },
68
+ { key: "240", label: msg("drawing.showOn.hour4", "4H"), fromMs: 4 * HOUR },
69
+ { key: "D", label: msg("drawing.showOn.day", "D"), fromMs: DAY },
70
+ { key: "W", label: msg("drawing.showOn.week", "W"), fromMs: 7 * DAY },
71
+ { key: "M", label: msg("drawing.showOn.month", "M"), fromMs: 28 * DAY }
59
72
  ];
60
73
  var BAND_KEYS = new Set(TIMEFRAME_BANDS.map((b) => b.key));
61
74
  function timeframeBandOf(barMs) {
@@ -146,6 +159,12 @@ var _Drawing = class _Drawing {
146
159
  }
147
160
  return { min: lo, max: hi };
148
161
  }
162
+ /** The text a fresh drawing of this type starts with ("Note", "Callout"), as a message,
163
+ * or null for a type that seeds none. A new drawing stores its English source; the chart
164
+ * that places one interactively writes it in its own language instead. */
165
+ placeholderText() {
166
+ return null;
167
+ }
149
168
  /**
150
169
  * Editable per-level config for a rich "gear" settings panel (Fibonacci levels):
151
170
  * each entry's `color` / `enabled` / `label` is mutated via a `levels.<i>.<field>`
@@ -212,28 +231,33 @@ function setByPath(obj, path, value) {
212
231
 
213
232
  // src/core/drawings/schema.ts
214
233
  var LINE_STYLE_OPTIONS = [
215
- { value: "solid", label: "Solid" },
216
- { value: "dashed", label: "Dashed" },
217
- { value: "dotted", label: "Dotted" }
234
+ { value: "solid", label: msg("drawing.option.solid", "Solid") },
235
+ { value: "dashed", label: msg("drawing.option.dashed", "Dashed") },
236
+ { value: "dotted", label: msg("drawing.option.dotted", "Dotted") }
218
237
  ];
219
238
  var LINE_FIELDS = [
220
- { path: "style.lineColor", label: "Line color", kind: "color", group: "line" },
221
- { path: "style.lineWidth", label: "Line width", kind: "number", min: 1, max: 10, step: 1, group: "line" },
222
- { path: "style.lineStyle", label: "Line style", kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" }
239
+ { path: "style.lineColor", label: msg("drawing.field.lineColor", "Line color"), kind: "color", group: "line" },
240
+ { path: "style.lineWidth", label: msg("drawing.field.lineWidth", "Line width"), kind: "number", min: 1, max: 10, step: 1, group: "line" },
241
+ { path: "style.lineStyle", label: msg("drawing.field.lineStyle", "Line style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" }
242
+ ];
243
+ var BORDER_FIELDS = [
244
+ { path: "style.lineColor", label: msg("drawing.field.borderColor", "Border color"), kind: "color", group: "line" },
245
+ { path: "style.lineWidth", label: msg("drawing.field.borderWidth", "Border width"), kind: "number", min: 1, max: 10, step: 1, group: "line" },
246
+ { path: "style.lineStyle", label: msg("drawing.field.borderStyle", "Border style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" }
223
247
  ];
224
- var FILL_FIELDS = [{ path: "style.fillColor", label: "Fill color", kind: "color", group: "fill" }];
248
+ var FILL_FIELDS = [{ path: "style.fillColor", label: msg("drawing.field.fillColor", "Fill color"), kind: "color", group: "fill" }];
225
249
  var TEXT_SIZE_OPTIONS = [
226
- { value: "small", label: "Small" },
227
- { value: "normal", label: "Normal" },
228
- { value: "large", label: "Large" },
229
- { value: "huge", label: "Huge" }
250
+ { value: "small", label: msg("drawing.option.small", "Small") },
251
+ { value: "normal", label: msg("drawing.option.normal", "Normal") },
252
+ { value: "large", label: msg("drawing.option.large", "Large") },
253
+ { value: "huge", label: msg("drawing.option.huge", "Huge") }
230
254
  ];
231
255
  var TEXT_FIELDS = [
232
- { path: "text.value", label: "Text", kind: "text", group: "text" },
233
- { path: "text.color", label: "Text color", kind: "color", group: "text" },
234
- { path: "text.size", label: "Text size", kind: "select", options: TEXT_SIZE_OPTIONS, group: "text" },
235
- { path: "text.bold", label: "Bold", kind: "boolean", group: "text" },
236
- { path: "text.italic", label: "Italic", kind: "boolean", group: "text" }
256
+ { path: "text.value", label: msg("drawing.field.text", "Text"), kind: "text", group: "text" },
257
+ { path: "text.color", label: msg("drawing.field.textColor", "Text color"), kind: "color", group: "text" },
258
+ { path: "text.size", label: msg("drawing.field.textSize", "Text size"), kind: "select", options: TEXT_SIZE_OPTIONS, group: "text" },
259
+ { path: "text.bold", label: msg("drawing.field.bold", "Bold"), kind: "boolean", group: "text" },
260
+ { path: "text.italic", label: msg("drawing.field.italic", "Italic"), kind: "boolean", group: "text" }
237
261
  ];
238
262
 
239
263
  // src/core/drawings/hittest.ts
@@ -362,9 +386,9 @@ var TrendLine = class extends Drawing {
362
386
  return {
363
387
  fields: [
364
388
  ...LINE_FIELDS,
365
- { path: "style.arrowRight", label: "Arrow", kind: "boolean", group: "line" },
366
- { path: "style.extendLeft", label: "Extend left", kind: "boolean", group: "line" },
367
- { path: "style.extendRight", label: "Extend right", kind: "boolean", group: "line" },
389
+ { path: "style.arrowRight", label: msg("drawing.trendline.arrowRight", "Arrow"), kind: "boolean", group: "line" },
390
+ { path: "style.extendLeft", label: msg("drawing.trendline.extendLeft", "Extend left"), kind: "boolean", group: "line" },
391
+ { path: "style.extendRight", label: msg("drawing.trendline.extendRight", "Extend right"), kind: "boolean", group: "line" },
368
392
  ...TEXT_FIELDS
369
393
  ]
370
394
  };
@@ -713,8 +737,8 @@ var Box = class extends Drawing {
713
737
  schema() {
714
738
  return {
715
739
  fields: [
716
- ...LINE_FIELDS.map((f) => ({ ...f, label: f.label.replace("Line", "Border") })),
717
- { path: "style.fillColor", label: "Fill color", kind: "color", group: "fill" },
740
+ ...BORDER_FIELDS,
741
+ { path: "style.fillColor", label: msg("drawing.box.fillColor", "Fill color"), kind: "color", group: "fill" },
718
742
  ...TEXT_FIELDS
719
743
  ]
720
744
  };
@@ -724,13 +748,16 @@ var Box = class extends Drawing {
724
748
  // src/core/drawings/types/PinnedLabel.ts
725
749
  var SIZE_PX = { tiny: 10, small: 12, normal: 14, large: 18, huge: 24, auto: 14 };
726
750
  var PinnedLabel = class extends Drawing {
727
- /** The placeholder string when no text has been entered yet. */
751
+ /** The placeholder text when no text has been entered yet. */
728
752
  defaultLabel() {
729
- return "Text";
753
+ return msg("drawing.text.placeholder", "Text");
754
+ }
755
+ placeholderText() {
756
+ return this.defaultLabel();
730
757
  }
731
758
  /** The string used to size the approximate hit box (subclasses with computed text override it). */
732
759
  labelText() {
733
- return this.text?.value ?? this.defaultLabel();
760
+ return this.text?.value ?? sourceText(this.defaultLabel());
734
761
  }
735
762
  anchorSchema() {
736
763
  return { min: 1, max: 1, slots: [{ role: "p", free: "both" }] };
@@ -784,10 +811,10 @@ var Note = class extends PinnedLabel {
784
811
  constructor(init) {
785
812
  super(init);
786
813
  this.type = "note";
787
- if (!this.text) this.text = defaultText("Note");
814
+ if (!this.text) this.text = defaultText(sourceText(this.defaultLabel()));
788
815
  }
789
816
  defaultLabel() {
790
- return "Note";
817
+ return msg("drawing.note.placeholder", "Note");
791
818
  }
792
819
  schema() {
793
820
  return { fields: [...LINE_FIELDS, ...FILL_FIELDS, ...TEXT_FIELDS], textIsContent: true };
@@ -816,15 +843,19 @@ var SIZE_PX2 = { tiny: 10, small: 12, normal: 14, large: 18, huge: 24, auto: 14
816
843
  var CalloutBase = class extends Drawing {
817
844
  constructor(init) {
818
845
  super(init);
819
- if (!this.text) this.text = defaultText(this.defaultLabel());
846
+ if (!this.text) this.text = defaultText(sourceText(this.defaultLabel()));
820
847
  }
821
848
  /** The placeholder text seeded for a fresh annotation. */
822
849
  defaultLabel() {
823
- return "Callout";
850
+ return msg("drawing.callout.placeholder", "Callout");
851
+ }
852
+ placeholderText() {
853
+ const label = this.defaultLabel();
854
+ return sourceText(label) === "" ? null : label;
824
855
  }
825
856
  /** The string used to size the approximate hit box (auto-text subclasses override it). */
826
857
  labelText() {
827
- return this.text?.value ?? this.defaultLabel();
858
+ return this.text?.value ?? sourceText(this.defaultLabel());
828
859
  }
829
860
  anchorSchema() {
830
861
  return { min: 2, max: 2, slots: [{ role: "target", free: "both" }, { role: "box", free: "both" }] };
@@ -929,7 +960,7 @@ var Comment = class extends CalloutBase {
929
960
  this.type = "comment";
930
961
  }
931
962
  defaultLabel() {
932
- return "Comment";
963
+ return msg("drawing.comment.placeholder", "Comment");
933
964
  }
934
965
  };
935
966
 
@@ -940,7 +971,7 @@ var Signpost = class extends CalloutBase {
940
971
  this.type = "signpost";
941
972
  }
942
973
  defaultLabel() {
943
- return "Signpost";
974
+ return msg("drawing.signpost.placeholder", "Signpost");
944
975
  }
945
976
  };
946
977
 
@@ -1369,15 +1400,15 @@ var RegressionChannel = class extends Drawing {
1369
1400
  schema() {
1370
1401
  return {
1371
1402
  fields: [
1372
- { path: "reg.midColor", label: "Midline color", kind: "color", group: "line" },
1373
- { path: "reg.midStyle", label: "Midline style", kind: "lineStyle", group: "line" },
1374
- { path: "reg.upperColor", label: "Upper line color", kind: "color", group: "line" },
1375
- { path: "reg.upperStyle", label: "Upper line style", kind: "lineStyle", group: "line" },
1376
- { path: "reg.lowerColor", label: "Lower line color", kind: "color", group: "line" },
1377
- { path: "reg.lowerStyle", label: "Lower line style", kind: "lineStyle", group: "line" },
1378
- { path: "reg.upperFill", label: "Upper fill", kind: "color", group: "fill" },
1379
- { path: "reg.lowerFill", label: "Lower fill", kind: "color", group: "fill" },
1380
- { path: "reg.showR2", label: "Show R\xB2", kind: "boolean", group: "behavior" }
1403
+ { path: "reg.midColor", label: msg("drawing.regressionchannel.regMidColor", "Midline color"), kind: "color", group: "line" },
1404
+ { path: "reg.midStyle", label: msg("drawing.regressionchannel.regMidStyle", "Midline style"), kind: "lineStyle", group: "line" },
1405
+ { path: "reg.upperColor", label: msg("drawing.regressionchannel.regUpperColor", "Upper line color"), kind: "color", group: "line" },
1406
+ { path: "reg.upperStyle", label: msg("drawing.regressionchannel.regUpperStyle", "Upper line style"), kind: "lineStyle", group: "line" },
1407
+ { path: "reg.lowerColor", label: msg("drawing.regressionchannel.regLowerColor", "Lower line color"), kind: "color", group: "line" },
1408
+ { path: "reg.lowerStyle", label: msg("drawing.regressionchannel.regLowerStyle", "Lower line style"), kind: "lineStyle", group: "line" },
1409
+ { path: "reg.upperFill", label: msg("drawing.regressionchannel.regUpperFill", "Upper fill"), kind: "color", group: "fill" },
1410
+ { path: "reg.lowerFill", label: msg("drawing.regressionchannel.regLowerFill", "Lower fill"), kind: "color", group: "fill" },
1411
+ { path: "reg.showR2", label: msg("drawing.regressionchannel.regShowR2", "Show R²"), kind: "boolean", group: "behavior" }
1381
1412
  ]
1382
1413
  };
1383
1414
  }
@@ -1527,12 +1558,12 @@ var AnchoredVwap = class extends Drawing {
1527
1558
  schema() {
1528
1559
  return {
1529
1560
  fields: [
1530
- { path: "vwap.midColor", label: "VWAP color", kind: "color", group: "line" },
1531
- { path: "vwap.midStyle", label: "VWAP style", kind: "lineStyle", group: "line" },
1532
- { path: "vwap.multiplier", label: "Band multiplier", kind: "number", min: 0.5, max: 5, step: 0.5, group: "behavior" },
1533
- { path: "vwap.upperColor", label: "Upper band color", kind: "color", group: "line" },
1534
- { path: "vwap.lowerColor", label: "Lower band color", kind: "color", group: "line" },
1535
- { path: "vwap.bandFill", label: "Band fill", kind: "color", group: "fill" }
1561
+ { path: "vwap.midColor", label: msg("drawing.anchoredvwap.vwapMidColor", "VWAP color"), kind: "color", group: "line" },
1562
+ { path: "vwap.midStyle", label: msg("drawing.anchoredvwap.vwapMidStyle", "VWAP style"), kind: "lineStyle", group: "line" },
1563
+ { path: "vwap.multiplier", label: msg("drawing.anchoredvwap.vwapMultiplier", "Band multiplier"), kind: "number", min: 0.5, max: 5, step: 0.5, group: "behavior" },
1564
+ { path: "vwap.upperColor", label: msg("drawing.anchoredvwap.vwapUpperColor", "Upper band color"), kind: "color", group: "line" },
1565
+ { path: "vwap.lowerColor", label: msg("drawing.anchoredvwap.vwapLowerColor", "Lower band color"), kind: "color", group: "line" },
1566
+ { path: "vwap.bandFill", label: msg("drawing.anchoredvwap.vwapBandFill", "Band fill"), kind: "color", group: "fill" }
1536
1567
  ]
1537
1568
  };
1538
1569
  }
@@ -1835,38 +1866,38 @@ var FixedRangeVolumeProfile = class extends Drawing {
1835
1866
  schema() {
1836
1867
  return {
1837
1868
  fields: [
1838
- { path: "frvp.rows", label: "Rows", kind: "number", min: 1, max: 500, step: 1, group: "behavior" },
1839
- { path: "frvp.valueAreaPct", label: "Value Area", kind: "number", min: 0, max: 100, step: 1, group: "behavior" },
1840
- { path: "frvp.widthPct", label: "Width %", kind: "number", min: 0, max: 100, step: 1, group: "behavior" },
1869
+ { path: "frvp.rows", label: msg("drawing.fixedrangevp.frvpRows", "Rows"), kind: "number", min: 1, max: 500, step: 1, group: "behavior" },
1870
+ { path: "frvp.valueAreaPct", label: msg("drawing.fixedrangevp.frvpValueAreaPct", "Value Area"), kind: "number", min: 0, max: 100, step: 1, group: "behavior" },
1871
+ { path: "frvp.widthPct", label: msg("drawing.fixedrangevp.frvpWidthPct", "Width %"), kind: "number", min: 0, max: 100, step: 1, group: "behavior" },
1841
1872
  {
1842
1873
  path: "frvp.anchor",
1843
- label: "Anchor",
1874
+ label: msg("drawing.fixedrangevp.frvpAnchor", "Anchor"),
1844
1875
  kind: "select",
1845
1876
  options: [
1846
- { value: "right", label: "Right" },
1847
- { value: "left", label: "Left" }
1877
+ { value: "right", label: msg("drawing.fixedrangevp.option.right", "Right") },
1878
+ { value: "left", label: msg("drawing.fixedrangevp.option.left", "Left") }
1848
1879
  ],
1849
1880
  group: "behavior"
1850
1881
  },
1851
- { path: "frvp.upColor", label: "Up Volume", kind: "color", group: "fill" },
1852
- { path: "frvp.downColor", label: "Down Volume", kind: "color", group: "fill" },
1853
- { path: "frvp.vaUpColor", label: "Value Area Up", kind: "color", group: "fill" },
1854
- { path: "frvp.vaDownColor", label: "Value Area Down", kind: "color", group: "fill" },
1855
- { path: "frvp.showVah", label: "VAH", kind: "boolean", group: "line" },
1856
- { path: "frvp.vahColor", label: "VAH color", kind: "color", group: "line" },
1857
- { path: "frvp.vahStyle", label: "VAH style", kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
1858
- { path: "frvp.showVal", label: "VAL", kind: "boolean", group: "line" },
1859
- { path: "frvp.valColor", label: "VAL color", kind: "color", group: "line" },
1860
- { path: "frvp.valStyle", label: "VAL style", kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
1861
- { path: "frvp.showPoc", label: "POC", kind: "boolean", group: "line" },
1862
- { path: "frvp.pocColor", label: "POC color", kind: "color", group: "line" },
1863
- { path: "frvp.pocStyle", label: "POC style", kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
1864
- { path: "frvp.showDevelopingPoc", label: "Developing POC", kind: "boolean", group: "line" },
1865
- { path: "frvp.developingPocColor", label: "Developing POC color", kind: "color", group: "line" },
1866
- { path: "frvp.developingPocStyle", label: "Developing POC style", kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
1867
- { path: "frvp.showDevelopingVa", label: "Developing VA", kind: "boolean", group: "line" },
1868
- { path: "frvp.developingVaColor", label: "Developing VA color", kind: "color", group: "line" },
1869
- { path: "frvp.developingVaStyle", label: "Developing VA style", kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" }
1882
+ { path: "frvp.upColor", label: msg("drawing.fixedrangevp.frvpUpColor", "Up Volume"), kind: "color", group: "fill" },
1883
+ { path: "frvp.downColor", label: msg("drawing.fixedrangevp.frvpDownColor", "Down Volume"), kind: "color", group: "fill" },
1884
+ { path: "frvp.vaUpColor", label: msg("drawing.fixedrangevp.frvpVaUpColor", "Value Area Up"), kind: "color", group: "fill" },
1885
+ { path: "frvp.vaDownColor", label: msg("drawing.fixedrangevp.frvpVaDownColor", "Value Area Down"), kind: "color", group: "fill" },
1886
+ { path: "frvp.showVah", label: msg("drawing.fixedrangevp.frvpShowVah", "VAH"), kind: "boolean", group: "line" },
1887
+ { path: "frvp.vahColor", label: msg("drawing.fixedrangevp.frvpVahColor", "VAH color"), kind: "color", group: "line" },
1888
+ { path: "frvp.vahStyle", label: msg("drawing.fixedrangevp.frvpVahStyle", "VAH style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
1889
+ { path: "frvp.showVal", label: msg("drawing.fixedrangevp.frvpShowVal", "VAL"), kind: "boolean", group: "line" },
1890
+ { path: "frvp.valColor", label: msg("drawing.fixedrangevp.frvpValColor", "VAL color"), kind: "color", group: "line" },
1891
+ { path: "frvp.valStyle", label: msg("drawing.fixedrangevp.frvpValStyle", "VAL style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
1892
+ { path: "frvp.showPoc", label: msg("drawing.fixedrangevp.frvpShowPoc", "POC"), kind: "boolean", group: "line" },
1893
+ { path: "frvp.pocColor", label: msg("drawing.fixedrangevp.frvpPocColor", "POC color"), kind: "color", group: "line" },
1894
+ { path: "frvp.pocStyle", label: msg("drawing.fixedrangevp.frvpPocStyle", "POC style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
1895
+ { path: "frvp.showDevelopingPoc", label: msg("drawing.fixedrangevp.frvpShowDevelopingPoc", "Developing POC"), kind: "boolean", group: "line" },
1896
+ { path: "frvp.developingPocColor", label: msg("drawing.fixedrangevp.frvpDevelopingPocColor", "Developing POC color"), kind: "color", group: "line" },
1897
+ { path: "frvp.developingPocStyle", label: msg("drawing.fixedrangevp.frvpDevelopingPocStyle", "Developing POC style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" },
1898
+ { path: "frvp.showDevelopingVa", label: msg("drawing.fixedrangevp.frvpShowDevelopingVa", "Developing VA"), kind: "boolean", group: "line" },
1899
+ { path: "frvp.developingVaColor", label: msg("drawing.fixedrangevp.frvpDevelopingVaColor", "Developing VA color"), kind: "color", group: "line" },
1900
+ { path: "frvp.developingVaStyle", label: msg("drawing.fixedrangevp.frvpDevelopingVaStyle", "Developing VA style"), kind: "lineStyle", options: LINE_STYLE_OPTIONS, group: "line" }
1870
1901
  ]
1871
1902
  };
1872
1903
  }
@@ -2136,8 +2167,8 @@ var Arrow = class extends Drawing {
2136
2167
  return {
2137
2168
  fields: [
2138
2169
  ...LINE_FIELDS,
2139
- { path: "style.arrowRight", label: "Head (end)", kind: "boolean", group: "line" },
2140
- { path: "style.arrowLeft", label: "Head (start)", kind: "boolean", group: "line" },
2170
+ { path: "style.arrowRight", label: msg("drawing.arrow.arrowRight", "Head (end)"), kind: "boolean", group: "line" },
2171
+ { path: "style.arrowLeft", label: msg("drawing.arrow.arrowLeft", "Head (start)"), kind: "boolean", group: "line" },
2141
2172
  ...TEXT_FIELDS
2142
2173
  ]
2143
2174
  };
@@ -2327,8 +2358,8 @@ var Freehand = class extends BrushStroke {
2327
2358
 
2328
2359
  // src/core/drawings/types/Highlighter.ts
2329
2360
  var HIGHLIGHTER_FIELDS = [
2330
- { path: "style.lineColor", label: "Color", kind: "color", group: "line" },
2331
- { path: "style.lineWidth", label: "Width", kind: "number", min: 4, max: 60, step: 1, group: "line" }
2361
+ { path: "style.lineColor", label: msg("drawing.highlighter.lineColor", "Color"), kind: "color", group: "line" },
2362
+ { path: "style.lineWidth", label: msg("drawing.highlighter.lineWidth", "Width"), kind: "number", min: 4, max: 60, step: 1, group: "line" }
2332
2363
  ];
2333
2364
  var Highlighter = class extends BrushStroke {
2334
2365
  constructor() {
@@ -2447,7 +2478,7 @@ var RotatedRect = class extends SegmentDrawing {
2447
2478
  return { min: Math.min(...ps), max: Math.max(...ps) };
2448
2479
  }
2449
2480
  schema() {
2450
- return { fields: [...LINE_FIELDS.map((f) => ({ ...f, label: f.label.replace("Line", "Border") })), ...FILL_FIELDS, ...TEXT_FIELDS] };
2481
+ return { fields: [...BORDER_FIELDS, ...FILL_FIELDS, ...TEXT_FIELDS] };
2451
2482
  }
2452
2483
  };
2453
2484
 
@@ -2529,7 +2560,7 @@ var Arc = class extends SegmentDrawing {
2529
2560
  return { min: Math.min(...ps), max: Math.max(...ps) };
2530
2561
  }
2531
2562
  schema() {
2532
- return { fields: [...LINE_FIELDS.map((f) => ({ ...f, label: f.label.replace("Line", "Border") })), ...FILL_FIELDS, ...TEXT_FIELDS] };
2563
+ return { fields: [...BORDER_FIELDS, ...FILL_FIELDS, ...TEXT_FIELDS] };
2533
2564
  }
2534
2565
  };
2535
2566
 
@@ -2645,7 +2676,7 @@ var ArrowMark = class extends Drawing {
2645
2676
  return a ? { min: a.price, max: a.price } : null;
2646
2677
  }
2647
2678
  schema() {
2648
- return { fields: [{ path: "style.lineColor", label: "Color", kind: "color", group: "line" }, ...TEXT_FIELDS] };
2679
+ return { fields: [{ path: "style.lineColor", label: msg("drawing.arrowmarkup.lineColor", "Color"), kind: "color", group: "line" }, ...TEXT_FIELDS] };
2649
2680
  }
2650
2681
  };
2651
2682
  var ArrowMarkUp = class extends ArrowMark {
@@ -2668,7 +2699,7 @@ var ArrowMarkDown = class extends ArrowMark {
2668
2699
  };
2669
2700
 
2670
2701
  // src/core/drawings/types/GlyphStamp.ts
2671
- var GLYPH_OPTIONS = ["\u2605", "\u2606", "\u25CF", "\u25C6", "\u25B2", "\u25BC", "\u27A4", "\u2691", "\u271A", "\u2715", "\u2764", "\u2666"];
2702
+ var GLYPH_OPTIONS = ["★", "☆", "●", "◆", "▲", "▼", "➤", "⚑", "✚", "✕", "❤", "♦"];
2672
2703
  var STAMP_SIZE_OPTIONS = ["small", "normal", "large", "huge"];
2673
2704
  var STAMP_PX = { small: 16, normal: 22, large: 32, huge: 44 };
2674
2705
  var GlyphStamp = class extends Drawing {
@@ -2717,9 +2748,9 @@ var GlyphStamp = class extends Drawing {
2717
2748
  schema() {
2718
2749
  return {
2719
2750
  fields: [
2720
- { path: "glyph", label: "Icon", kind: "select", options: GLYPH_OPTIONS.map((g) => ({ value: g, label: g })), group: "line" },
2721
- { path: "size", label: "Size", kind: "select", options: STAMP_SIZE_OPTIONS.map((s) => ({ value: s, label: s })), group: "line" },
2722
- { path: "style.lineColor", label: "Color", kind: "color", group: "line" },
2751
+ { path: "glyph", label: msg("drawing.flagmark.glyph", "Icon"), kind: "select", options: GLYPH_OPTIONS.map((g) => ({ value: g, label: g })), group: "line" },
2752
+ { path: "size", label: msg("drawing.flagmark.size", "Size"), kind: "select", options: STAMP_SIZE_OPTIONS.map((s) => ({ value: s, label: s })), group: "line" },
2753
+ { path: "style.lineColor", label: msg("drawing.flagmark.lineColor", "Color"), kind: "color", group: "line" },
2723
2754
  ...TEXT_FIELDS
2724
2755
  ]
2725
2756
  };
@@ -2738,7 +2769,7 @@ var FlagMark = class extends GlyphStamp {
2738
2769
  this.type = "flagmark";
2739
2770
  }
2740
2771
  defaultGlyph() {
2741
- return "\u2691";
2772
+ return "⚑";
2742
2773
  }
2743
2774
  };
2744
2775
  var IconStamp = class extends GlyphStamp {
@@ -2747,7 +2778,7 @@ var IconStamp = class extends GlyphStamp {
2747
2778
  this.type = "iconstamp";
2748
2779
  }
2749
2780
  defaultGlyph() {
2750
- return "\u2605";
2781
+ return "★";
2751
2782
  }
2752
2783
  };
2753
2784
 
@@ -2906,8 +2937,8 @@ var FibLevels = class extends FibRatios {
2906
2937
  return {
2907
2938
  fields: [
2908
2939
  ...base.fields,
2909
- { path: "style.extendLeft", label: "Extend left", kind: "boolean", group: "line" },
2910
- { path: "style.extendRight", label: "Extend right", kind: "boolean", group: "line" }
2940
+ { path: "style.extendLeft", label: msg("drawing.field.extendLeft", "Extend left"), kind: "boolean", group: "line" },
2941
+ { path: "style.extendRight", label: msg("drawing.field.extendRight", "Extend right"), kind: "boolean", group: "line" }
2911
2942
  ]
2912
2943
  };
2913
2944
  }
@@ -3026,19 +3057,19 @@ function ladder(ratios, on, colors = {}) {
3026
3057
  var FIB_PRESETS = [
3027
3058
  {
3028
3059
  key: "classic",
3029
- label: "Classic",
3060
+ label: msg("drawing.fibPreset.classic", "Classic"),
3030
3061
  reverse: false,
3031
3062
  levels: ladder(LADDER, [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1])
3032
3063
  },
3033
3064
  {
3034
3065
  key: "extension",
3035
- label: "Extension",
3066
+ label: msg("drawing.fibPreset.extension", "Extension"),
3036
3067
  reverse: true,
3037
3068
  levels: ladder(LADDER, [0, 1, 1.272, 1.414, 1.618, 2, 2.618, 3.618, 4.236])
3038
3069
  },
3039
3070
  {
3040
3071
  key: "ote",
3041
- label: "OTE",
3072
+ label: msg("drawing.fibPreset.ote", "OTE"),
3042
3073
  reverse: false,
3043
3074
  // The entry zone reads as one band.
3044
3075
  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 })
@@ -3999,7 +4030,7 @@ var DedekindTessellation = class extends Drawing {
3999
4030
  ...LINE_FIELDS,
4000
4031
  {
4001
4032
  path: "maxCurvature",
4002
- label: "Max curvature",
4033
+ label: msg("drawing.dedekind.maxCurvature", "Max curvature"),
4003
4034
  kind: "number",
4004
4035
  min: 4,
4005
4036
  max: 64,
@@ -4041,7 +4072,7 @@ function sanitizeLevel2(v) {
4041
4072
  }
4042
4073
  var SHOW_RATIOS_FIELD = {
4043
4074
  path: "showRatios",
4044
- label: "Show ratios",
4075
+ label: msg("drawing.sonic.showRatios", "Show ratios"),
4045
4076
  kind: "boolean",
4046
4077
  group: "behavior"
4047
4078
  };
@@ -4193,7 +4224,7 @@ var MachFigure = class extends Drawing {
4193
4224
  ...LINE_FIELDS,
4194
4225
  {
4195
4226
  path: "waveCount",
4196
- label: "Waves",
4227
+ label: msg("drawing.sonic.waveCount", "Waves"),
4197
4228
  kind: "number",
4198
4229
  min: 3,
4199
4230
  max: 12,
@@ -4253,7 +4284,7 @@ var Supersonic = class extends MachFigure {
4253
4284
  ...LINE_FIELDS,
4254
4285
  {
4255
4286
  path: "mach",
4256
- label: "Mach number",
4287
+ label: msg("drawing.supersonic.mach", "Mach number"),
4257
4288
  kind: "number",
4258
4289
  min: 1.5,
4259
4290
  max: 5,
@@ -4262,7 +4293,7 @@ var Supersonic = class extends MachFigure {
4262
4293
  },
4263
4294
  {
4264
4295
  path: "waveCount",
4265
- label: "Waves",
4296
+ label: msg("drawing.supersonic.waveCount", "Waves"),
4266
4297
  kind: "number",
4267
4298
  min: 3,
4268
4299
  max: 12,
@@ -4327,7 +4358,7 @@ var GoldenSupersonic = class extends MachFigure {
4327
4358
  ...LINE_FIELDS,
4328
4359
  {
4329
4360
  path: "mach",
4330
- label: "Mach number",
4361
+ label: msg("drawing.goldensupersonic.mach", "Mach number"),
4331
4362
  kind: "number",
4332
4363
  min: 1.5,
4333
4364
  max: 5,
@@ -4484,13 +4515,16 @@ var ElliottCorrection = class extends PatternDrawing {
4484
4515
  };
4485
4516
 
4486
4517
  // src/core/drawings/types/HeadShoulders.ts
4518
+ var LEFT_SHOULDER = msg("drawing.headshoulders.leftShoulder", "LS");
4519
+ var HEAD = msg("drawing.headshoulders.head", "H");
4520
+ var RIGHT_SHOULDER = msg("drawing.headshoulders.rightShoulder", "RS");
4487
4521
  var HeadShoulders = class extends PatternDrawing {
4488
4522
  constructor() {
4489
4523
  super(...arguments);
4490
4524
  this.type = "headshoulders";
4491
4525
  }
4492
4526
  vertexLabels() {
4493
- return ["", "LS", "", "H", "", "RS", ""];
4527
+ return ["", LEFT_SHOULDER, "", HEAD, "", RIGHT_SHOULDER, ""];
4494
4528
  }
4495
4529
  necklineIndices() {
4496
4530
  return [2, 4];
@@ -4554,7 +4588,7 @@ var Gartley = class extends HarmonicPattern {
4554
4588
  this.type = "gartley";
4555
4589
  }
4556
4590
  patternName() {
4557
- return "Gartley";
4591
+ return msg("drawing.gartley.patternName", "Gartley");
4558
4592
  }
4559
4593
  ranges() {
4560
4594
  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 } };
@@ -4568,7 +4602,7 @@ var Bat = class extends HarmonicPattern {
4568
4602
  this.type = "bat";
4569
4603
  }
4570
4604
  patternName() {
4571
- return "Bat";
4605
+ return msg("drawing.bat.patternName", "Bat");
4572
4606
  }
4573
4607
  ranges() {
4574
4608
  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 } };
@@ -4582,7 +4616,7 @@ var Butterfly = class extends HarmonicPattern {
4582
4616
  this.type = "butterfly";
4583
4617
  }
4584
4618
  patternName() {
4585
- return "Butterfly";
4619
+ return msg("drawing.butterfly.patternName", "Butterfly");
4586
4620
  }
4587
4621
  ranges() {
4588
4622
  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 } };
@@ -4596,7 +4630,7 @@ var Crab = class extends HarmonicPattern {
4596
4630
  this.type = "crab";
4597
4631
  }
4598
4632
  patternName() {
4599
- return "Crab";
4633
+ return msg("drawing.crab.patternName", "Crab");
4600
4634
  }
4601
4635
  ranges() {
4602
4636
  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 } };
@@ -4610,7 +4644,7 @@ var Shark = class extends HarmonicPattern {
4610
4644
  this.type = "shark";
4611
4645
  }
4612
4646
  patternName() {
4613
- return "Shark";
4647
+ return msg("drawing.shark.patternName", "Shark");
4614
4648
  }
4615
4649
  ranges() {
4616
4650
  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 } };
@@ -4626,7 +4660,7 @@ var Cypher = class extends HarmonicPattern {
4626
4660
  this.type = "cypher";
4627
4661
  }
4628
4662
  patternName() {
4629
- return "Cypher";
4663
+ return msg("drawing.cypher.patternName", "Cypher");
4630
4664
  }
4631
4665
  ranges() {
4632
4666
  return { ab: { min: 0.382, max: 0.618 }, bc: { min: 0, max: Infinity }, cd: { min: 0, max: Infinity }, ad: { min: 0, max: Infinity } };
@@ -4660,27 +4694,13 @@ var Cypher = class extends HarmonicPattern {
4660
4694
  };
4661
4695
 
4662
4696
  // src/core/drawings/types/MeasureBox.ts
4697
+ var MEASURE_TEXT = {
4698
+ priceChange: msg("drawing.measure.priceChange", "{change} ({percent}%)"),
4699
+ barsAndDuration: msg("drawing.measure.barsAndDuration", "{count, plural, one {{bars} bar} other {{bars} bars}}, {duration}")
4700
+ };
4663
4701
  function signed(n) {
4664
4702
  return `${n >= 0 ? "+" : ""}${n.toFixed(2)}`;
4665
4703
  }
4666
- function formatDuration(ms) {
4667
- const m = Math.abs(ms);
4668
- const DAY2 = 864e5;
4669
- const HR = 36e5;
4670
- const MIN2 = 6e4;
4671
- if (m >= DAY2) {
4672
- const d = Math.floor(m / DAY2);
4673
- const h = Math.round(m % DAY2 / HR);
4674
- return h ? `${d}d ${h}h` : `${d}d`;
4675
- }
4676
- if (m >= HR) {
4677
- const h = Math.floor(m / HR);
4678
- const mn = Math.round(m % HR / MIN2);
4679
- return mn ? `${h}h ${mn}m` : `${h}h`;
4680
- }
4681
- if (m >= MIN2) return `${Math.round(m / MIN2)}m`;
4682
- return `${Math.round(m / 1e3)}s`;
4683
- }
4684
4704
  var MeasureBox = class extends Drawing {
4685
4705
  constructor(init) {
4686
4706
  super(init);
@@ -4692,11 +4712,12 @@ var MeasureBox = class extends Drawing {
4692
4712
  }
4693
4713
  // Placed click-move-click (the inherited 'click' mode): first click sets a corner, the second
4694
4714
  // sets the opposite one — consistent with the box/Gann tools.
4695
- /** The measurement lines, filtered by the enabled toggles. */
4696
- measureLabel(proj) {
4715
+ /** The measurement lines, filtered by the enabled toggles, in `i18n`'s language
4716
+ * (English without one). */
4717
+ measureLabel(proj, i18n) {
4697
4718
  const lines = [];
4698
- if (this.showPrice) lines.push(this.priceLabel());
4699
- if (this.showDate) lines.push(this.timeLabel(proj));
4719
+ if (this.showPrice) lines.push(this.priceLabel(i18n));
4720
+ if (this.showDate) lines.push(this.timeLabel(proj, i18n));
4700
4721
  return lines;
4701
4722
  }
4702
4723
  /** Up (later price ≥ earlier) → green; else red. */
@@ -4706,22 +4727,22 @@ var MeasureBox = class extends Drawing {
4706
4727
  return a != null && b != null && b.price >= a.price;
4707
4728
  }
4708
4729
  /** Formatted `Δprice (Δ%)` between the two anchors. */
4709
- priceLabel() {
4730
+ priceLabel(i18n) {
4710
4731
  const a = this.anchors[0];
4711
4732
  const b = this.anchors[1];
4712
4733
  if (!a || !b) return "";
4713
4734
  const delta = b.price - a.price;
4714
4735
  const percent = a.price !== 0 ? delta / a.price * 100 : 0;
4715
- return `${signed(delta)} (${signed(percent)}%)`;
4736
+ return textOf(i18n, MEASURE_TEXT.priceChange, { change: localizeNumberText(signed(delta), i18n), percent: localizeNumberText(signed(percent), i18n) });
4716
4737
  }
4717
4738
  /** Formatted `N bars, duration` between the two anchors (bars only when the projector knows). */
4718
- timeLabel(proj) {
4739
+ timeLabel(proj, i18n) {
4719
4740
  const a = this.anchors[0];
4720
4741
  const b = this.anchors[1];
4721
4742
  if (!a || !b) return "";
4722
- const duration = formatDuration(b.time - a.time);
4743
+ const duration = (i18n ?? englishTranslator()).format.duration(b.time - a.time, { style: "span", surface: "drawing" });
4723
4744
  const bars = proj.barsBetween ? Math.round(proj.barsBetween(a.time, b.time)) : null;
4724
- return bars != null ? `${bars} bars, ${duration}` : duration;
4745
+ return bars != null ? textOf(i18n, MEASURE_TEXT.barsAndDuration, { count: bars, bars: localizeNumberText(String(bars), i18n), duration }) : duration;
4725
4746
  }
4726
4747
  rect(proj) {
4727
4748
  const a = this.anchors[0];
@@ -4757,12 +4778,12 @@ var MeasureBox = class extends Drawing {
4757
4778
  schema() {
4758
4779
  return {
4759
4780
  fields: [
4760
- { path: "showPrice", label: "Show price", kind: "boolean", group: "behavior" },
4761
- { path: "showDate", label: "Show date", kind: "boolean", group: "behavior" },
4781
+ { path: "showPrice", label: msg("drawing.measure.showPrice", "Show price"), kind: "boolean", group: "behavior" },
4782
+ { path: "showDate", label: msg("drawing.measure.showDate", "Show date"), kind: "boolean", group: "behavior" },
4762
4783
  ...LINE_FIELDS.filter((f) => f.path !== "style.lineColor"),
4763
4784
  // box border (the fill is direction-tinted)
4764
- { path: "text.color", label: "Text color", kind: "color", group: "text" },
4765
- { path: "text.size", label: "Text size", kind: "select", options: TEXT_SIZE_OPTIONS, group: "text" }
4785
+ { path: "text.color", label: msg("drawing.field.textColor", "Text color"), kind: "color", group: "text" },
4786
+ { path: "text.size", label: msg("drawing.field.textSize", "Text size"), kind: "select", options: TEXT_SIZE_OPTIONS, group: "text" }
4766
4787
  ]
4767
4788
  };
4768
4789
  }
@@ -4784,9 +4805,17 @@ var DatePriceRange = class extends MeasureBox {
4784
4805
  };
4785
4806
 
4786
4807
  // src/core/drawings/types/PositionTool.ts
4808
+ var POSITION_TEXT = {
4809
+ header: msg("drawing.position.header", "{direction, select, long {LONG} other {SHORT}} · R:R {ratio}"),
4810
+ lossSize: msg("drawing.position.lossSize", "Loss {loss} · Size {size}"),
4811
+ target: msg("drawing.position.targetLabel", "Target +{percent}%"),
4812
+ targetAt: msg("drawing.position.targetLabelAt", "Target +{percent}% @ {price}"),
4813
+ stop: msg("drawing.position.stopLabel", "Stop −{percent}%"),
4814
+ stopAt: msg("drawing.position.stopLabelAt", "Stop −{percent}% @ {price}")
4815
+ };
4787
4816
  var DIRECTION_OPTIONS = [
4788
- { value: "long", label: "Long" },
4789
- { value: "short", label: "Short" }
4817
+ { value: "long", label: msg("drawing.position.option.long", "Long") },
4818
+ { value: "short", label: msg("drawing.position.option.short", "Short") }
4790
4819
  ];
4791
4820
  var _PositionTool = class _PositionTool extends Drawing {
4792
4821
  constructor(init) {
@@ -4964,7 +4993,7 @@ var _PositionTool = class _PositionTool extends Drawing {
4964
4993
  const p = this.prices();
4965
4994
  return p && p.entry !== 0 ? Math.abs(p.entry - p.stop) / p.entry * 100 : 0;
4966
4995
  }
4967
- /** Dollar amount risked at the stop = accountBalance × riskPercent / 100. */
4996
+ /** Amount risked at the stop, in the balance's units = accountBalance × riskPercent / 100. */
4968
4997
  dollarLoss() {
4969
4998
  return Math.max(0, this.accountBalance) * (Math.max(0, this.riskPercent) / 100);
4970
4999
  }
@@ -4976,25 +5005,34 @@ var _PositionTool = class _PositionTool extends Drawing {
4976
5005
  return risk < 1e-9 ? 0 : this.dollarLoss() / risk;
4977
5006
  }
4978
5007
  // ── painted label lines (each respects its own toggle; the painter checks showText) ──
4979
- /** `DIR · R:R x.xx` — the always-on header when text is shown. */
4980
- headerLabel() {
4981
- return `${this.directionLabel()} \xB7 R:R ${this.rr().toFixed(2)}`;
5008
+ /** `DIR · R:R x.xx` — the always-on header when text is shown, in `i18n`'s language
5009
+ * (English without one). */
5010
+ headerLabel(i18n) {
5011
+ return textOf(i18n, POSITION_TEXT.header, {
5012
+ direction: this.directionLabel() === "LONG" ? "long" : "short",
5013
+ ratio: localizeNumberText(this.rr().toFixed(2), i18n)
5014
+ });
4982
5015
  }
4983
- /** `Loss $… · Size …` — the painter hides it when showLossSize is off. */
4984
- lossSizeLabel() {
4985
- return `Loss $${formatMoney(this.dollarLoss())} \xB7 Size ${formatQty(this.positionSize())}`;
5016
+ /** `Loss … · Size …` — the painter hides it when showLossSize is off. */
5017
+ lossSizeLabel(i18n) {
5018
+ return textOf(i18n, POSITION_TEXT.lossSize, {
5019
+ loss: localizeNumberText(formatMoney(this.dollarLoss()), i18n),
5020
+ size: localizeNumberText(formatQty(this.positionSize()), i18n)
5021
+ });
4986
5022
  }
4987
5023
  /** `Target +x.xx%`, with the level price appended when showPrices is on. */
4988
- targetLabel() {
5024
+ targetLabel(i18n) {
4989
5025
  const p = this.prices();
4990
- const at = this.showPrices && p ? ` @ ${formatPrice(p.target)}` : "";
4991
- return `Target +${this.rewardPct().toFixed(2)}%${at}`;
5026
+ const percent = localizeNumberText(this.rewardPct().toFixed(2), i18n);
5027
+ if (this.showPrices && p) return textOf(i18n, POSITION_TEXT.targetAt, { percent, price: localizeNumberText(formatPrice(p.target), i18n) });
5028
+ return textOf(i18n, POSITION_TEXT.target, { percent });
4992
5029
  }
4993
5030
  /** `Stop −x.xx%`, with the level price appended when showPrices is on. */
4994
- stopLabel() {
5031
+ stopLabel(i18n) {
4995
5032
  const p = this.prices();
4996
- const at = this.showPrices && p ? ` @ ${formatPrice(p.stop)}` : "";
4997
- return `Stop \u2212${this.riskPct().toFixed(2)}%${at}`;
5033
+ const percent = localizeNumberText(this.riskPct().toFixed(2), i18n);
5034
+ if (this.showPrices && p) return textOf(i18n, POSITION_TEXT.stopAt, { percent, price: localizeNumberText(formatPrice(p.stop), i18n) });
5035
+ return textOf(i18n, POSITION_TEXT.stop, { percent });
4998
5036
  }
4999
5037
  // ── stop/target input units (the gear panel's Price / Points dropdowns) ──
5000
5038
  /** The stop or target expressed in the given unit: the absolute price, or the distance from
@@ -5063,24 +5101,24 @@ var _PositionTool = class _PositionTool extends Drawing {
5063
5101
  schema() {
5064
5102
  return {
5065
5103
  fields: [
5066
- { path: "riskPercent", label: "Risk %", kind: "number", min: 0, max: 100, step: 0.1, group: "behavior" },
5067
- { path: "accountBalance", label: "Account balance", kind: "number", min: 0, max: 1e12, step: 1, group: "behavior" },
5068
- { path: "quantity", label: "Position size", kind: "number", group: "behavior" },
5069
- { path: "direction", label: "Direction", kind: "select", options: DIRECTION_OPTIONS, group: "behavior" },
5070
- { path: "entryPrice", label: "Entry price", kind: "number", group: "behavior" },
5071
- { path: "stopPrice", label: "Stop price", kind: "number", group: "behavior" },
5072
- { path: "targetPrice", label: "Target price", kind: "number", group: "behavior" },
5073
- { path: "showText", label: "Show text", kind: "boolean", group: "behavior" },
5074
- { path: "showHeader", label: "Show direction & ratio", kind: "boolean", group: "behavior" },
5075
- { path: "showLossSize", label: "Show loss & size", kind: "boolean", group: "behavior" },
5076
- { path: "showTargetLabel", label: "Show target label", kind: "boolean", group: "behavior" },
5077
- { path: "showStopLabel", label: "Show stop label", kind: "boolean", group: "behavior" },
5078
- { path: "showPrices", label: "Show level prices", kind: "boolean", group: "behavior" },
5079
- { path: "profitColor", label: "Profit zone", kind: "color", group: "fill" },
5080
- { path: "lossColor", label: "Loss zone", kind: "color", group: "fill" },
5104
+ { path: "riskPercent", label: msg("drawing.position.riskPercent", "Risk %"), kind: "number", min: 0, max: 100, step: 0.1, group: "behavior" },
5105
+ { path: "accountBalance", label: msg("drawing.position.accountBalance", "Account balance"), kind: "number", min: 0, max: 1e12, step: 1, group: "behavior" },
5106
+ { path: "quantity", label: msg("drawing.position.quantity", "Position size"), kind: "number", group: "behavior" },
5107
+ { path: "direction", label: msg("drawing.position.direction", "Direction"), kind: "select", options: DIRECTION_OPTIONS, group: "behavior" },
5108
+ { path: "entryPrice", label: msg("drawing.position.entryPrice", "Entry price"), kind: "number", group: "behavior" },
5109
+ { path: "stopPrice", label: msg("drawing.position.stopPrice", "Stop price"), kind: "number", group: "behavior" },
5110
+ { path: "targetPrice", label: msg("drawing.position.targetPrice", "Target price"), kind: "number", group: "behavior" },
5111
+ { path: "showText", label: msg("drawing.position.showText", "Show text"), kind: "boolean", group: "behavior" },
5112
+ { path: "showHeader", label: msg("drawing.position.showHeader", "Show direction & ratio"), kind: "boolean", group: "behavior" },
5113
+ { path: "showLossSize", label: msg("drawing.position.showLossSize", "Show loss & size"), kind: "boolean", group: "behavior" },
5114
+ { path: "showTargetLabel", label: msg("drawing.position.showTargetLabel", "Show target label"), kind: "boolean", group: "behavior" },
5115
+ { path: "showStopLabel", label: msg("drawing.position.showStopLabel", "Show stop label"), kind: "boolean", group: "behavior" },
5116
+ { path: "showPrices", label: msg("drawing.position.showPrices", "Show level prices"), kind: "boolean", group: "behavior" },
5117
+ { path: "profitColor", label: msg("drawing.position.profitColor", "Profit zone"), kind: "color", group: "fill" },
5118
+ { path: "lossColor", label: msg("drawing.position.lossColor", "Loss zone"), kind: "color", group: "fill" },
5081
5119
  ...LINE_FIELDS.filter((f) => f.path !== "style.lineColor"),
5082
- { path: "text.color", label: "Text color", kind: "color", group: "text" },
5083
- { path: "text.size", label: "Text size", kind: "select", options: TEXT_SIZE_OPTIONS, group: "text" }
5120
+ { path: "text.color", label: msg("drawing.position.textColor", "Text color"), kind: "color", group: "text" },
5121
+ { path: "text.size", label: msg("drawing.position.textSize", "Text size"), kind: "select", options: TEXT_SIZE_OPTIONS, group: "text" }
5084
5122
  ]
5085
5123
  };
5086
5124
  }
@@ -5149,14 +5187,14 @@ function roundFloat(n) {
5149
5187
 
5150
5188
  // src/core/drawings/types/Magnifier.ts
5151
5189
  var MAGNIFIER_TIMEFRAME_OPTIONS = [
5152
- { value: "auto", label: "Auto", ms: 0 },
5153
- { value: "1", label: "1m", ms: 6e4 },
5154
- { value: "5", label: "5m", ms: 3e5 },
5155
- { value: "15", label: "15m", ms: 9e5 },
5156
- { value: "30", label: "30m", ms: 18e5 },
5157
- { value: "60", label: "1h", ms: 36e5 },
5158
- { value: "240", label: "4h", ms: 144e5 },
5159
- { value: "D", label: "1D", ms: 864e5 }
5190
+ { value: "auto", label: msg("drawing.magnifier.option.auto", "Auto"), ms: 0 },
5191
+ { value: "1", label: msg("drawing.magnifier.option.n1", "1m"), ms: 6e4 },
5192
+ { value: "5", label: msg("drawing.magnifier.option.n5", "5m"), ms: 3e5 },
5193
+ { value: "15", label: msg("drawing.magnifier.option.n15", "15m"), ms: 9e5 },
5194
+ { value: "30", label: msg("drawing.magnifier.option.n30", "30m"), ms: 18e5 },
5195
+ { value: "60", label: msg("drawing.magnifier.option.n60", "1h"), ms: 36e5 },
5196
+ { value: "240", label: msg("drawing.magnifier.option.n240", "4h"), ms: 144e5 },
5197
+ { value: "D", label: msg("drawing.magnifier.option.d", "1D"), ms: 864e5 }
5160
5198
  ];
5161
5199
  function magnifierTimeframesBelow(chartMs) {
5162
5200
  if (!(chartMs > 0)) return [...MAGNIFIER_TIMEFRAME_OPTIONS];
@@ -5238,14 +5276,14 @@ var Magnifier = class extends Drawing {
5238
5276
  fields: [
5239
5277
  {
5240
5278
  path: "magnifier.timeframe",
5241
- label: "Timeframe",
5279
+ label: msg("drawing.magnifier.magnifierTimeframe", "Timeframe"),
5242
5280
  kind: "select",
5243
5281
  options: MAGNIFIER_TIMEFRAME_OPTIONS,
5244
5282
  group: "behavior"
5245
5283
  },
5246
- ...LINE_FIELDS.map((f) => ({ ...f, label: f.label.replace("Line", "Border") })),
5247
- { path: "magnifier.upColor", label: "Up candles", kind: "color", group: "fill" },
5248
- { path: "magnifier.downColor", label: "Down candles", kind: "color", group: "fill" }
5284
+ ...BORDER_FIELDS,
5285
+ { path: "magnifier.upColor", label: msg("drawing.magnifier.magnifierUpColor", "Up candles"), kind: "color", group: "fill" },
5286
+ { path: "magnifier.downColor", label: msg("drawing.magnifier.magnifierDownColor", "Down candles"), kind: "color", group: "fill" }
5249
5287
  ]
5250
5288
  };
5251
5289
  }
@@ -5448,10 +5486,10 @@ var PriceActionZone = class extends PriceActionTool {
5448
5486
 
5449
5487
  // src/core/drawings/types/FairValueGap.ts
5450
5488
  var EXTEND_OPTIONS = [
5451
- { value: "tested", label: "Until tested" },
5452
- { value: "half", label: "Until 50%" },
5453
- { value: "filled", label: "Until filled" },
5454
- { value: "always", label: "Always" }
5489
+ { value: "tested", label: msg("drawing.fairvaluegap.option.tested", "Until tested") },
5490
+ { value: "half", label: msg("drawing.fairvaluegap.option.half", "Until 50%") },
5491
+ { value: "filled", label: msg("drawing.fairvaluegap.option.filled", "Until filled") },
5492
+ { value: "always", label: msg("drawing.fairvaluegap.option.always", "Always") }
5455
5493
  ];
5456
5494
  function defaults() {
5457
5495
  return { extend: "filled", upColor: `${BULLISH}33`, downColor: `${BEARISH}33`, midline: true, border: false, fade: true, inverse: false };
@@ -5475,13 +5513,13 @@ var FairValueGap = class extends PriceActionZone {
5475
5513
  schema() {
5476
5514
  return {
5477
5515
  fields: [
5478
- { path: "gap.extend", label: "Extend right", kind: "select", options: EXTEND_OPTIONS, group: "behavior" },
5479
- { path: "gap.upColor", label: "Bullish", kind: "color", group: "fill" },
5480
- { path: "gap.downColor", label: "Bearish", kind: "color", group: "fill" },
5481
- { path: "gap.midline", label: "Midline", kind: "boolean", group: "line" },
5482
- { path: "gap.border", label: "Border", kind: "boolean", group: "line" },
5483
- { path: "gap.fade", label: "Fade at end", kind: "boolean", group: "behavior", when: { path: "gap.extend", in: ["tested", "half", "filled"] } },
5484
- { path: "gap.inverse", label: "Flip on close", kind: "boolean", group: "behavior", when: { path: "gap.extend", in: ["filled"] } }
5516
+ { path: "gap.extend", label: msg("drawing.fairvaluegap.gapExtend", "Extend right"), kind: "select", options: EXTEND_OPTIONS, group: "behavior" },
5517
+ { path: "gap.upColor", label: msg("drawing.fairvaluegap.gapUpColor", "Bullish"), kind: "color", group: "fill" },
5518
+ { path: "gap.downColor", label: msg("drawing.fairvaluegap.gapDownColor", "Bearish"), kind: "color", group: "fill" },
5519
+ { path: "gap.midline", label: msg("drawing.fairvaluegap.gapMidline", "Midline"), kind: "boolean", group: "line" },
5520
+ { path: "gap.border", label: msg("drawing.fairvaluegap.gapBorder", "Border"), kind: "boolean", group: "line" },
5521
+ { path: "gap.fade", label: msg("drawing.fairvaluegap.gapFade", "Fade at end"), kind: "boolean", group: "behavior", when: { path: "gap.extend", in: ["tested", "half", "filled"] } },
5522
+ { path: "gap.inverse", label: msg("drawing.fairvaluegap.gapInverse", "Flip on close"), kind: "boolean", group: "behavior", when: { path: "gap.extend", in: ["filled"] } }
5485
5523
  ]
5486
5524
  };
5487
5525
  }
@@ -5505,14 +5543,14 @@ var FairValueGap = class extends PriceActionZone {
5505
5543
 
5506
5544
  // src/core/drawings/types/OrderBlock.ts
5507
5545
  var RANGE_OPTIONS = [
5508
- { value: "body", label: "Body" },
5509
- { value: "wick", label: "Full range" }
5546
+ { value: "body", label: msg("drawing.orderblock.option.body", "Body") },
5547
+ { value: "wick", label: msg("drawing.orderblock.option.wick", "Full range") }
5510
5548
  ];
5511
5549
  var EXTEND_OPTIONS2 = [
5512
- { value: "tested", label: "Until tested" },
5513
- { value: "half", label: "Until 50%" },
5514
- { value: "broken", label: "Until broken" },
5515
- { value: "always", label: "Always" }
5550
+ { value: "tested", label: msg("drawing.orderblock.option.tested", "Until tested") },
5551
+ { value: "half", label: msg("drawing.orderblock.option.half", "Until 50%") },
5552
+ { value: "broken", label: msg("drawing.orderblock.option.broken", "Until broken") },
5553
+ { value: "always", label: msg("drawing.orderblock.option.always", "Always") }
5516
5554
  ];
5517
5555
  function defaults2() {
5518
5556
  return { range: "body", extend: "broken", upColor: `${BULLISH}29`, downColor: `${BEARISH}29`, midline: true, border: true, fade: true, breaker: true };
@@ -5536,14 +5574,14 @@ var OrderBlock = class extends PriceActionZone {
5536
5574
  schema() {
5537
5575
  return {
5538
5576
  fields: [
5539
- { path: "block.range", label: "Zone", kind: "select", options: RANGE_OPTIONS, group: "behavior" },
5540
- { path: "block.extend", label: "Extend right", kind: "select", options: EXTEND_OPTIONS2, group: "behavior" },
5541
- { path: "block.upColor", label: "Bullish", kind: "color", group: "fill" },
5542
- { path: "block.downColor", label: "Bearish", kind: "color", group: "fill" },
5543
- { path: "block.midline", label: "Midline", kind: "boolean", group: "line" },
5544
- { path: "block.border", label: "Border", kind: "boolean", group: "line" },
5545
- { path: "block.fade", label: "Fade at end", kind: "boolean", group: "behavior", when: { path: "block.extend", in: ["tested", "half", "broken"] } },
5546
- { path: "block.breaker", label: "Breaker", kind: "boolean", group: "behavior", when: { path: "block.extend", in: ["broken"] } }
5577
+ { path: "block.range", label: msg("drawing.orderblock.blockRange", "Zone"), kind: "select", options: RANGE_OPTIONS, group: "behavior" },
5578
+ { path: "block.extend", label: msg("drawing.orderblock.blockExtend", "Extend right"), kind: "select", options: EXTEND_OPTIONS2, group: "behavior" },
5579
+ { path: "block.upColor", label: msg("drawing.orderblock.blockUpColor", "Bullish"), kind: "color", group: "fill" },
5580
+ { path: "block.downColor", label: msg("drawing.orderblock.blockDownColor", "Bearish"), kind: "color", group: "fill" },
5581
+ { path: "block.midline", label: msg("drawing.orderblock.blockMidline", "Midline"), kind: "boolean", group: "line" },
5582
+ { path: "block.border", label: msg("drawing.orderblock.blockBorder", "Border"), kind: "boolean", group: "line" },
5583
+ { path: "block.fade", label: msg("drawing.orderblock.blockFade", "Fade at end"), kind: "boolean", group: "behavior", when: { path: "block.extend", in: ["tested", "half", "broken"] } },
5584
+ { path: "block.breaker", label: msg("drawing.orderblock.blockBreaker", "Breaker"), kind: "boolean", group: "behavior", when: { path: "block.extend", in: ["broken"] } }
5547
5585
  ]
5548
5586
  };
5549
5587
  }
@@ -5568,9 +5606,9 @@ var OrderBlock = class extends PriceActionZone {
5568
5606
 
5569
5607
  // src/core/drawings/types/Liquidity.ts
5570
5608
  var EXTEND_OPTIONS3 = [
5571
- { value: "swept", label: "Until swept" },
5572
- { value: "broken", label: "Until broken" },
5573
- { value: "always", label: "Always" }
5609
+ { value: "swept", label: msg("drawing.liquidity.option.swept", "Until swept") },
5610
+ { value: "broken", label: msg("drawing.liquidity.option.broken", "Until broken") },
5611
+ { value: "always", label: msg("drawing.liquidity.option.always", "Always") }
5574
5612
  ];
5575
5613
  function defaults3() {
5576
5614
  return { extend: "swept", markSweep: true };
@@ -5626,8 +5664,8 @@ var Liquidity = class extends PriceActionTool {
5626
5664
  return {
5627
5665
  fields: [
5628
5666
  ...LINE_FIELDS,
5629
- { path: "liq.extend", label: "Extend right", kind: "select", options: EXTEND_OPTIONS3, group: "behavior" },
5630
- { path: "liq.markSweep", label: "Mark sweep", kind: "boolean", group: "behavior" }
5667
+ { path: "liq.extend", label: msg("drawing.liquidity.liqExtend", "Extend right"), kind: "select", options: EXTEND_OPTIONS3, group: "behavior" },
5668
+ { path: "liq.markSweep", label: msg("drawing.liquidity.liqMarkSweep", "Mark sweep"), kind: "boolean", group: "behavior" }
5631
5669
  ]
5632
5670
  };
5633
5671
  }
@@ -5649,10 +5687,24 @@ var REGISTRY2 = /* @__PURE__ */ new Map();
5649
5687
  function registerDrawingType(meta) {
5650
5688
  REGISTRY2.set(meta.type, meta);
5651
5689
  }
5652
- function getDrawingType(type) {
5690
+ function resolved2(meta, i18n) {
5691
+ if (typeof meta.label === "string" && (meta.placementHint === void 0 || typeof meta.placementHint === "string")) return meta;
5692
+ const out = { ...meta, label: textOf(i18n, meta.label), placementHint: void 0 };
5693
+ if (meta.placementHint !== void 0) out.placementHint = textOf(i18n, meta.placementHint);
5694
+ else delete out.placementHint;
5695
+ return out;
5696
+ }
5697
+ function getDrawingType(type, i18n) {
5698
+ const meta = REGISTRY2.get(type);
5699
+ return meta ? resolved2(meta, i18n) : void 0;
5700
+ }
5701
+ function drawingTypes(i18n) {
5702
+ return [...REGISTRY2.values()].map((meta) => resolved2(meta, i18n));
5703
+ }
5704
+ function drawingTypeEntry(type) {
5653
5705
  return REGISTRY2.get(type);
5654
5706
  }
5655
- function drawingTypes() {
5707
+ function drawingTypeEntries() {
5656
5708
  return [...REGISTRY2.values()];
5657
5709
  }
5658
5710
  function createDrawing(type, init) {
@@ -5684,7 +5736,7 @@ var HLINE_ICON = svg24('<line x1="3" y1="12" x2="21" y2="12"/>');
5684
5736
  registerDrawingType({
5685
5737
  type: "trendline",
5686
5738
  group: "lines",
5687
- label: "Trend Line",
5739
+ label: msg("drawing.trendline.label", "Trend Line"),
5688
5740
  icon: LINE_ICON,
5689
5741
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5690
5742
  create: (init) => new TrendLine(init)
@@ -5692,7 +5744,7 @@ registerDrawingType({
5692
5744
  registerDrawingType({
5693
5745
  type: "hline",
5694
5746
  group: "lines",
5695
- label: "Horizontal Line",
5747
+ label: msg("drawing.hline.label", "Horizontal Line"),
5696
5748
  icon: HLINE_ICON,
5697
5749
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "dashed" },
5698
5750
  create: (init) => new HorizontalLine(init)
@@ -5703,7 +5755,7 @@ var TEXT_ICON = svg24('<path d="M5 6h14M12 6v13"/>');
5703
5755
  registerDrawingType({
5704
5756
  type: "ray",
5705
5757
  group: "lines",
5706
- label: "Ray",
5758
+ label: msg("drawing.ray.label", "Ray"),
5707
5759
  icon: RAY_ICON,
5708
5760
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5709
5761
  create: (init) => new Ray(init)
@@ -5717,7 +5769,7 @@ var TRENDANGLE_ICON = svg24('<path d="M4 20 20 6"/><path d="M4 20 15 20"/><path
5717
5769
  registerDrawingType({
5718
5770
  type: "extendedline",
5719
5771
  group: "lines",
5720
- label: "Extended Line",
5772
+ label: msg("drawing.extendedline.label", "Extended Line"),
5721
5773
  icon: EXTLINE_ICON,
5722
5774
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5723
5775
  create: (init) => new ExtendedLine(init)
@@ -5725,7 +5777,7 @@ registerDrawingType({
5725
5777
  registerDrawingType({
5726
5778
  type: "vline",
5727
5779
  group: "lines",
5728
- label: "Vertical Line",
5780
+ label: msg("drawing.vline.label", "Vertical Line"),
5729
5781
  icon: VLINE_ICON,
5730
5782
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5731
5783
  create: (init) => new VerticalLine(init)
@@ -5733,7 +5785,7 @@ registerDrawingType({
5733
5785
  registerDrawingType({
5734
5786
  type: "hray",
5735
5787
  group: "lines",
5736
- label: "Horizontal Ray",
5788
+ label: msg("drawing.hray.label", "Horizontal Ray"),
5737
5789
  icon: HRAY_ICON,
5738
5790
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5739
5791
  create: (init) => new HorizontalRay(init)
@@ -5741,7 +5793,7 @@ registerDrawingType({
5741
5793
  registerDrawingType({
5742
5794
  type: "crossline",
5743
5795
  group: "lines",
5744
- label: "Cross Line",
5796
+ label: msg("drawing.crossline.label", "Cross Line"),
5745
5797
  icon: CROSSLINE_ICON,
5746
5798
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
5747
5799
  create: (init) => new CrossLine(init)
@@ -5749,7 +5801,7 @@ registerDrawingType({
5749
5801
  registerDrawingType({
5750
5802
  type: "infoline",
5751
5803
  group: "lines",
5752
- label: "Info Line",
5804
+ label: msg("drawing.infoline.label", "Info Line"),
5753
5805
  icon: INFOLINE_ICON,
5754
5806
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5755
5807
  create: (init) => new InfoLine(init)
@@ -5757,7 +5809,7 @@ registerDrawingType({
5757
5809
  registerDrawingType({
5758
5810
  type: "trendangle",
5759
5811
  group: "lines",
5760
- label: "Trend Angle",
5812
+ label: msg("drawing.trendangle.label", "Trend Angle"),
5761
5813
  icon: TRENDANGLE_ICON,
5762
5814
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5763
5815
  create: (init) => new TrendAngle(init)
@@ -5765,7 +5817,7 @@ registerDrawingType({
5765
5817
  registerDrawingType({
5766
5818
  type: "box",
5767
5819
  group: "shapes",
5768
- label: "Rectangle",
5820
+ label: msg("drawing.box.label", "Rectangle"),
5769
5821
  icon: BOX_ICON,
5770
5822
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}26` },
5771
5823
  create: (init) => new Box(init)
@@ -5773,7 +5825,7 @@ registerDrawingType({
5773
5825
  registerDrawingType({
5774
5826
  type: "text",
5775
5827
  group: "annotations",
5776
- label: "Text",
5828
+ label: msg("drawing.text.label", "Text"),
5777
5829
  icon: TEXT_ICON,
5778
5830
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
5779
5831
  create: (init) => new TextLabel(init)
@@ -5782,7 +5834,7 @@ var CALLOUT_ICON = svg24('<path d="M5 4h14a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-6l-5 5
5782
5834
  registerDrawingType({
5783
5835
  type: "callout",
5784
5836
  group: "annotations",
5785
- label: "Callout",
5837
+ label: msg("drawing.callout.label", "Callout"),
5786
5838
  icon: CALLOUT_ICON,
5787
5839
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}d9` },
5788
5840
  create: (init) => new Callout(init)
@@ -5795,7 +5847,7 @@ var SIGNPOST_ICON = svg24('<path d="M12 11.5V21"/><rect x="5" y="4" width="14" h
5795
5847
  registerDrawingType({
5796
5848
  type: "note",
5797
5849
  group: "annotations",
5798
- label: "Note",
5850
+ label: msg("drawing.note.label", "Note"),
5799
5851
  icon: NOTE_ICON,
5800
5852
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}d9` },
5801
5853
  create: (init) => new Note(init)
@@ -5803,7 +5855,7 @@ registerDrawingType({
5803
5855
  registerDrawingType({
5804
5856
  type: "pricenote",
5805
5857
  group: "annotations",
5806
- label: "Price Note",
5858
+ label: msg("drawing.pricenote.label", "Price Note"),
5807
5859
  icon: PRICE_NOTE_ICON,
5808
5860
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}d9` },
5809
5861
  create: (init) => new PriceNote(init)
@@ -5811,7 +5863,7 @@ registerDrawingType({
5811
5863
  registerDrawingType({
5812
5864
  type: "comment",
5813
5865
  group: "annotations",
5814
- label: "Comment",
5866
+ label: msg("drawing.comment.label", "Comment"),
5815
5867
  icon: COMMENT_ICON,
5816
5868
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}d9` },
5817
5869
  create: (init) => new Comment(init)
@@ -5819,7 +5871,7 @@ registerDrawingType({
5819
5871
  registerDrawingType({
5820
5872
  type: "pricelabel",
5821
5873
  group: "annotations",
5822
- label: "Price Label",
5874
+ label: msg("drawing.pricelabel.label", "Price Label"),
5823
5875
  icon: PRICE_LABEL_ICON,
5824
5876
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}d9` },
5825
5877
  create: (init) => new PriceLabel(init)
@@ -5827,7 +5879,7 @@ registerDrawingType({
5827
5879
  registerDrawingType({
5828
5880
  type: "signpost",
5829
5881
  group: "annotations",
5830
- label: "Signpost",
5882
+ label: msg("drawing.signpost.label", "Signpost"),
5831
5883
  icon: SIGNPOST_ICON,
5832
5884
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}d9` },
5833
5885
  create: (init) => new Signpost(init)
@@ -5838,7 +5890,7 @@ var PITCHFORK_ICON = svg24('<circle cx="4" cy="12" r="1.6" fill="currentColor"/>
5838
5890
  registerDrawingType({
5839
5891
  type: "parallelchannel",
5840
5892
  group: "channels",
5841
- label: "Parallel Channel",
5893
+ label: msg("drawing.parallelchannel.label", "Parallel Channel"),
5842
5894
  icon: PARALLEL_ICON,
5843
5895
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}1a` },
5844
5896
  create: (init) => new ParallelChannel(init)
@@ -5846,7 +5898,7 @@ registerDrawingType({
5846
5898
  registerDrawingType({
5847
5899
  type: "disjointchannel",
5848
5900
  group: "channels",
5849
- label: "Disjoint Channel",
5901
+ label: msg("drawing.disjointchannel.label", "Disjoint Channel"),
5850
5902
  icon: DISJOINT_ICON,
5851
5903
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}1a` },
5852
5904
  create: (init) => new DisjointChannel(init)
@@ -5855,7 +5907,7 @@ var FLATTOP_ICON = svg24('<line x1="3" y1="7" x2="21" y2="7"/><line x1="3" y1="1
5855
5907
  registerDrawingType({
5856
5908
  type: "flattopbottom",
5857
5909
  group: "channels",
5858
- label: "Flat Top/Bottom",
5910
+ label: msg("drawing.flattopbottom.label", "Flat Top/Bottom"),
5859
5911
  icon: FLATTOP_ICON,
5860
5912
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}1a` },
5861
5913
  create: (init) => new FlatTopBottom(init)
@@ -5864,7 +5916,7 @@ var REGRESSION_ICON = svg24('<line x1="3" y1="8" x2="21" y2="4"/><line x1="3" y1
5864
5916
  registerDrawingType({
5865
5917
  type: "regressionchannel",
5866
5918
  group: "channels",
5867
- label: "Linear Regression",
5919
+ label: msg("drawing.regressionchannel.label", "Linear Regression"),
5868
5920
  icon: REGRESSION_ICON,
5869
5921
  defaultStyle: { lineColor: NEUTRAL, lineWidth: 1, lineStyle: "solid" },
5870
5922
  create: (init) => new RegressionChannel(init)
@@ -5872,7 +5924,7 @@ registerDrawingType({
5872
5924
  registerDrawingType({
5873
5925
  type: "pitchfork",
5874
5926
  group: "pitchforks",
5875
- label: "Pitchfork",
5927
+ label: msg("drawing.pitchfork.label", "Pitchfork"),
5876
5928
  icon: PITCHFORK_ICON,
5877
5929
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5878
5930
  create: (init) => new Pitchfork(init)
@@ -5883,7 +5935,7 @@ var INSIDE_ICON = svg24('<line x1="4" y1="12" x2="10" y2="12"/><line x1="10" y1=
5883
5935
  registerDrawingType({
5884
5936
  type: "schiffpitchfork",
5885
5937
  group: "pitchforks",
5886
- label: "Schiff Pitchfork",
5938
+ label: msg("drawing.schiffpitchfork.label", "Schiff Pitchfork"),
5887
5939
  icon: SCHIFF_ICON,
5888
5940
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5889
5941
  create: (init) => new SchiffPitchfork(init)
@@ -5891,7 +5943,7 @@ registerDrawingType({
5891
5943
  registerDrawingType({
5892
5944
  type: "modifiedschiffpitchfork",
5893
5945
  group: "pitchforks",
5894
- label: "Modified Schiff Pitchfork",
5946
+ label: msg("drawing.modifiedschiffpitchfork.label", "Modified Schiff Pitchfork"),
5895
5947
  icon: MODSCHIFF_ICON,
5896
5948
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5897
5949
  create: (init) => new ModifiedSchiffPitchfork(init)
@@ -5899,7 +5951,7 @@ registerDrawingType({
5899
5951
  registerDrawingType({
5900
5952
  type: "insidepitchfork",
5901
5953
  group: "pitchforks",
5902
- label: "Inside Pitchfork",
5954
+ label: msg("drawing.insidepitchfork.label", "Inside Pitchfork"),
5903
5955
  icon: INSIDE_ICON,
5904
5956
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5905
5957
  create: (init) => new InsidePitchfork(init)
@@ -5910,7 +5962,7 @@ var TRIANGLE_ICON = svg24('<path d="M12 4 20 19 4 19Z"/>');
5910
5962
  registerDrawingType({
5911
5963
  type: "arrow",
5912
5964
  group: "shapes",
5913
- label: "Arrow",
5965
+ label: msg("drawing.arrow.label", "Arrow"),
5914
5966
  icon: ARROW_ICON,
5915
5967
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", arrowRight: true },
5916
5968
  create: (init) => new Arrow(init)
@@ -5918,7 +5970,7 @@ registerDrawingType({
5918
5970
  registerDrawingType({
5919
5971
  type: "ellipse",
5920
5972
  group: "shapes",
5921
- label: "Ellipse",
5973
+ label: msg("drawing.ellipse.label", "Ellipse"),
5922
5974
  icon: ELLIPSE_ICON,
5923
5975
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}1a` },
5924
5976
  create: (init) => new Ellipse(init)
@@ -5926,7 +5978,7 @@ registerDrawingType({
5926
5978
  registerDrawingType({
5927
5979
  type: "triangle",
5928
5980
  group: "shapes",
5929
- label: "Triangle",
5981
+ label: msg("drawing.triangle.label", "Triangle"),
5930
5982
  icon: TRIANGLE_ICON,
5931
5983
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}1a` },
5932
5984
  create: (init) => new Triangle(init)
@@ -5937,7 +5989,7 @@ var HIGHLIGHTER_ICON = svg24('<path d="M9 11 15 5l4 4-6 6H9Z"/><path d="M9 15l-2
5937
5989
  registerDrawingType({
5938
5990
  type: "polyline",
5939
5991
  group: "shapes",
5940
- label: "Polyline",
5992
+ label: msg("drawing.polyline.label", "Polyline"),
5941
5993
  icon: POLYLINE_ICON,
5942
5994
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5943
5995
  create: (init) => new Polyline(init)
@@ -5945,7 +5997,7 @@ registerDrawingType({
5945
5997
  registerDrawingType({
5946
5998
  type: "freehand",
5947
5999
  group: "shapes",
5948
- label: "Brush",
6000
+ label: msg("drawing.freehand.label", "Brush"),
5949
6001
  icon: FREEHAND_ICON,
5950
6002
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5951
6003
  create: (init) => new Freehand(init)
@@ -5953,7 +6005,7 @@ registerDrawingType({
5953
6005
  registerDrawingType({
5954
6006
  type: "highlighter",
5955
6007
  group: "shapes",
5956
- label: "Highlighter",
6008
+ label: msg("drawing.highlighter.label", "Highlighter"),
5957
6009
  icon: HIGHLIGHTER_ICON,
5958
6010
  // A marker: wide + translucent by default (the alpha in the color is the highlight's see-through).
5959
6011
  defaultStyle: { lineColor: `${MARKER}59`, lineWidth: 14, lineStyle: "solid" },
@@ -5969,7 +6021,7 @@ var ARROW_DOWN_ICON = svg24('<path d="M12 5 12 19"/><path d="M6 13 12 19 18 13"/
5969
6021
  registerDrawingType({
5970
6022
  type: "circle",
5971
6023
  group: "shapes",
5972
- label: "Circle",
6024
+ label: msg("drawing.circle.label", "Circle"),
5973
6025
  icon: CIRCLE_ICON,
5974
6026
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}1a` },
5975
6027
  create: (init) => new Circle(init)
@@ -5977,7 +6029,7 @@ registerDrawingType({
5977
6029
  registerDrawingType({
5978
6030
  type: "rotatedrect",
5979
6031
  group: "shapes",
5980
- label: "Rotated Rectangle",
6032
+ label: msg("drawing.rotatedrect.label", "Rotated Rectangle"),
5981
6033
  icon: ROTRECT_ICON,
5982
6034
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}26` },
5983
6035
  create: (init) => new RotatedRect(init)
@@ -5985,7 +6037,7 @@ registerDrawingType({
5985
6037
  registerDrawingType({
5986
6038
  type: "path",
5987
6039
  group: "shapes",
5988
- label: "Path",
6040
+ label: msg("drawing.path.label", "Path"),
5989
6041
  icon: PATH_ICON,
5990
6042
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
5991
6043
  create: (init) => new Path(init)
@@ -5993,7 +6045,7 @@ registerDrawingType({
5993
6045
  registerDrawingType({
5994
6046
  type: "arc",
5995
6047
  group: "shapes",
5996
- label: "Arc",
6048
+ label: msg("drawing.arc.label", "Arc"),
5997
6049
  icon: ARC_ICON,
5998
6050
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid", fillColor: `${DEFAULT_DRAWING_COLOR}26` },
5999
6051
  create: (init) => new Arc(init)
@@ -6001,7 +6053,7 @@ registerDrawingType({
6001
6053
  registerDrawingType({
6002
6054
  type: "curve",
6003
6055
  group: "shapes",
6004
- label: "Curve",
6056
+ label: msg("drawing.curve.label", "Curve"),
6005
6057
  icon: CURVE_ICON,
6006
6058
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6007
6059
  create: (init) => new Curve(init)
@@ -6009,7 +6061,7 @@ registerDrawingType({
6009
6061
  registerDrawingType({
6010
6062
  type: "arrowmarkup",
6011
6063
  group: "shapes",
6012
- label: "Arrow Mark Up",
6064
+ label: msg("drawing.arrowmarkup.label", "Arrow Mark Up"),
6013
6065
  icon: ARROW_UP_ICON,
6014
6066
  defaultStyle: { lineColor: BULLISH, lineWidth: 1, lineStyle: "solid" },
6015
6067
  create: (init) => new ArrowMarkUp(init)
@@ -6017,7 +6069,7 @@ registerDrawingType({
6017
6069
  registerDrawingType({
6018
6070
  type: "arrowmarkdown",
6019
6071
  group: "shapes",
6020
- label: "Arrow Mark Down",
6072
+ label: msg("drawing.arrowmarkdown.label", "Arrow Mark Down"),
6021
6073
  icon: ARROW_DOWN_ICON,
6022
6074
  defaultStyle: { lineColor: BEARISH, lineWidth: 1, lineStyle: "solid" },
6023
6075
  create: (init) => new ArrowMarkDown(init)
@@ -6027,7 +6079,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.
6027
6079
  registerDrawingType({
6028
6080
  type: "flagmark",
6029
6081
  group: "stamps",
6030
- label: "Flag",
6082
+ label: msg("drawing.flagmark.label", "Flag"),
6031
6083
  icon: FLAG_MARK_ICON,
6032
6084
  defaultStyle: { lineColor: ACCENT, lineWidth: 1, lineStyle: "solid" },
6033
6085
  create: (init) => new FlagMark(init)
@@ -6035,7 +6087,7 @@ registerDrawingType({
6035
6087
  registerDrawingType({
6036
6088
  type: "iconstamp",
6037
6089
  group: "stamps",
6038
- label: "Icon",
6090
+ label: msg("drawing.iconstamp.label", "Icon"),
6039
6091
  icon: ICON_STAMP_ICON,
6040
6092
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6041
6093
  create: (init) => new IconStamp(init)
@@ -6045,7 +6097,7 @@ var FIB_EXTEND_ICON = svg24('<line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1
6045
6097
  registerDrawingType({
6046
6098
  type: "fibretracement",
6047
6099
  group: "fibonacci",
6048
- label: "Fib Retracement",
6100
+ label: msg("drawing.fibretracement.label", "Fib Retracement"),
6049
6101
  icon: FIB_RETRACE_ICON,
6050
6102
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6051
6103
  create: (init) => new FibRetracement(init)
@@ -6053,7 +6105,7 @@ registerDrawingType({
6053
6105
  registerDrawingType({
6054
6106
  type: "fibextension",
6055
6107
  group: "fibonacci",
6056
- label: "Fib Extension",
6108
+ label: msg("drawing.fibextension.label", "Fib Extension"),
6057
6109
  icon: FIB_EXTEND_ICON,
6058
6110
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6059
6111
  create: (init) => new FibExtension(init)
@@ -6062,7 +6114,7 @@ var FIB_TREND_ICON = svg24('<path d="M3 20 10 9l4 5"/><path d="M14 14h7M14 9h7M1
6062
6114
  registerDrawingType({
6063
6115
  type: "fibextensiontrend",
6064
6116
  group: "fibonacci",
6065
- label: "Trend-Based Fib Extension",
6117
+ label: msg("drawing.fibextensiontrend.label", "Trend-Based Fib Extension"),
6066
6118
  icon: FIB_TREND_ICON,
6067
6119
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6068
6120
  create: (init) => new FibExtensionTrend(init)
@@ -6072,7 +6124,7 @@ var FIB_TZ_ICON = svg24('<path d="M3 5v14M6 5v14M11 5v14M19 5v14"/>');
6072
6124
  registerDrawingType({
6073
6125
  type: "fibfan",
6074
6126
  group: "fibonacci",
6075
- label: "Fib Fan",
6127
+ label: msg("drawing.fibfan.label", "Fib Fan"),
6076
6128
  icon: FIB_FAN_ICON,
6077
6129
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6078
6130
  create: (init) => new FibFan(init)
@@ -6080,7 +6132,7 @@ registerDrawingType({
6080
6132
  registerDrawingType({
6081
6133
  type: "fibtimezones",
6082
6134
  group: "fibonacci",
6083
- label: "Fib Time Zones",
6135
+ label: msg("drawing.fibtimezones.label", "Fib Time Zones"),
6084
6136
  icon: FIB_TZ_ICON,
6085
6137
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "dashed" },
6086
6138
  create: (init) => new FibTimeZones(init)
@@ -6091,7 +6143,7 @@ var FIB_TRENDTIME_ICON = svg24('<path d="M3 19 9 8M9 8 12 5v14M14 5v14M18 5v14M2
6091
6143
  registerDrawingType({
6092
6144
  type: "fibchannel",
6093
6145
  group: "fibonacci",
6094
- label: "Fib Channel",
6146
+ label: msg("drawing.fibchannel.label", "Fib Channel"),
6095
6147
  icon: FIB_CHANNEL_ICON,
6096
6148
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6097
6149
  create: (init) => new FibChannel(init)
@@ -6099,7 +6151,7 @@ registerDrawingType({
6099
6151
  registerDrawingType({
6100
6152
  type: "fibspeedfan",
6101
6153
  group: "fibonacci",
6102
- label: "Fib Speed Resistance Fan",
6154
+ label: msg("drawing.fibspeedfan.label", "Fib Speed Resistance Fan"),
6103
6155
  icon: FIB_SPEEDFAN_ICON,
6104
6156
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6105
6157
  create: (init) => new FibSpeedFan(init)
@@ -6107,7 +6159,7 @@ registerDrawingType({
6107
6159
  registerDrawingType({
6108
6160
  type: "trendfibtime",
6109
6161
  group: "fibonacci",
6110
- label: "Trend-Based Fib Time",
6162
+ label: msg("drawing.trendfibtime.label", "Trend-Based Fib Time"),
6111
6163
  icon: FIB_TRENDTIME_ICON,
6112
6164
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "dashed" },
6113
6165
  create: (init) => new TrendFibTime(init)
@@ -6119,7 +6171,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
6119
6171
  registerDrawingType({
6120
6172
  type: "fibcircles",
6121
6173
  group: "fibonacci",
6122
- label: "Fib Circles",
6174
+ label: msg("drawing.fibcircles.label", "Fib Circles"),
6123
6175
  icon: FIB_CIRCLES_ICON,
6124
6176
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6125
6177
  create: (init) => new FibCircles(init)
@@ -6127,7 +6179,7 @@ registerDrawingType({
6127
6179
  registerDrawingType({
6128
6180
  type: "fibarcs",
6129
6181
  group: "fibonacci",
6130
- label: "Fib Speed Resistance Arcs",
6182
+ label: msg("drawing.fibarcs.label", "Fib Speed Resistance Arcs"),
6131
6183
  icon: FIB_ARCS_ICON,
6132
6184
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6133
6185
  create: (init) => new FibArcs(init)
@@ -6135,7 +6187,7 @@ registerDrawingType({
6135
6187
  registerDrawingType({
6136
6188
  type: "fibwedge",
6137
6189
  group: "fibonacci",
6138
- label: "Fib Wedge",
6190
+ label: msg("drawing.fibwedge.label", "Fib Wedge"),
6139
6191
  icon: FIB_WEDGE_ICON,
6140
6192
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6141
6193
  create: (init) => new FibWedge(init)
@@ -6143,7 +6195,7 @@ registerDrawingType({
6143
6195
  registerDrawingType({
6144
6196
  type: "fibspiral",
6145
6197
  group: "fibonacci",
6146
- label: "Fib Spiral",
6198
+ label: msg("drawing.fibspiral.label", "Fib Spiral"),
6147
6199
  icon: FIB_SPIRAL_ICON,
6148
6200
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 2, lineStyle: "solid" },
6149
6201
  create: (init) => new FibSpiral(init)
@@ -6153,7 +6205,7 @@ var GANN_BOX_ICON = svg24('<rect x="4" y="4" width="16" height="16" rx="1"/><pat
6153
6205
  registerDrawingType({
6154
6206
  type: "gannfan",
6155
6207
  group: "fibonacci",
6156
- label: "Gann Fan",
6208
+ label: msg("drawing.gannfan.label", "Gann Fan"),
6157
6209
  icon: GANN_FAN_ICON,
6158
6210
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6159
6211
  create: (init) => new GannFan(init)
@@ -6161,7 +6213,7 @@ registerDrawingType({
6161
6213
  registerDrawingType({
6162
6214
  type: "gannbox",
6163
6215
  group: "fibonacci",
6164
- label: "Gann Box",
6216
+ label: msg("drawing.gannbox.label", "Gann Box"),
6165
6217
  icon: GANN_BOX_ICON,
6166
6218
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6167
6219
  create: (init) => new GannBox(init)
@@ -6170,7 +6222,7 @@ var GANN_SQUARE_ICON = svg24('<rect x="4" y="4" width="16" height="16" rx="1"/><
6170
6222
  registerDrawingType({
6171
6223
  type: "gannsquare",
6172
6224
  group: "fibonacci",
6173
- label: "Gann Square",
6225
+ label: msg("drawing.gannsquare.label", "Gann Square"),
6174
6226
  icon: GANN_SQUARE_ICON,
6175
6227
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6176
6228
  create: (init) => new GannSquare(init)
@@ -6181,7 +6233,7 @@ var DEDEKIND_ICON = svg24(
6181
6233
  registerDrawingType({
6182
6234
  type: "dedekind",
6183
6235
  group: "geometry",
6184
- label: "Dedekind Tessellation",
6236
+ label: msg("drawing.dedekind.label", "Dedekind Tessellation"),
6185
6237
  icon: DEDEKIND_ICON,
6186
6238
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6187
6239
  create: (init) => new DedekindTessellation(init)
@@ -6195,7 +6247,7 @@ var SUPERSONIC_ICON = svg24(
6195
6247
  registerDrawingType({
6196
6248
  type: "sonic",
6197
6249
  group: "geometry",
6198
- label: "Sonic",
6250
+ label: msg("drawing.sonic.label", "Sonic"),
6199
6251
  icon: SONIC_ICON,
6200
6252
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6201
6253
  create: (init) => new Sonic(init)
@@ -6203,7 +6255,7 @@ registerDrawingType({
6203
6255
  registerDrawingType({
6204
6256
  type: "supersonic",
6205
6257
  group: "geometry",
6206
- label: "Supersonic",
6258
+ label: msg("drawing.supersonic.label", "Supersonic"),
6207
6259
  icon: SUPERSONIC_ICON,
6208
6260
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6209
6261
  create: (init) => new Supersonic(init)
@@ -6217,7 +6269,7 @@ var GOLDEN_SUPERSONIC_ICON = svg24(
6217
6269
  registerDrawingType({
6218
6270
  type: "goldensonic",
6219
6271
  group: "geometry",
6220
- label: "Golden Sonic",
6272
+ label: msg("drawing.goldensonic.label", "Golden Sonic"),
6221
6273
  icon: GOLDEN_SONIC_ICON,
6222
6274
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6223
6275
  create: (init) => new GoldenSonic(init)
@@ -6225,7 +6277,7 @@ registerDrawingType({
6225
6277
  registerDrawingType({
6226
6278
  type: "goldensupersonic",
6227
6279
  group: "geometry",
6228
- label: "Golden Supersonic",
6280
+ label: msg("drawing.goldensupersonic.label", "Golden Supersonic"),
6229
6281
  icon: GOLDEN_SUPERSONIC_ICON,
6230
6282
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6231
6283
  create: (init) => new GoldenSupersonic(init)
@@ -6238,7 +6290,7 @@ var HEAD_SHOULDERS_ICON = svg24('<path d="M3 18 6 12 9 16 12 5 15 16 18 12 21 18
6238
6290
  registerDrawingType({
6239
6291
  type: "xabcd",
6240
6292
  group: "patterns",
6241
- label: "XABCD Pattern",
6293
+ label: msg("drawing.xabcd.label", "XABCD Pattern"),
6242
6294
  icon: XABCD_ICON,
6243
6295
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6244
6296
  create: (init) => new XABCD(init)
@@ -6246,7 +6298,7 @@ registerDrawingType({
6246
6298
  registerDrawingType({
6247
6299
  type: "abcd",
6248
6300
  group: "patterns",
6249
- label: "ABCD Pattern",
6301
+ label: msg("drawing.abcd.label", "ABCD Pattern"),
6250
6302
  icon: ABCD_ICON,
6251
6303
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6252
6304
  create: (init) => new ABCDPattern(init)
@@ -6254,7 +6306,7 @@ registerDrawingType({
6254
6306
  registerDrawingType({
6255
6307
  type: "elliottimpulse",
6256
6308
  group: "patterns",
6257
- label: "Elliott Impulse Wave (1-5)",
6309
+ label: msg("drawing.elliottimpulse.label", "Elliott Impulse Wave (1-5)"),
6258
6310
  icon: ELLIOTT_IMPULSE_ICON,
6259
6311
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6260
6312
  create: (init) => new ElliottImpulse(init)
@@ -6262,7 +6314,7 @@ registerDrawingType({
6262
6314
  registerDrawingType({
6263
6315
  type: "elliottcorrection",
6264
6316
  group: "patterns",
6265
- label: "Elliott Correction Wave (ABC)",
6317
+ label: msg("drawing.elliottcorrection.label", "Elliott Correction Wave (ABC)"),
6266
6318
  icon: ELLIOTT_CORRECTION_ICON,
6267
6319
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6268
6320
  create: (init) => new ElliottCorrection(init)
@@ -6270,24 +6322,24 @@ registerDrawingType({
6270
6322
  registerDrawingType({
6271
6323
  type: "headshoulders",
6272
6324
  group: "patterns",
6273
- label: "Head & Shoulders",
6325
+ label: msg("drawing.headshoulders.label", "Head & Shoulders"),
6274
6326
  icon: HEAD_SHOULDERS_ICON,
6275
6327
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6276
6328
  create: (init) => new HeadShoulders(init)
6277
6329
  });
6278
6330
  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"/>');
6279
6331
  var harmonic = { group: "patterns", icon: HARMONIC_ICON, defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" } };
6280
- registerDrawingType({ type: "gartley", label: "Gartley", ...harmonic, create: (init) => new Gartley(init) });
6281
- registerDrawingType({ type: "bat", label: "Bat", ...harmonic, create: (init) => new Bat(init) });
6282
- registerDrawingType({ type: "butterfly", label: "Butterfly", ...harmonic, create: (init) => new Butterfly(init) });
6283
- registerDrawingType({ type: "crab", label: "Crab", ...harmonic, create: (init) => new Crab(init) });
6284
- registerDrawingType({ type: "shark", label: "Shark", ...harmonic, create: (init) => new Shark(init) });
6285
- registerDrawingType({ type: "cypher", label: "Cypher", ...harmonic, create: (init) => new Cypher(init) });
6332
+ registerDrawingType({ type: "gartley", label: msg("drawing.gartley.label", "Gartley"), ...harmonic, create: (init) => new Gartley(init) });
6333
+ registerDrawingType({ type: "bat", label: msg("drawing.bat.label", "Bat"), ...harmonic, create: (init) => new Bat(init) });
6334
+ registerDrawingType({ type: "butterfly", label: msg("drawing.butterfly.label", "Butterfly"), ...harmonic, create: (init) => new Butterfly(init) });
6335
+ registerDrawingType({ type: "crab", label: msg("drawing.crab.label", "Crab"), ...harmonic, create: (init) => new Crab(init) });
6336
+ registerDrawingType({ type: "shark", label: msg("drawing.shark.label", "Shark"), ...harmonic, create: (init) => new Shark(init) });
6337
+ registerDrawingType({ type: "cypher", label: msg("drawing.cypher.label", "Cypher"), ...harmonic, create: (init) => new Cypher(init) });
6286
6338
  var MEASURE_ICON = svg24('<rect x="4" y="6" width="16" height="12" rx="1"/><path d="M4 18 20 6" opacity="0.5"/>');
6287
6339
  registerDrawingType({
6288
6340
  type: "datepricerange",
6289
6341
  group: "measure",
6290
- label: "Date & Price Range",
6342
+ label: msg("drawing.datepricerange.label", "Date & Price Range"),
6291
6343
  icon: MEASURE_ICON,
6292
6344
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6293
6345
  create: (init) => new DatePriceRange(init)
@@ -6298,7 +6350,7 @@ var POSITION_ICON = svg24(
6298
6350
  registerDrawingType({
6299
6351
  type: "position",
6300
6352
  group: "measure",
6301
- label: "Long/Short Position",
6353
+ label: msg("drawing.position.label", "Long/Short Position"),
6302
6354
  icon: POSITION_ICON,
6303
6355
  defaultStyle: { lineColor: DEFAULT_DRAWING_COLOR, lineWidth: 1, lineStyle: "solid" },
6304
6356
  create: (init) => new PositionTool(init)
@@ -6309,21 +6361,21 @@ var MAGNIFIER_ICON = svg24(
6309
6361
  registerDrawingType({
6310
6362
  type: "magnifier",
6311
6363
  group: "measure",
6312
- label: "Magnifier",
6364
+ label: msg("drawing.magnifier.label", "Magnifier"),
6313
6365
  icon: MAGNIFIER_ICON,
6314
6366
  // An empty border color means the THEME's contrast ink (white on dark, black on
6315
6367
  // light), resolved at paint time so it follows theme switches; a user pick wins.
6316
6368
  defaultStyle: { lineColor: "", lineWidth: 1, lineStyle: "solid" },
6317
6369
  coversSeries: true,
6318
6370
  // the inset's backdrop must sit over the base candles it replaces
6319
- placementHint: "Drag an area on the chart to view it at a lower timeframe",
6371
+ placementHint: msg("drawing.magnifier.placementHint", "Drag an area on the chart to view it at a lower timeframe"),
6320
6372
  create: (init) => new Magnifier(init)
6321
6373
  });
6322
6374
  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"/>');
6323
6375
  registerDrawingType({
6324
6376
  type: "anchoredvwap",
6325
6377
  group: "measure",
6326
- label: "Anchored VWAP",
6378
+ label: msg("drawing.anchoredvwap.label", "Anchored VWAP"),
6327
6379
  icon: VWAP_ICON,
6328
6380
  defaultStyle: { lineColor: INFO, lineWidth: 2, lineStyle: "solid" },
6329
6381
  create: (init) => new AnchoredVwap(init)
@@ -6332,7 +6384,7 @@ var FRVP_ICON = svg24('<path d="M4 4v16"/><path d="M4 8h10"/><path d="M4 12h14"/
6332
6384
  registerDrawingType({
6333
6385
  type: "fixedrangevp",
6334
6386
  group: "measure",
6335
- label: "Fixed Range Volume Profile",
6387
+ label: msg("drawing.fixedrangevp.label", "Fixed Range Volume Profile"),
6336
6388
  icon: FRVP_ICON,
6337
6389
  defaultStyle: { lineColor: BULLISH, lineWidth: 1, lineStyle: "solid" },
6338
6390
  create: (init) => new FixedRangeVolumeProfile(init)
@@ -6343,32 +6395,34 @@ var LIQUIDITY_ICON = svg24('<path d="M3 8h12" stroke-dasharray="2.5 2.5"/><path
6343
6395
  registerDrawingType({
6344
6396
  type: "fairvaluegap",
6345
6397
  group: "priceaction",
6346
- label: "Fair Value Gap",
6398
+ label: msg("drawing.fairvaluegap.label", "Fair Value Gap"),
6347
6399
  icon: FVG_ICON,
6348
6400
  defaultStyle: { lineColor: BULLISH, lineWidth: 1, lineStyle: "solid" },
6349
- placementHint: "Click the middle candle of a gap",
6401
+ placementHint: msg("drawing.fairvaluegap.placementHint", "Click the middle candle of a gap"),
6350
6402
  create: (init) => new FairValueGap(init)
6351
6403
  });
6352
6404
  registerDrawingType({
6353
6405
  type: "orderblock",
6354
6406
  group: "priceaction",
6355
- label: "Order Block",
6407
+ label: msg("drawing.orderblock.label", "Order Block"),
6356
6408
  icon: ORDER_BLOCK_ICON,
6357
6409
  defaultStyle: { lineColor: BULLISH, lineWidth: 1, lineStyle: "solid" },
6358
- placementHint: "Click the candle that forms the block",
6410
+ placementHint: msg("drawing.orderblock.placementHint", "Click the candle that forms the block"),
6359
6411
  create: (init) => new OrderBlock(init)
6360
6412
  });
6361
6413
  registerDrawingType({
6362
6414
  type: "liquidity",
6363
6415
  group: "priceaction",
6364
- label: "Liquidity",
6416
+ label: msg("drawing.liquidity.label", "Liquidity"),
6365
6417
  icon: LIQUIDITY_ICON,
6366
6418
  defaultStyle: { lineColor: WARNING, lineWidth: 1, lineStyle: "solid" },
6367
- placementHint: "Click near a candle's high or low",
6419
+ placementHint: msg("drawing.liquidity.placementHint", "Click near a candle's high or low"),
6368
6420
  create: (init) => new Liquidity(init)
6369
6421
  });
6370
6422
 
6371
6423
  // src/chart-types/registry.ts
6424
+ var RANGE_MIN = msg("chart.settings.rangeMin", "{label} — min");
6425
+ var RANGE_MAX = msg("chart.settings.rangeMax", "{label} — max");
6372
6426
  function normalizeSettingsRow(r) {
6373
6427
  switch (r.kind) {
6374
6428
  case "row":
@@ -6390,9 +6444,9 @@ function normalizeSettingsRow(r) {
6390
6444
  return {
6391
6445
  label: r.label,
6392
6446
  controls: [
6393
- { 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 },
6394
- { kind: "hint", text: "\u2013" },
6395
- { 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 }
6447
+ { 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 },
6448
+ { kind: "hint", text: "–" },
6449
+ { 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 }
6396
6450
  ],
6397
6451
  when: r.when
6398
6452
  };
@@ -6465,59 +6519,62 @@ function inputDeltas(schema, values) {
6465
6519
  }
6466
6520
 
6467
6521
  // src/core/timezones.ts
6522
+ function tz(value, name) {
6523
+ return { value, label: sourceText(name), name };
6524
+ }
6468
6525
  var TIMEZONES = [
6469
- { value: "Etc/UTC", label: "UTC" },
6470
- { value: "Etc/GMT+12", label: "International Date Line West" },
6471
- { value: "Pacific/Pago_Pago", label: "Pago Pago" },
6472
- { value: "Pacific/Honolulu", label: "Honolulu" },
6473
- { value: "Pacific/Marquesas", label: "Marquesas Islands" },
6474
- { value: "America/Anchorage", label: "Anchorage" },
6475
- { value: "America/Los_Angeles", label: "Los Angeles" },
6476
- { value: "America/Phoenix", label: "Phoenix" },
6477
- { value: "America/Denver", label: "Denver" },
6478
- { value: "America/Chicago", label: "Chicago" },
6479
- { value: "America/Mexico_City", label: "Mexico City" },
6480
- { value: "America/New_York", label: "New York" },
6481
- { value: "America/Bogota", label: "Bogot\xE1" },
6482
- { value: "America/Caracas", label: "Caracas" },
6483
- { value: "America/Santiago", label: "Santiago" },
6484
- { value: "America/St_Johns", label: "St. John's" },
6485
- { value: "America/Sao_Paulo", label: "S\xE3o Paulo" },
6486
- { value: "America/Argentina/Buenos_Aires", label: "Buenos Aires" },
6487
- { value: "America/Noronha", label: "Fernando de Noronha" },
6488
- { value: "Atlantic/Azores", label: "Azores" },
6489
- { value: "Atlantic/Reykjavik", label: "Reykjavik" },
6490
- { value: "Europe/London", label: "London" },
6491
- { value: "Europe/Paris", label: "Paris" },
6492
- { value: "Europe/Berlin", label: "Berlin" },
6493
- { value: "Europe/Athens", label: "Athens" },
6494
- { value: "Africa/Cairo", label: "Cairo" },
6495
- { value: "Africa/Johannesburg", label: "Johannesburg" },
6496
- { value: "Europe/Moscow", label: "Moscow" },
6497
- { value: "Europe/Istanbul", label: "Istanbul" },
6498
- { value: "Asia/Tehran", label: "Tehran" },
6499
- { value: "Asia/Dubai", label: "Dubai" },
6500
- { value: "Asia/Kabul", label: "Kabul" },
6501
- { value: "Asia/Karachi", label: "Karachi" },
6502
- { value: "Asia/Kolkata", label: "Mumbai" },
6503
- { value: "Asia/Kathmandu", label: "Kathmandu" },
6504
- { value: "Asia/Dhaka", label: "Dhaka" },
6505
- { value: "Asia/Yangon", label: "Yangon" },
6506
- { value: "Asia/Bangkok", label: "Bangkok" },
6507
- { value: "Asia/Shanghai", label: "Shanghai" },
6508
- { value: "Asia/Hong_Kong", label: "Hong Kong" },
6509
- { value: "Asia/Singapore", label: "Singapore" },
6510
- { value: "Australia/Eucla", label: "Eucla" },
6511
- { value: "Asia/Tokyo", label: "Tokyo" },
6512
- { value: "Asia/Seoul", label: "Seoul" },
6513
- { value: "Australia/Adelaide", label: "Adelaide" },
6514
- { value: "Australia/Sydney", label: "Sydney" },
6515
- { value: "Australia/Lord_Howe", label: "Lord Howe Island" },
6516
- { value: "Pacific/Noumea", label: "Noum\xE9a" },
6517
- { value: "Pacific/Auckland", label: "Auckland" },
6518
- { value: "Pacific/Chatham", label: "Chatham Islands" },
6519
- { value: "Pacific/Apia", label: "Apia" },
6520
- { value: "Pacific/Kiritimati", label: "Kiritimati" }
6526
+ tz("Etc/UTC", msg("timezone.Etc.UTC", "UTC")),
6527
+ tz("Etc/GMT+12", msg("timezone.Etc.GMTPlus12", "International Date Line West")),
6528
+ tz("Pacific/Pago_Pago", msg("timezone.Pacific.PagoPago", "Pago Pago")),
6529
+ tz("Pacific/Honolulu", msg("timezone.Pacific.Honolulu", "Honolulu")),
6530
+ tz("Pacific/Marquesas", msg("timezone.Pacific.Marquesas", "Marquesas Islands")),
6531
+ tz("America/Anchorage", msg("timezone.America.Anchorage", "Anchorage")),
6532
+ tz("America/Los_Angeles", msg("timezone.America.LosAngeles", "Los Angeles")),
6533
+ tz("America/Phoenix", msg("timezone.America.Phoenix", "Phoenix")),
6534
+ tz("America/Denver", msg("timezone.America.Denver", "Denver")),
6535
+ tz("America/Chicago", msg("timezone.America.Chicago", "Chicago")),
6536
+ tz("America/Mexico_City", msg("timezone.America.MexicoCity", "Mexico City")),
6537
+ tz("America/New_York", msg("timezone.America.NewYork", "New York")),
6538
+ tz("America/Bogota", msg("timezone.America.Bogota", "Bogotá")),
6539
+ tz("America/Caracas", msg("timezone.America.Caracas", "Caracas")),
6540
+ tz("America/Santiago", msg("timezone.America.Santiago", "Santiago")),
6541
+ tz("America/St_Johns", msg("timezone.America.StJohns", "St. John's")),
6542
+ tz("America/Sao_Paulo", msg("timezone.America.SaoPaulo", "São Paulo")),
6543
+ tz("America/Argentina/Buenos_Aires", msg("timezone.America.Argentina.BuenosAires", "Buenos Aires")),
6544
+ tz("America/Noronha", msg("timezone.America.Noronha", "Fernando de Noronha")),
6545
+ tz("Atlantic/Azores", msg("timezone.Atlantic.Azores", "Azores")),
6546
+ tz("Atlantic/Reykjavik", msg("timezone.Atlantic.Reykjavik", "Reykjavik")),
6547
+ tz("Europe/London", msg("timezone.Europe.London", "London")),
6548
+ tz("Europe/Paris", msg("timezone.Europe.Paris", "Paris")),
6549
+ tz("Europe/Berlin", msg("timezone.Europe.Berlin", "Berlin")),
6550
+ tz("Europe/Athens", msg("timezone.Europe.Athens", "Athens")),
6551
+ tz("Africa/Cairo", msg("timezone.Africa.Cairo", "Cairo")),
6552
+ tz("Africa/Johannesburg", msg("timezone.Africa.Johannesburg", "Johannesburg")),
6553
+ tz("Europe/Moscow", msg("timezone.Europe.Moscow", "Moscow")),
6554
+ tz("Europe/Istanbul", msg("timezone.Europe.Istanbul", "Istanbul")),
6555
+ tz("Asia/Tehran", msg("timezone.Asia.Tehran", "Tehran")),
6556
+ tz("Asia/Dubai", msg("timezone.Asia.Dubai", "Dubai")),
6557
+ tz("Asia/Kabul", msg("timezone.Asia.Kabul", "Kabul")),
6558
+ tz("Asia/Karachi", msg("timezone.Asia.Karachi", "Karachi")),
6559
+ tz("Asia/Kolkata", msg("timezone.Asia.Kolkata", "Mumbai")),
6560
+ tz("Asia/Kathmandu", msg("timezone.Asia.Kathmandu", "Kathmandu")),
6561
+ tz("Asia/Dhaka", msg("timezone.Asia.Dhaka", "Dhaka")),
6562
+ tz("Asia/Yangon", msg("timezone.Asia.Yangon", "Yangon")),
6563
+ tz("Asia/Bangkok", msg("timezone.Asia.Bangkok", "Bangkok")),
6564
+ tz("Asia/Shanghai", msg("timezone.Asia.Shanghai", "Shanghai")),
6565
+ tz("Asia/Hong_Kong", msg("timezone.Asia.HongKong", "Hong Kong")),
6566
+ tz("Asia/Singapore", msg("timezone.Asia.Singapore", "Singapore")),
6567
+ tz("Australia/Eucla", msg("timezone.Australia.Eucla", "Eucla")),
6568
+ tz("Asia/Tokyo", msg("timezone.Asia.Tokyo", "Tokyo")),
6569
+ tz("Asia/Seoul", msg("timezone.Asia.Seoul", "Seoul")),
6570
+ tz("Australia/Adelaide", msg("timezone.Australia.Adelaide", "Adelaide")),
6571
+ tz("Australia/Sydney", msg("timezone.Australia.Sydney", "Sydney")),
6572
+ tz("Australia/Lord_Howe", msg("timezone.Australia.LordHowe", "Lord Howe Island")),
6573
+ tz("Pacific/Noumea", msg("timezone.Pacific.Noumea", "Nouméa")),
6574
+ tz("Pacific/Auckland", msg("timezone.Pacific.Auckland", "Auckland")),
6575
+ tz("Pacific/Chatham", msg("timezone.Pacific.Chatham", "Chatham Islands")),
6576
+ tz("Pacific/Apia", msg("timezone.Pacific.Apia", "Apia")),
6577
+ tz("Pacific/Kiritimati", msg("timezone.Pacific.Kiritimati", "Kiritimati"))
6521
6578
  ];
6522
6579
  var EXCHANGE_TIMEZONE = "exchange";
6523
6580
  function isExchangeTimezone(zone) {
@@ -6530,11 +6587,13 @@ function resolveTimezone(zone, exchangeZone) {
6530
6587
  function normalizeTimezone(zone) {
6531
6588
  return zone === "UTC" || zone === "Etc/UTC" || zone === "Etc/GMT" ? "Etc/UTC" : zone;
6532
6589
  }
6533
- function timezoneMenuRows(current) {
6590
+ function timezoneMenuRows(current, i18n) {
6534
6591
  const active = normalizeTimezone(current);
6535
- const [utc, ...zones] = TIMEZONES.map((t) => ({ value: t.value, label: tzMenuLabel(t.value, t.label), checked: t.value === active }));
6536
- return [utc, { value: EXCHANGE_TIMEZONE, label: "Exchange", checked: isExchangeTimezone(current) }, ...zones];
6592
+ const [utc, ...zones] = TIMEZONES.map((t) => ({ value: t.value, label: tzMenuLabel(t.value, textOf(i18n, t.name), i18n), checked: t.value === active }));
6593
+ return [utc, { value: EXCHANGE_TIMEZONE, label: textOf(i18n, EXCHANGE_LABEL), checked: isExchangeTimezone(current) }, ...zones];
6537
6594
  }
6595
+ var EXCHANGE_LABEL = msg("timezone.exchange", "Exchange");
6596
+ var MENU_LABEL = msg("timezone.menuLabel", "({offset}) {location}");
6538
6597
  function tzOffset(zone, date = /* @__PURE__ */ new Date()) {
6539
6598
  try {
6540
6599
  const parts = new Intl.DateTimeFormat("en-US", { timeZone: zone, timeZoneName: "shortOffset" }).formatToParts(date);
@@ -6549,9 +6608,9 @@ function tzOffset(zone, date = /* @__PURE__ */ new Date()) {
6549
6608
  return "UTC";
6550
6609
  }
6551
6610
  }
6552
- function tzMenuLabel(zone, location) {
6611
+ function tzMenuLabel(zone, location, i18n) {
6553
6612
  if (normalizeTimezone(zone) === "Etc/UTC") return location;
6554
- return `(${tzOffset(zone)}) ${location}`;
6613
+ return textOf(i18n, MENU_LABEL, { offset: tzOffset(zone), location });
6555
6614
  }
6556
6615
  function tzButtonLabel(zone) {
6557
6616
  if (normalizeTimezone(zone) === "Etc/UTC") return "UTC";
@@ -6658,7 +6717,7 @@ function topbarActionOverride(id) {
6658
6717
  }
6659
6718
  function registerWidgetAction(desc) {
6660
6719
  if (builtinTopbarSet.has(desc.id) && !overridableSet.has(desc.id)) {
6661
- 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(", ")}.`);
6720
+ 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(", ")}.`);
6662
6721
  return () => void 0;
6663
6722
  }
6664
6723
  registry3.set(desc.id, desc);
@@ -6694,7 +6753,7 @@ function legendActionsProviderFor(chart, context) {
6694
6753
  const handle = find();
6695
6754
  if (!handle) return [];
6696
6755
  const info = infoOf(handle);
6697
- return legendActions().filter((d) => !d.when || d.when(info)).map((d) => ({ id: d.id, icon: d.icon, tooltip: d.tooltip, run: () => d.run(context(), infoOf(find() ?? handle)) }));
6756
+ return legendActions().filter((d) => !d.when || d.when(info)).map((d) => ({ id: d.id, icon: d.icon, tooltip: textOf(chart.i18n, d.tooltip), run: () => d.run(context(), infoOf(find() ?? handle)) }));
6698
6757
  };
6699
6758
  }
6700
6759
  var calloutRegistry = /* @__PURE__ */ new Map();
@@ -6716,6 +6775,7 @@ function legendCalloutsProviderFor(chart, context) {
6716
6775
  if (!handle) return [];
6717
6776
  const info = { id: handle.id, title: handle.title, ...handle.source !== void 0 ? { source: handle.source } : {} };
6718
6777
  const views = [];
6778
+ const t = (m) => textOf(chart.i18n, m);
6719
6779
  for (const d of legendCallouts()) {
6720
6780
  const spec = d.callout(info);
6721
6781
  if (!spec) continue;
@@ -6724,14 +6784,14 @@ function legendCalloutsProviderFor(chart, context) {
6724
6784
  icon: spec.icon,
6725
6785
  background: spec.background,
6726
6786
  ...spec.color !== void 0 ? { color: spec.color } : {},
6727
- tooltip: spec.tooltip,
6787
+ tooltip: t(spec.tooltip),
6728
6788
  ...spec.content !== void 0 ? {
6729
6789
  content: {
6730
- ...spec.content.title !== void 0 ? { title: spec.content.title } : {},
6790
+ ...spec.content.title !== void 0 ? { title: t(spec.content.title) } : {},
6731
6791
  items: spec.content.items.map(
6732
- (item) => item.type === "text" ? item : {
6792
+ (item) => item.type === "text" ? { type: "text", text: t(item.text) } : {
6733
6793
  type: "button",
6734
- label: item.label,
6794
+ label: t(item.label),
6735
6795
  ...item.primary !== void 0 ? { primary: item.primary } : {},
6736
6796
  ...item.close !== void 0 ? { close: item.close } : {},
6737
6797
  run: () => item.run(context(), info)
@@ -6782,6 +6842,26 @@ function resolveEngines(overrides) {
6782
6842
  }
6783
6843
 
6784
6844
  // src/widget/context-menu-model.ts
6845
+ var TEXT = {
6846
+ regular: msg("widget.contextMenu.scale.regular", "Regular"),
6847
+ percent: msg("widget.contextMenu.scale.percent", "Percent"),
6848
+ indexed: msg("widget.contextMenu.scale.indexed", "Indexed to 100"),
6849
+ log: msg("widget.contextMenu.scale.log", "Logarithmic"),
6850
+ auto: msg("widget.contextMenu.auto", "Auto (fits data to screen)"),
6851
+ invert: msg("widget.contextMenu.invert", "Invert scale"),
6852
+ labels: msg("widget.contextMenu.labels", "Labels"),
6853
+ axisLabels: msg("widget.contextMenu.axisLabels", "Price axis labels"),
6854
+ priceLabel: msg("widget.contextMenu.priceLabel", "Last price label"),
6855
+ countdown: msg("widget.contextMenu.countdown", "Countdown to bar close"),
6856
+ levels: msg("widget.contextMenu.levels", "Levels"),
6857
+ priceLine: msg("widget.contextMenu.priceLine", "Last price line"),
6858
+ moreSettings: msg("widget.contextMenu.moreSettings", "More settings…"),
6859
+ timezone: msg("widget.contextMenu.timezone", "Time zone"),
6860
+ resetView: msg("widget.contextMenu.resetView", "Reset chart view"),
6861
+ removeDrawings: msg("widget.contextMenu.removeDrawings", "Remove drawings"),
6862
+ removeIndicators: msg("widget.contextMenu.removeIndicators", "Remove indicators"),
6863
+ settings: msg("widget.contextMenu.settings", "Settings…")
6864
+ };
6785
6865
  var SETTINGS_SECTION = {
6786
6866
  body: "Canvas",
6787
6867
  "price-axis": "Scales and lines",
@@ -6794,10 +6874,10 @@ function settingsSectionOf(id) {
6794
6874
  return id.slice("settings:".length) || void 0;
6795
6875
  }
6796
6876
  var SCALE_CHOICES = [
6797
- ["regular", "Regular"],
6798
- ["percent", "Percent"],
6799
- ["indexed", "Indexed to 100"],
6800
- ["log", "Logarithmic"]
6877
+ ["regular", TEXT.regular],
6878
+ ["percent", TEXT.percent],
6879
+ ["indexed", TEXT.indexed],
6880
+ ["log", TEXT.log]
6801
6881
  ];
6802
6882
  function paneScaleAt(panes, y) {
6803
6883
  return panes.find((p) => y >= p.top && y < p.top + p.height) ?? panes[0] ?? null;
@@ -6828,50 +6908,52 @@ function scaleWrites(choice, pane) {
6828
6908
  function invertWrite(next, pane) {
6829
6909
  return mainScale(pane) ? ["invertScale", next] : ["invertScale", { pane: pane.id, value: next }];
6830
6910
  }
6831
- function priceAxisItems(s) {
6911
+ function priceAxisItems(s, i18n) {
6912
+ const t = (m) => textOf(i18n, m);
6832
6913
  return [
6833
- { id: "auto", label: "Auto (fits data to screen)", checked: s.auto },
6834
- { id: "invert", label: "Invert scale", checked: s.invert },
6914
+ { id: "auto", label: t(TEXT.auto), checked: s.auto },
6915
+ { id: "invert", label: t(TEXT.invert), checked: s.invert },
6835
6916
  ...SCALE_CHOICES.map(([choice, label], i) => ({
6836
6917
  id: `scale:${choice}`,
6837
- label,
6918
+ label: t(label),
6838
6919
  checked: s.choice === choice,
6839
6920
  separatorBefore: i === 0
6840
6921
  })),
6841
6922
  {
6842
6923
  id: "labels",
6843
- label: "Labels",
6924
+ label: t(TEXT.labels),
6844
6925
  separatorBefore: true,
6845
6926
  submenu: [
6846
- { id: "toggle:axisLabels", label: "Price axis labels", checked: s.axisLabels },
6847
- { id: "toggle:priceLabel", label: "Last price label", checked: s.priceLabel },
6848
- { id: "toggle:countdown", label: "Countdown to bar close", checked: s.countdown }
6927
+ { id: "toggle:axisLabels", label: t(TEXT.axisLabels), checked: s.axisLabels },
6928
+ { id: "toggle:priceLabel", label: t(TEXT.priceLabel), checked: s.priceLabel },
6929
+ { id: "toggle:countdown", label: t(TEXT.countdown), checked: s.countdown }
6849
6930
  ]
6850
6931
  },
6851
6932
  {
6852
6933
  id: "levels",
6853
- label: "Levels",
6854
- submenu: [{ id: "toggle:currentPriceLine", label: "Last Price Line", checked: s.priceLine }]
6934
+ label: t(TEXT.levels),
6935
+ submenu: [{ id: "toggle:currentPriceLine", label: t(TEXT.priceLine), checked: s.priceLine }]
6855
6936
  },
6856
- settingsItem("price-axis", "More settings\u2026")
6937
+ settingsItem("price-axis", t(TEXT.moreSettings))
6857
6938
  ];
6858
6939
  }
6859
- function timeAxisItems(timezone) {
6940
+ function timeAxisItems(timezone, i18n) {
6860
6941
  return [
6861
6942
  {
6862
6943
  id: "timezone",
6863
- label: "Time zone",
6864
- submenu: timezoneMenuRows(timezone).map((r) => ({ id: `tz:${r.value}`, label: r.label, checked: r.checked }))
6944
+ label: textOf(i18n, TEXT.timezone),
6945
+ submenu: timezoneMenuRows(timezone, i18n).map((r) => ({ id: `tz:${r.value}`, label: r.label, checked: r.checked }))
6865
6946
  },
6866
- settingsItem("time-axis", "More settings\u2026")
6947
+ settingsItem("time-axis", textOf(i18n, TEXT.moreSettings))
6867
6948
  ];
6868
6949
  }
6869
- function bodyItems(counts) {
6950
+ function bodyItems(counts, i18n) {
6951
+ const t = (m) => textOf(i18n, m);
6870
6952
  return [
6871
- { id: "reset-view", label: "Reset chart view", icon: "reset" },
6872
- { id: "remove-drawings", label: "Remove drawings", icon: "eraser", disabled: counts.drawings === 0, separatorBefore: true },
6873
- { id: "remove-indicators", label: "Remove indicators", icon: "indicators", disabled: counts.indicators === 0 },
6874
- settingsItem("body", "Settings\u2026", "gear")
6953
+ { id: "reset-view", label: t(TEXT.resetView), icon: "reset" },
6954
+ { id: "remove-drawings", label: t(TEXT.removeDrawings), icon: "eraser", disabled: counts.drawings === 0, separatorBefore: true },
6955
+ { id: "remove-indicators", label: t(TEXT.removeIndicators), icon: "indicators", disabled: counts.indicators === 0 },
6956
+ settingsItem("body", t(TEXT.settings), "gear")
6875
6957
  ];
6876
6958
  }
6877
6959
  var CONTEXT_MENU_BUILTIN_ORDER = {
@@ -6904,6 +6986,13 @@ function composeMenu(zone, builtin, contributed) {
6904
6986
 
6905
6987
  // src/widget/side-panel.ts
6906
6988
  var STYLE_ID = "vela-widget-sidepanel";
6989
+ var TEXT2 = {
6990
+ close: msg("widget.sidePanel.close", "Close"),
6991
+ restore: msg("widget.sidePanel.restore", "Restore"),
6992
+ maximize: msg("widget.sidePanel.maximize", "Maximize"),
6993
+ unpin: msg("widget.sidePanel.unpin", "Unpin — float over the chart"),
6994
+ pin: msg("widget.sidePanel.pin", "Pin beside the chart")
6995
+ };
6907
6996
  var DEFAULT_PANEL_WIDTH = 280;
6908
6997
  var DEFAULT_PANEL_MIN_WIDTH = 200;
6909
6998
  var DEFAULT_PANEL_MAX_WIDTH = 640;
@@ -6980,7 +7069,7 @@ var CSS = `
6980
7069
  }
6981
7070
  .vela-panel-max .vela-icon { width: 15px; height: 15px; }
6982
7071
  .vela-panel-max:hover { background: var(--vela-hover); color: var(--vela-fg-bright); }
6983
- /* MAXIMIZED: the panel covers the whole dock host \u2014 every chart of the shell \u2014 whatever
7072
+ /* MAXIMIZED: the panel covers the whole dock host — every chart of the shell — whatever
6984
7073
  its placement; the width handle and the pin have nothing to do meanwhile. */
6985
7074
  .vela-panel[data-maximized] {
6986
7075
  position: absolute;
@@ -6996,7 +7085,7 @@ var CSS = `
6996
7085
  .vela-panel-body::-webkit-scrollbar { width: 8px; }
6997
7086
  .vela-panel-body::-webkit-scrollbar-thumb { background: var(--vela-scroll); border-radius: 4px; border: 2px solid transparent; background-clip: padding-box; }
6998
7087
  /* Straddles the panel's inner border so the whole seam is grabbable; it paints only under the
6999
- pointer \u2014 a permanently visible bar would read as a second border. */
7088
+ pointer — a permanently visible bar would read as a second border. */
7000
7089
  .vela-panel-resizer {
7001
7090
  position: absolute;
7002
7091
  top: 0;
@@ -7021,7 +7110,7 @@ var CSS = `
7021
7110
  .vela-panel-resizer:hover::after,
7022
7111
  .vela-panel-resizer[data-dragging]::after { background: var(--vela-separator-hover-line); }
7023
7112
  /* An OVERLAY panel floats over the chart's right edge instead of taking a column: the
7024
- chart keeps its width and layout (the dock host is position:relative \u2014 the anchoring the
7113
+ chart keeps its width and layout (the dock host is position:relative — the anchoring the
7025
7114
  mobile rule below relies on too). Same z-order as that mobile overlay, above the chart's
7026
7115
  own DOM overlays; the shadow separates it from the plot it covers. */
7027
7116
  .vela-panel[data-overlay] {
@@ -7033,9 +7122,9 @@ var CSS = `
7033
7122
  z-index: 25;
7034
7123
  box-shadow: var(--vela-shadow);
7035
7124
  }
7036
- /* Mobile: a 280px column would crush a phone-width chart \u2014 the panel overlays the
7125
+ /* Mobile: a 280px column would crush a phone-width chart — the panel overlays the
7037
7126
  chart area instead (its flex parent is position:relative), full-bleed, closed by
7038
- the same header \u2715. Width dragging is a pointer affordance; off on mobile. */
7127
+ the same header ✕. Width dragging is a pointer affordance; off on mobile. */
7039
7128
  [data-layout='mobile'] .vela-panel {
7040
7129
  position: absolute;
7041
7130
  inset: 0;
@@ -7078,6 +7167,8 @@ var SidePanel = class {
7078
7167
  /** The exit animation of a close; a reopen cancels it. */
7079
7168
  this.exit = null;
7080
7169
  const doc = host.ownerDocument;
7170
+ this.i18n = opts.i18n ?? null;
7171
+ this.title = title;
7081
7172
  injectStyles(STYLE_ID, CSS, doc);
7082
7173
  this.minWidth = opts.resizable ? opts.minWidth ?? DEFAULT_PANEL_MIN_WIDTH : 1;
7083
7174
  this.maxWidth = opts.resizable ? opts.maxWidth ?? DEFAULT_PANEL_MAX_WIDTH : Number.POSITIVE_INFINITY;
@@ -7094,13 +7185,14 @@ var SidePanel = class {
7094
7185
  header.className = "vela-panel-header";
7095
7186
  this.heading = doc.createElement("span");
7096
7187
  this.heading.className = "vela-panel-title";
7097
- this.heading.textContent = title;
7188
+ this.heading.textContent = this.t(title);
7098
7189
  this.slot = doc.createElement("div");
7099
7190
  this.slot.className = "vela-panel-header-slot";
7100
7191
  const close = doc.createElement("button");
7192
+ this.closeButton = close;
7101
7193
  close.className = "vela-panel-close";
7102
7194
  close.appendChild(iconEl("close", doc));
7103
- close.title = "Close";
7195
+ close.title = this.t(TEXT2.close);
7104
7196
  close.addEventListener("click", () => this.toggle(false));
7105
7197
  if (this.floatable) {
7106
7198
  this.pin = doc.createElement("button");
@@ -7181,7 +7273,7 @@ var SidePanel = class {
7181
7273
  if (!this.maxButton) return;
7182
7274
  const doc = this.maxButton.ownerDocument;
7183
7275
  this.maxButton.replaceChildren(iconEl(this.maximizedOn ? "restore" : "maximize", doc));
7184
- this.maxButton.title = this.maximizedOn ? "Restore" : "Maximize";
7276
+ this.maxButton.title = this.t(this.maximizedOn ? TEXT2.restore : TEXT2.maximize);
7185
7277
  this.maxButton.setAttribute("aria-label", this.maxButton.title);
7186
7278
  this.maxButton.setAttribute("aria-pressed", this.maximizedOn ? "true" : "false");
7187
7279
  }
@@ -7198,7 +7290,19 @@ var SidePanel = class {
7198
7290
  /** Replace the header title. The topbar toggle keeps the DECLARED title as its
7199
7291
  * tooltip — this only changes what the open column says about itself. */
7200
7292
  setTitle(title) {
7201
- this.heading.textContent = title;
7293
+ this.title = title;
7294
+ this.heading.textContent = this.t(title);
7295
+ }
7296
+ /** Text in the shell's language. */
7297
+ t(text, values) {
7298
+ return textOf(this.i18n, text, values);
7299
+ }
7300
+ /** Re-read the header in the current language; a panel with its own text extends it. */
7301
+ relocalize() {
7302
+ this.heading.textContent = this.t(this.title);
7303
+ this.closeButton.title = this.t(TEXT2.close);
7304
+ this.refreshPin();
7305
+ this.refreshMaxButton();
7202
7306
  }
7203
7307
  /** Current width in px. */
7204
7308
  get width() {
@@ -7230,7 +7334,7 @@ var SidePanel = class {
7230
7334
  const doc = this.pin.ownerDocument;
7231
7335
  this.pin.replaceChildren(iconEl(pinned ? "pin-filled" : "pin", doc));
7232
7336
  this.pin.dataset.on = pinned ? "1" : "0";
7233
- this.pin.title = pinned ? "Unpin \u2014 float over the chart" : "Pin beside the chart";
7337
+ this.pin.title = this.t(pinned ? TEXT2.unpin : TEXT2.pin);
7234
7338
  this.pin.setAttribute("aria-label", this.pin.title);
7235
7339
  this.pin.setAttribute("aria-pressed", pinned ? "true" : "false");
7236
7340
  }
@@ -7281,4 +7385,4 @@ var SidePanel = class {
7281
7385
  }
7282
7386
  };
7283
7387
 
7284
- export { AnchoredVwap, ArrowMark, CONTEXT_MENU_BUILTIN_ORDER, Callout, CalloutBase, Comment, DEDEKIND_CURVATURE_OPTIONS, DEFAULT_DRAWING_COLOR, DEFAULT_PANEL_MAX_WIDTH, DEFAULT_PANEL_MIN_WIDTH, DEFAULT_PANEL_ORDER, DEFAULT_PANEL_WIDTH, DIRECTION_OPTIONS, DedekindTessellation, Drawing, FIB_PRESETS, FibLevels, FibRatios, FibRetracement, FibSpiral, FixedRangeVolumeProfile, GANN_SQUARE_ARCS, GLYPH_OPTIONS, GannSquare, GlyphStamp, LINE_STYLE_OPTIONS, Liquidity, MACH_NUMBER_OPTIONS, MACH_WAVE_COUNT_OPTIONS, MachFigure, Magnifier, MeasureBox, Note, OVERRIDABLE_TOPBAR_IDS, PatternDrawing, PositionTool, PriceActionZone, PriceLabel, PriceNote, RadialFib, RegressionChannel, STAMP_SIZE_OPTIONS, SegmentDrawing, SidePanel, Signpost, TEXT_SIZE_OPTIONS, TIMEFRAME_BANDS, TIMEZONES, TOPBAR_BUILTIN_IDS, TOPBAR_DEFAULT_LEFT, TOPBAR_DEFAULT_RIGHT, TextLabel, TrendLine, bodyItems, chartType, chartTypes, clampPanelWidth, composeMenu, createDrawing, defaultText, deserializeDrawing, drawingTypes, foldBaseModulation, formatDuration, getDrawingType, getNativeIndicator, inputDeltas, inputVisible, invertWrite, isExchangeTimezone, isLineLikeSeries, legendActions, legendActionsProviderFor, legendCallouts, legendCalloutsProviderFor, lineSegmentIntersection, magnifierTimeframeLabel, magnifierTimeframesBelow, matchFibPreset, mobilePlacement, nativeIndicatorDescriptors, nativeIndicatorTypes, nativeInstanceChannel, normalizeSettingsRow, normalizeTimezone, paneScaleAt, pinnedTopbarActionIds, priceAxisItems, registerChartType, registerDefaultEngine, registerDrawingType, registerLegendAction, registerLegendCallout, registerNativeIndicator, registerRendererDefaults, registerRendererLayer, registerSidePanel, registerStatePersistence, registerSymbolRanking, registerWidgetAction, registerWidgetAttachment, rendererDefaults, rendererLayers, resetDrawingSettings, resolveEngines, resolveTimezone, resolveTopbarComposition, sanitizeShowOn, scaleChoiceOf, scaleWrites, seriesInScale, seriesShownOn, settingsRowValueKeys, settingsRowVisible, settingsSectionOf, shownOnTimeframe, sidePanels, stableSeriesId, statePersistenceHandlers, symbolRanking, tickerModifierIds, timeAxisItems, timeframeBandOf, timezoneMenuRows, topbarActionOverride, topbarHas, tzButtonLabel, tzMenuLabel, tzOffset, unregisterChartType, unregisterDefaultEngine, unregisterLegendAction, unregisterLegendCallout, unregisterNativeIndicator, unregisterRendererDefaults, unregisterRendererLayer, unregisterSidePanel, unregisterStatePersistence, unregisterWidgetAction, unregisterWidgetAttachment, widgetActions, widgetAttachments };
7388
+ export { AnchoredVwap, ArrowMark, CONTEXT_MENU_BUILTIN_ORDER, Callout, CalloutBase, Comment, DEDEKIND_CURVATURE_OPTIONS, DEFAULT_DRAWING_COLOR, DEFAULT_PANEL_MAX_WIDTH, DEFAULT_PANEL_MIN_WIDTH, DEFAULT_PANEL_ORDER, DEFAULT_PANEL_WIDTH, DIRECTION_OPTIONS, DedekindTessellation, Drawing, FIB_PRESETS, FibLevels, FibRatios, FibRetracement, FibSpiral, FixedRangeVolumeProfile, GANN_SQUARE_ARCS, GLYPH_OPTIONS, GannSquare, GlyphStamp, LINE_STYLE_OPTIONS, Liquidity, MACH_NUMBER_OPTIONS, MACH_WAVE_COUNT_OPTIONS, MachFigure, Magnifier, MeasureBox, Note, OVERRIDABLE_TOPBAR_IDS, PatternDrawing, PositionTool, PriceActionZone, PriceLabel, PriceNote, RadialFib, RegressionChannel, STAMP_SIZE_OPTIONS, SegmentDrawing, SidePanel, Signpost, TEXT_SIZE_OPTIONS, TIMEFRAME_BANDS, TIMEZONES, TOPBAR_BUILTIN_IDS, TOPBAR_DEFAULT_LEFT, TOPBAR_DEFAULT_RIGHT, TextLabel, TrendLine, bodyItems, chartType, chartTypes, clampPanelWidth, composeMenu, createDrawing, defaultText, deserializeDrawing, drawingTypeEntries, drawingTypeEntry, drawingTypes, foldBaseModulation, getDrawingType, getNativeIndicator, inputDeltas, inputVisible, invertWrite, isExchangeTimezone, isLineLikeSeries, legendActions, legendActionsProviderFor, legendCallouts, legendCalloutsProviderFor, lineSegmentIntersection, magnifierTimeframeLabel, magnifierTimeframesBelow, matchFibPreset, mobilePlacement, nativeIndicatorDescriptors, nativeIndicatorEntries, nativeIndicatorEntry, nativeIndicatorTypes, nativeInstanceChannel, normalizeSettingsRow, normalizeTimezone, paneScaleAt, pinnedTopbarActionIds, priceAxisItems, registerChartType, registerDefaultEngine, registerDrawingType, registerLegendAction, registerLegendCallout, registerNativeIndicator, registerRendererDefaults, registerRendererLayer, registerSidePanel, registerStatePersistence, registerSymbolRanking, registerWidgetAction, registerWidgetAttachment, rendererDefaults, rendererLayers, resetDrawingSettings, resolveEngines, resolveTimezone, resolveTopbarComposition, sanitizeShowOn, scaleChoiceOf, scaleWrites, seriesInScale, seriesShownOn, settingsRowValueKeys, settingsRowVisible, settingsSectionOf, shownOnTimeframe, sidePanels, stableSeriesId, statePersistenceHandlers, symbolRanking, tickerModifierIds, timeAxisItems, timeframeBandOf, timezoneMenuRows, topbarActionOverride, topbarHas, tzButtonLabel, tzMenuLabel, tzOffset, unregisterChartType, unregisterDefaultEngine, unregisterLegendAction, unregisterLegendCallout, unregisterNativeIndicator, unregisterRendererDefaults, unregisterRendererLayer, unregisterSidePanel, unregisterStatePersistence, unregisterWidgetAction, unregisterWidgetAttachment, widgetActions, widgetAttachments };