@deriv-web-design/ui 0.1.35 → 0.1.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -52,10 +52,17 @@ __export(index_exports, {
52
52
  CryptoMarketsTable: () => CryptoMarketsTable,
53
53
  CryptoTradeConverter: () => CryptoTradeConverter,
54
54
  DEFAULT_AWARDS: () => DEFAULT_AWARDS,
55
+ DEFAULT_CRYPTO_MARKETS_TABLE_LABELS: () => DEFAULT_CRYPTO_MARKETS_TABLE_LABELS,
56
+ DEFAULT_CRYPTO_MARKETS_TABLE_TITLE: () => DEFAULT_CRYPTO_MARKETS_TABLE_TITLE,
57
+ DEFAULT_CRYPTO_TRADE_CONVERTER_LABELS: () => DEFAULT_CRYPTO_TRADE_CONVERTER_LABELS,
58
+ DEFAULT_CRYPTO_TRADE_CONVERTER_SUBTITLE: () => DEFAULT_CRYPTO_TRADE_CONVERTER_SUBTITLE,
59
+ DEFAULT_CRYPTO_TRADE_CONVERTER_TITLE: () => DEFAULT_CRYPTO_TRADE_CONVERTER_TITLE,
55
60
  DEFAULT_CULTURE_CARDS: () => DEFAULT_CULTURE_CARDS,
56
61
  DEFAULT_EXCHANGE_RATE_WS_URL: () => DEFAULT_EXCHANGE_RATE_WS_URL,
57
62
  DEFAULT_SYMBOLS_ENDPOINT: () => DEFAULT_SYMBOLS_ENDPOINT,
58
63
  DEFAULT_TRADE_HREF: () => DEFAULT_TRADE_HREF,
64
+ DEFAULT_TRADING_CALCULATOR_HOWTO_LABELS: () => DEFAULT_TRADING_CALCULATOR_HOWTO_LABELS,
65
+ DEFAULT_TRADING_CALCULATOR_LABELS: () => DEFAULT_TRADING_CALCULATOR_LABELS,
59
66
  DayNightTransition: () => DayNightTransition,
60
67
  DocumentChips: () => DocumentChips,
61
68
  DotLottieInView: () => DotLottieInView,
@@ -8321,7 +8328,55 @@ var ParallaxBanner = ({
8321
8328
 
8322
8329
  // templates/TradingCalculator/TradingCalculator.tsx
8323
8330
  var import_react34 = require("react");
8331
+
8332
+ // templates/TradingCalculator/TradingCalculator.types.ts
8333
+ var DEFAULT_TRADING_CALCULATOR_LABELS = {
8334
+ calculatorPanel: "Calculator",
8335
+ resultsPanel: "Results",
8336
+ calculate: "Calculate",
8337
+ calculating: "Calculating\u2026",
8338
+ reset: "Reset",
8339
+ symbols: "Symbols",
8340
+ volume: "Volume in Lots",
8341
+ assetPrice: "Asset price",
8342
+ contractSize: "Contract size",
8343
+ pipSize: "Pip size",
8344
+ effectiveLeverage: "Effective Leverage",
8345
+ pointSize: "Point size",
8346
+ marginRequired: "Margin Required",
8347
+ tradeVolume: "Trade Volume",
8348
+ pipValue: "Pip value",
8349
+ swapChargeLong: "Swap Charge Long",
8350
+ swapChargeShort: "Swap Charge Short",
8351
+ swapLongRate: "Swap long rate",
8352
+ swapShortRate: "Swap short rate",
8353
+ swapCalculationType: "Swap calculation type",
8354
+ threeDaySwap: "Three-day swap",
8355
+ weekendSwaps: "Weekend swaps",
8356
+ threeDaySwapFallback: "No",
8357
+ loadingSymbols: "Loading symbols\u2026",
8358
+ symbolsUnavailable: "Symbols unavailable",
8359
+ searchSymbolPlaceholder: "Search symbol, e.g. EURUSD",
8360
+ symbolsLoadError: "Unable to load symbols.",
8361
+ retry: "Retry",
8362
+ selectSymbolError: "Select a symbol to continue.",
8363
+ volumeRequiredError: "Enter a valid volume in lots.",
8364
+ volumePositiveError: "Volume must be greater than 0.",
8365
+ volumeRangeError: "Volume must be between {min} and {max} lots.",
8366
+ assetPriceError: "Enter a valid asset price.",
8367
+ exchangeRateError: "Unable to fetch live exchange rates. Please try again.",
8368
+ exchangeRateErrorWithMessage: "Unable to fetch live exchange rates ({message}). Please try again.",
8369
+ noSymbolsMatch: 'No symbols match "{query}"'
8370
+ };
8371
+
8372
+ // templates/TradingCalculator/TradingCalculator.tsx
8324
8373
  var import_jsx_runtime60 = require("react/jsx-runtime");
8374
+ function fillTemplate2(template, values) {
8375
+ return template.replace(/\{(\w+)\}/g, (_, key) => values[key] ?? "");
8376
+ }
8377
+ function mergeLabels(overrides) {
8378
+ return { ...DEFAULT_TRADING_CALCULATOR_LABELS, ...overrides };
8379
+ }
8325
8380
  var DEFAULT_SYMBOLS_ENDPOINT = "https://deriv-static-pricingfeedv2.firebaseio.com/n8n/row/prod/dynamic_trading_specs.json";
8326
8381
  var DEFAULT_EXCHANGE_RATE_WS_URL = "wss://ws.derivws.com/websockets/v3?app_id=1089";
8327
8382
  var USD = "USD";
@@ -8481,7 +8536,15 @@ function groupByAssetClass(symbols) {
8481
8536
  }
8482
8537
  return [...groups.entries()];
8483
8538
  }
8484
- var SymbolCombobox = ({ symbolsState, onRetry, selected, onSelect, error, inputId }) => {
8539
+ var SymbolCombobox = ({
8540
+ symbolsState,
8541
+ onRetry,
8542
+ selected,
8543
+ onSelect,
8544
+ error,
8545
+ inputId,
8546
+ copy
8547
+ }) => {
8485
8548
  const [query, setQuery] = (0, import_react34.useState)("");
8486
8549
  const [isOpen, setIsOpen] = (0, import_react34.useState)(false);
8487
8550
  const [activeIndex, setActiveIndex] = (0, import_react34.useState)(-1);
@@ -8539,7 +8602,8 @@ var SymbolCombobox = ({ symbolsState, onRetry, selected, onSelect, error, inputI
8539
8602
  {
8540
8603
  id: inputId,
8541
8604
  label: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
8542
- "Symbols ",
8605
+ copy.symbols,
8606
+ " ",
8543
8607
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "tcalc-required", children: "*" })
8544
8608
  ] }),
8545
8609
  role: "combobox",
@@ -8554,7 +8618,7 @@ var SymbolCombobox = ({ symbolsState, onRetry, selected, onSelect, error, inputI
8554
8618
  disabled: isLoading || isError,
8555
8619
  hideClearButton: true,
8556
8620
  trailingSlot: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ChevronIcon3, {}),
8557
- placeholder: isLoading ? "Loading symbols\u2026" : isError ? "Symbols unavailable" : "Search symbol, e.g. EURUSD",
8621
+ placeholder: isLoading ? copy.loadingSymbols : isError ? copy.symbolsUnavailable : copy.searchSymbolPlaceholder,
8558
8622
  value: displayValue,
8559
8623
  onFocus: () => setIsOpen(true),
8560
8624
  onChange: (event) => {
@@ -8566,11 +8630,7 @@ var SymbolCombobox = ({ symbolsState, onRetry, selected, onSelect, error, inputI
8566
8630
  }
8567
8631
  ),
8568
8632
  isOpen && !isLoading && !isError && /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "tcalc-dropdown", id: listboxId, role: "listbox", children: [
8569
- grouped.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("p", { className: "tcalc-dropdownEmpty", children: [
8570
- 'No symbols match "',
8571
- query,
8572
- '"'
8573
- ] }),
8633
+ grouped.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { className: "tcalc-dropdownEmpty", children: fillTemplate2(copy.noSymbolsMatch, { query }) }),
8574
8634
  grouped.map(([assetClass, items]) => /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "tcalc-dropdownGroup", children: [
8575
8635
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { className: "tcalc-dropdownGroupTitle", children: assetClass }),
8576
8636
  items.map((item) => {
@@ -8602,9 +8662,10 @@ var SymbolCombobox = ({ symbolsState, onRetry, selected, onSelect, error, inputI
8602
8662
  ] }),
8603
8663
  isError && /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("p", { className: "tcalc-fieldError", children: [
8604
8664
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ErrorIcon, {}),
8605
- " Unable to load symbols.",
8606
8665
  " ",
8607
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("button", { type: "button", className: "tcalc-retryLink", onClick: onRetry, children: "Retry" })
8666
+ copy.symbolsLoadError,
8667
+ " ",
8668
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("button", { type: "button", className: "tcalc-retryLink", onClick: onRetry, children: copy.retry })
8608
8669
  ] }),
8609
8670
  !isError && error && /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("p", { className: "tcalc-fieldError", children: [
8610
8671
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ErrorIcon, {}),
@@ -8632,9 +8693,11 @@ var TradingCalculator = ({
8632
8693
  symbolsEndpoint = DEFAULT_SYMBOLS_ENDPOINT,
8633
8694
  exchangeRateWsUrl = DEFAULT_EXCHANGE_RATE_WS_URL,
8634
8695
  defaultSymbol,
8696
+ labels: labelsProp,
8635
8697
  className,
8636
8698
  ...props
8637
8699
  }) => {
8700
+ const copy = mergeLabels(labelsProp);
8638
8701
  const showMargin = variant === "main" || variant === "margin";
8639
8702
  const showPip = variant === "main" || variant === "pip";
8640
8703
  const showSwap = variant === "main" || variant === "swap";
@@ -8678,15 +8741,18 @@ var TradingCalculator = ({
8678
8741
  const volume = Number.parseFloat(volumeInLots);
8679
8742
  const price = Number.parseFloat(assetPrice);
8680
8743
  const nextErrors = {};
8681
- if (!selectedSymbol) nextErrors.symbol = "Select a symbol to continue.";
8744
+ if (!selectedSymbol) nextErrors.symbol = copy.selectSymbolError;
8682
8745
  if (!volumeInLots || Number.isNaN(volume)) {
8683
- nextErrors.volume = "Enter a valid volume in lots.";
8746
+ nextErrors.volume = copy.volumeRequiredError;
8684
8747
  } else if (volume <= 0) {
8685
- nextErrors.volume = "Volume must be greater than 0.";
8748
+ nextErrors.volume = copy.volumePositiveError;
8686
8749
  } else if (selectedSymbol && (volume < selectedSymbol.volume_min || volume > selectedSymbol.volume_limit)) {
8687
- nextErrors.volume = `Volume must be between ${selectedSymbol.volume_min} and ${selectedSymbol.volume_limit} lots.`;
8750
+ nextErrors.volume = fillTemplate2(copy.volumeRangeError, {
8751
+ min: String(selectedSymbol.volume_min),
8752
+ max: String(selectedSymbol.volume_limit)
8753
+ });
8688
8754
  }
8689
- if (!assetPrice || Number.isNaN(price) || price <= 0) nextErrors.price = "Enter a valid asset price.";
8755
+ if (!assetPrice || Number.isNaN(price) || price <= 0) nextErrors.price = copy.assetPriceError;
8690
8756
  setErrors(nextErrors);
8691
8757
  if (Object.keys(nextErrors).length > 0 || !selectedSymbol) return;
8692
8758
  setCalcError(null);
@@ -8697,7 +8763,7 @@ var TradingCalculator = ({
8697
8763
  setResults(computeResults(selectedSymbol, volume, price, rates));
8698
8764
  } catch (error) {
8699
8765
  setCalcError(
8700
- error instanceof Error ? `Unable to fetch live exchange rates (${error.message}). Please try again.` : "Unable to fetch live exchange rates. Please try again."
8766
+ error instanceof Error ? fillTemplate2(copy.exchangeRateErrorWithMessage, { message: error.message }) : copy.exchangeRateError
8701
8767
  );
8702
8768
  } finally {
8703
8769
  setIsCalculating(false);
@@ -8708,7 +8774,7 @@ var TradingCalculator = ({
8708
8774
  const priceInputId = (0, import_react34.useId)();
8709
8775
  return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("section", { className: ["tcalc-section", className ?? ""].filter(Boolean).join(" "), ...props, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "tcalc-container", children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "tcalc-card", children: [
8710
8776
  /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "tcalc-column", children: [
8711
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("h3", { className: "tcalc-panelTitle", children: "Calculator" }),
8777
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("h3", { className: "tcalc-panelTitle", children: copy.calculatorPanel }),
8712
8778
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8713
8779
  SymbolCombobox,
8714
8780
  {
@@ -8717,20 +8783,21 @@ var TradingCalculator = ({
8717
8783
  selected: selectedSymbol,
8718
8784
  onSelect: handleSelectSymbol,
8719
8785
  error: errors.symbol,
8720
- inputId: symbolInputId
8786
+ inputId: symbolInputId,
8787
+ copy
8721
8788
  }
8722
8789
  ),
8723
8790
  /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "tcalc-infoGrid", children: [
8724
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { label: "Contract size", value: selectedSymbol ? integerFormatter.format(selectedSymbol.contract_size) : "-" }),
8725
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { label: "Pip size", value: selectedSymbol ? String(selectedSymbol.pip_size) : "-" }),
8791
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { label: copy.contractSize, value: selectedSymbol ? integerFormatter.format(selectedSymbol.contract_size) : "-" }),
8792
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { label: copy.pipSize, value: selectedSymbol ? String(selectedSymbol.pip_size) : "-" }),
8726
8793
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8727
8794
  InfoRow,
8728
8795
  {
8729
- label: "Effective Leverage",
8796
+ label: copy.effectiveLeverage,
8730
8797
  value: selectedSymbol ? `1 : ${Math.round((selectedSymbol.effective_leverage + Number.EPSILON) * 100) / 100}` : "-"
8731
8798
  }
8732
8799
  ),
8733
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { label: "Point size", value: selectedSymbol ? String(selectedSymbol.point_size) : "-" })
8800
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { label: copy.pointSize, value: selectedSymbol ? String(selectedSymbol.point_size) : "-" })
8734
8801
  ] }),
8735
8802
  /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "tcalc-field", children: [
8736
8803
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
@@ -8739,7 +8806,8 @@ var TradingCalculator = ({
8739
8806
  id: volumeInputId,
8740
8807
  className: "tcalc-numberField",
8741
8808
  label: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
8742
- "Volume in Lots ",
8809
+ copy.volume,
8810
+ " ",
8743
8811
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "tcalc-required", children: "*" })
8744
8812
  ] }),
8745
8813
  status: errors.volume ? "fail" : "neutral",
@@ -8756,7 +8824,7 @@ var TradingCalculator = ({
8756
8824
  const isNegative = value !== "" && !Number.isNaN(parsed) && parsed <= 0;
8757
8825
  setErrors((prev) => ({
8758
8826
  ...prev,
8759
- volume: isNegative ? "Volume must be greater than 0." : void 0
8827
+ volume: isNegative ? copy.volumePositiveError : void 0
8760
8828
  }));
8761
8829
  }
8762
8830
  }
@@ -8774,7 +8842,8 @@ var TradingCalculator = ({
8774
8842
  id: priceInputId,
8775
8843
  className: "tcalc-numberField",
8776
8844
  label: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
8777
- "Asset price ",
8845
+ copy.assetPrice,
8846
+ " ",
8778
8847
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "tcalc-required", children: "*" })
8779
8848
  ] }),
8780
8849
  status: errors.price ? "fail" : "neutral",
@@ -8803,7 +8872,7 @@ var TradingCalculator = ({
8803
8872
  type: "button",
8804
8873
  colorScheme: "coral",
8805
8874
  variant: "primary",
8806
- label: isCalculating ? "Calculating\u2026" : "Calculate",
8875
+ label: isCalculating ? copy.calculating : copy.calculate,
8807
8876
  onClick: handleCalculate,
8808
8877
  disabled: isCalculating,
8809
8878
  fullWidth: true
@@ -8815,7 +8884,7 @@ var TradingCalculator = ({
8815
8884
  type: "button",
8816
8885
  colorScheme: "black",
8817
8886
  variant: "secondary",
8818
- label: "Reset",
8887
+ label: copy.reset,
8819
8888
  onClick: handleReset,
8820
8889
  fullWidth: true
8821
8890
  }
@@ -8823,16 +8892,16 @@ var TradingCalculator = ({
8823
8892
  ] })
8824
8893
  ] }),
8825
8894
  /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "tcalc-column tcalc-column--results", children: [
8826
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("h3", { className: "tcalc-panelTitle", children: "Results" }),
8827
- showMargin && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ResultBox, { label: "Margin Required", value: results ? formatMoney(results.marginRequired) : "$" }),
8895
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("h3", { className: "tcalc-panelTitle", children: copy.resultsPanel }),
8896
+ showMargin && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ResultBox, { label: copy.marginRequired, value: results ? formatMoney(results.marginRequired) : "$" }),
8828
8897
  showTradeVolume && showPip && /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "tcalc-resultRow", children: [
8829
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ResultBox, { label: "Trade Volume", value: results ? formatInteger(results.tradeVolume) : "$" }),
8830
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ResultBox, { label: "Pip value", value: results ? formatMoney(results.pipValue) : "$" })
8898
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ResultBox, { label: copy.tradeVolume, value: results ? formatInteger(results.tradeVolume) : "$" }),
8899
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ResultBox, { label: copy.pipValue, value: results ? formatMoney(results.pipValue) : "$" })
8831
8900
  ] }),
8832
- !showTradeVolume && showPip && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ResultBox, { label: "Pip value", value: results ? formatMoney(results.pipValue) : "$" }),
8901
+ !showTradeVolume && showPip && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ResultBox, { label: copy.pipValue, value: results ? formatMoney(results.pipValue) : "$" }),
8833
8902
  showSwap && /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "tcalc-resultRow", children: [
8834
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ResultBox, { label: "Swap Charge Long", value: results ? formatMoney(results.swapChargeLong) : "$" }),
8835
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ResultBox, { label: "Swap Charge Short", value: results ? formatMoney(results.swapChargeShort) : "$" })
8903
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ResultBox, { label: copy.swapChargeLong, value: results ? formatMoney(results.swapChargeLong) : "$" }),
8904
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ResultBox, { label: copy.swapChargeShort, value: results ? formatMoney(results.swapChargeShort) : "$" })
8836
8905
  ] }),
8837
8906
  calcError && /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("p", { className: "tcalc-fieldError tcalc-calcError", children: [
8838
8907
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ErrorIcon, {}),
@@ -8841,12 +8910,12 @@ var TradingCalculator = ({
8841
8910
  ] }),
8842
8911
  showSwap && /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
8843
8912
  /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "tcalc-infoGrid", children: [
8844
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { label: "Swap long rate", value: selectedSymbol ? String(selectedSymbol.swap_rate_long) : "-" }),
8845
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { label: "Swap short rate", value: selectedSymbol ? String(selectedSymbol.swap_rate_short) : "-" })
8913
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { label: copy.swapLongRate, value: selectedSymbol ? String(selectedSymbol.swap_rate_long) : "-" }),
8914
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { label: copy.swapShortRate, value: selectedSymbol ? String(selectedSymbol.swap_rate_short) : "-" })
8846
8915
  ] }),
8847
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { separator: ":", label: "Swap calculation type", value: selectedSymbol ? selectedSymbol.swap_mode : "-" }),
8848
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { separator: ":", label: "Three-day swap", value: selectedSymbol ? selectedSymbol.three_day_swap || "No" : "-" }),
8849
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { separator: ":", label: "Weekend swaps", value: selectedSymbol ? String(selectedSymbol.weekend_swaps ?? "-") : "-" })
8916
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { separator: ":", label: copy.swapCalculationType, value: selectedSymbol ? selectedSymbol.swap_mode : "-" }),
8917
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { separator: ":", label: copy.threeDaySwap, value: selectedSymbol ? selectedSymbol.three_day_swap || copy.threeDaySwapFallback : "-" }),
8918
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(InfoRow, { separator: ":", label: copy.weekendSwaps, value: selectedSymbol ? String(selectedSymbol.weekend_swaps ?? "-") : "-" })
8850
8919
  ] })
8851
8920
  ] })
8852
8921
  ] }) }) });
@@ -8854,7 +8923,53 @@ var TradingCalculator = ({
8854
8923
 
8855
8924
  // templates/TradingCalculatorHowTo/TradingCalculatorHowTo.tsx
8856
8925
  var import_react35 = require("react");
8926
+
8927
+ // templates/TradingCalculatorHowTo/TradingCalculatorHowTo.types.ts
8928
+ var DEFAULT_TRADING_CALCULATOR_HOWTO_LABELS = {
8929
+ formulaHeading: "Formula",
8930
+ exampleHeading: "Example",
8931
+ swapTabPoints: "Swap calculation (In points)",
8932
+ swapTabPercentage: "Swap calculation (In percentage)"
8933
+ };
8934
+
8935
+ // templates/TradingCalculatorHowTo/TradingCalculatorHowTo.tsx
8857
8936
  var import_jsx_runtime61 = require("react/jsx-runtime");
8937
+ function applyContentLabels(base, overrides) {
8938
+ if (!overrides) {
8939
+ return {
8940
+ ...base,
8941
+ formulaHeading: DEFAULT_TRADING_CALCULATOR_HOWTO_LABELS.formulaHeading,
8942
+ exampleHeading: DEFAULT_TRADING_CALCULATOR_HOWTO_LABELS.exampleHeading
8943
+ };
8944
+ }
8945
+ return {
8946
+ ...base,
8947
+ formulaHeading: overrides.formulaHeading ?? DEFAULT_TRADING_CALCULATOR_HOWTO_LABELS.formulaHeading,
8948
+ exampleHeading: overrides.exampleHeading ?? DEFAULT_TRADING_CALCULATOR_HOWTO_LABELS.exampleHeading,
8949
+ formulaBlocks: overrides.formulaBlocks ?? base.formulaBlocks,
8950
+ exampleIntro: overrides.exampleIntro ?? base.exampleIntro,
8951
+ exampleLead: overrides.exampleLead ?? base.exampleLead,
8952
+ calculations: overrides.calculations ?? base.calculations,
8953
+ resultText: overrides.resultText ?? base.resultText,
8954
+ note: overrides.note ?? base.note
8955
+ };
8956
+ }
8957
+ function bodyLabelsForMode(labels, isSwap, swapTab) {
8958
+ if (!labels) return void 0;
8959
+ const flat = {
8960
+ formulaHeading: labels.formulaHeading,
8961
+ exampleHeading: labels.exampleHeading,
8962
+ formulaBlocks: labels.formulaBlocks,
8963
+ exampleIntro: labels.exampleIntro,
8964
+ exampleLead: labels.exampleLead,
8965
+ calculations: labels.calculations,
8966
+ resultText: labels.resultText,
8967
+ note: labels.note
8968
+ };
8969
+ if (!isSwap) return flat;
8970
+ const tabSpecific = swapTab === "percentage" ? labels.swapPercentage : labels.swapPoints;
8971
+ return { ...flat, ...tabSpecific };
8972
+ }
8858
8973
  var MARGIN_CONTENT = {
8859
8974
  title: "How to calculate margin requirements",
8860
8975
  description: "Use this formula to calculate how much margin is required based on your lot size, leverage ratio, and the current market price.",
@@ -8999,11 +9114,15 @@ var SWAP_PERCENTAGE_CONTENT = {
8999
9114
  ],
9000
9115
  resultText: "This means the swap charge is USD -0.26 to keep the position open overnight."
9001
9116
  };
9002
- var SWAP_TABS = [
9003
- { id: "points", label: "Swap calculation (In points)" },
9004
- { id: "percentage", label: "Swap calculation (In percentage)" }
9005
- ];
9006
9117
  var swapModeForVariant = (variant) => variant === "swap-percentage" ? "percentage" : "points";
9118
+ function swapTabsForLabels(labels) {
9119
+ const points = labels?.swapTabPoints ?? DEFAULT_TRADING_CALCULATOR_HOWTO_LABELS.swapTabPoints;
9120
+ const percentage = labels?.swapTabPercentage ?? DEFAULT_TRADING_CALCULATOR_HOWTO_LABELS.swapTabPercentage;
9121
+ return [
9122
+ { id: "points", label: points },
9123
+ { id: "percentage", label: percentage }
9124
+ ];
9125
+ }
9007
9126
  var useIsomorphicLayoutEffect = typeof window !== "undefined" ? import_react35.useLayoutEffect : import_react35.useEffect;
9008
9127
  var FormulaBlockView = ({ block }) => {
9009
9128
  if (block.type === "footnote") {
@@ -9106,6 +9225,7 @@ var TradingCalculatorHowTo = ({
9106
9225
  variant = "margin",
9107
9226
  title,
9108
9227
  description,
9228
+ labels,
9109
9229
  className,
9110
9230
  ...props
9111
9231
  }) => {
@@ -9114,9 +9234,14 @@ var TradingCalculatorHowTo = ({
9114
9234
  (0, import_react35.useEffect)(() => {
9115
9235
  setSwapTab(swapModeForVariant(variant));
9116
9236
  }, [variant]);
9117
- const content = variant === "pip" ? PIP_CONTENT : isSwap ? swapTab === "percentage" ? SWAP_PERCENTAGE_CONTENT : SWAP_POINTS_CONTENT : MARGIN_CONTENT;
9237
+ const baseContent = variant === "pip" ? PIP_CONTENT : isSwap ? swapTab === "percentage" ? SWAP_PERCENTAGE_CONTENT : SWAP_POINTS_CONTENT : MARGIN_CONTENT;
9238
+ const content = applyContentLabels(
9239
+ baseContent,
9240
+ bodyLabelsForMode(labels, isSwap, swapTab)
9241
+ );
9118
9242
  const heading = title ?? content.title;
9119
9243
  const desc = description ?? content.description;
9244
+ const swapTabs = swapTabsForLabels(labels);
9120
9245
  return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("section", { className: ["tchow-section", className ?? ""].filter(Boolean).join(" "), ...props, children: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "tchow-container", children: [
9121
9246
  /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "tchow-intro", children: [
9122
9247
  /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("h2", { className: "tchow-title", children: heading }),
@@ -9126,7 +9251,7 @@ var TradingCalculatorHowTo = ({
9126
9251
  Tabs,
9127
9252
  {
9128
9253
  className: "tchow-tabs",
9129
- items: SWAP_TABS,
9254
+ items: swapTabs,
9130
9255
  activeId: swapTab,
9131
9256
  onChange: (id) => setSwapTab(id)
9132
9257
  }
@@ -9444,9 +9569,11 @@ function browserSupportsMarketStreaming() {
9444
9569
 
9445
9570
  // templates/cryptoMarketData/conversion.ts
9446
9571
  function convertAmounts(options) {
9572
+ const waitingForPrice = options.messages?.waitingForPrice ?? "Waiting for a live price";
9573
+ const invalidAmount = options.messages?.invalidAmount ?? "Enter a valid amount";
9447
9574
  const price = options.price;
9448
9575
  if (price == null || !Number.isFinite(price) || price <= 0) {
9449
- return { pay: options.payInput, receive: options.receiveInput, valid: false, error: "Waiting for a live price" };
9576
+ return { pay: options.payInput, receive: options.receiveInput, valid: false, error: waitingForPrice };
9450
9577
  }
9451
9578
  const source = options.edited === "pay" ? options.payInput : options.receiveInput;
9452
9579
  const trimmed = source.trim();
@@ -9459,7 +9586,7 @@ function convertAmounts(options) {
9459
9586
  pay: options.payInput,
9460
9587
  receive: options.receiveInput,
9461
9588
  valid: false,
9462
- error: "Enter a valid amount"
9589
+ error: invalidAmount
9463
9590
  };
9464
9591
  }
9465
9592
  if (options.side === "buy") {
@@ -10004,9 +10131,39 @@ function useCryptoMarketData(options) {
10004
10131
  return snapshot;
10005
10132
  }
10006
10133
 
10134
+ // templates/CryptoTradeConverter/CryptoTradeConverter.types.ts
10135
+ var DEFAULT_CRYPTO_TRADE_CONVERTER_TITLE = "Buy and sell in seconds";
10136
+ var DEFAULT_CRYPTO_TRADE_CONVERTER_SUBTITLE = "Choose your asset, enter an amount, and confirm. Your crypto lands in your account instantly, ready to trade, hold, or withdraw whenever you want.";
10137
+ var DEFAULT_CRYPTO_TRADE_CONVERTER_LABELS = {
10138
+ buy: "Buy",
10139
+ sell: "Sell",
10140
+ connecting: "Connecting to live prices\u2026",
10141
+ livePrices: "Live prices",
10142
+ waitingForPrice: "Waiting for a live price",
10143
+ unsupportedBrowser: "Please use a current browser to view live prices.",
10144
+ selectMarket: "Select a market",
10145
+ chooseMarket: "Choose a market",
10146
+ tradeSideGroup: "Trade side",
10147
+ youPay: "You pay",
10148
+ youReceive: "You receive",
10149
+ amountToSpend: "Amount to spend",
10150
+ primaryAmountAria: "Primary trade amount",
10151
+ convertedAmountAria: "Converted trade amount",
10152
+ estimateTemplate: "Estimate at 1 {base} = {price} {quote}. Fees and spread excluded.",
10153
+ change24hSuffix: "(24h)",
10154
+ waitingForLivePrice: "Waiting for live price\u2026",
10155
+ invalidAmount: "Enter a valid amount"
10156
+ };
10157
+
10007
10158
  // templates/CryptoTradeConverter/CryptoTradeConverter.tsx
10008
10159
  var import_jsx_runtime62 = require("react/jsx-runtime");
10009
10160
  var DEFAULT_TRADE_HREF = "https://deriv.exchange";
10161
+ function fillTemplate3(template, values) {
10162
+ return template.replace(/\{(\w+)\}/g, (_, key) => values[key] ?? "");
10163
+ }
10164
+ function mergeLabels2(overrides) {
10165
+ return { ...DEFAULT_CRYPTO_TRADE_CONVERTER_LABELS, ...overrides };
10166
+ }
10010
10167
  function matchPair(rows, defaultPair) {
10011
10168
  if (!rows.length) return null;
10012
10169
  if (!defaultPair) {
@@ -10059,8 +10216,12 @@ var CryptoTradeConverter = ({
10059
10216
  defaultPair,
10060
10217
  tradeHref = DEFAULT_TRADE_HREF,
10061
10218
  apiOrigin,
10219
+ title = DEFAULT_CRYPTO_TRADE_CONVERTER_TITLE,
10220
+ subtitle = DEFAULT_CRYPTO_TRADE_CONVERTER_SUBTITLE,
10221
+ labels: labelsProp,
10062
10222
  className
10063
10223
  }) => {
10224
+ const copy = mergeLabels2(labelsProp);
10064
10225
  const reactId = (0, import_react37.useId)().replace(/:/g, "");
10065
10226
  const listboxId = `ctc-listbox-${reactId}`;
10066
10227
  const payId = `ctc-pay-${reactId}`;
@@ -10088,9 +10249,13 @@ var CryptoTradeConverter = ({
10088
10249
  price: selected?.last ?? null,
10089
10250
  payInput: pay,
10090
10251
  receiveInput: receive,
10091
- edited
10252
+ edited,
10253
+ messages: {
10254
+ waitingForPrice: copy.waitingForPrice,
10255
+ invalidAmount: copy.invalidAmount
10256
+ }
10092
10257
  }),
10093
- [side, selected?.last, pay, receive, edited]
10258
+ [side, selected?.last, pay, receive, edited, copy.waitingForPrice, copy.invalidAmount]
10094
10259
  );
10095
10260
  (0, import_react37.useEffect)(() => {
10096
10261
  if (edited === "pay") setReceive(conversion.receive);
@@ -10161,8 +10326,12 @@ var CryptoTradeConverter = ({
10161
10326
  const changeClass = selected?.change24hPct == null ? "" : selected.change24hPct >= 0 ? "ctc-change--up" : "ctc-change--down";
10162
10327
  const payValue = edited === "pay" ? pay : conversion.pay;
10163
10328
  const receiveValue = edited === "receive" ? receive : conversion.receive;
10164
- const receiveMeta = priceReady && selected ? `Estimate at 1 ${selected.base} = ${formatPrice(selected.last, selected.pricePrecision)} ${selected.quote}. Fees and spread excluded.` : snapshot.status === "unsupported" ? "Please use a current browser to view live prices." : conversion.error || (snapshot.status === "idle" || snapshot.status === "connecting" ? "Connecting to live prices\u2026" : "Waiting for live price\u2026");
10165
- const ctaLabel = side === "buy" ? "Buy" : "Sell";
10329
+ const receiveMeta = priceReady && selected ? fillTemplate3(copy.estimateTemplate, {
10330
+ base: selected.base,
10331
+ price: formatPrice(selected.last, selected.pricePrecision),
10332
+ quote: selected.quote
10333
+ }) : snapshot.status === "unsupported" ? copy.unsupportedBrowser : conversion.error || (snapshot.status === "idle" || snapshot.status === "connecting" ? copy.connecting : copy.waitingForLivePrice);
10334
+ const ctaLabel = side === "buy" ? copy.buy : copy.sell;
10166
10335
  const ctaClass = ["ctc-cta__btn", side === "sell" ? "is-sell" : "is-buy"].join(" ");
10167
10336
  return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
10168
10337
  "section",
@@ -10174,8 +10343,8 @@ var CryptoTradeConverter = ({
10174
10343
  "aria-labelledby": `ctc-heading-${reactId}`,
10175
10344
  children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "ctc-container", children: [
10176
10345
  /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("header", { className: "ctc-header", children: [
10177
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("h2", { id: `ctc-heading-${reactId}`, className: "ctc-title", children: "Buy and sell in seconds" }),
10178
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("p", { className: "ctc-subtitle", children: "Choose your asset, enter an amount, and confirm. Your crypto lands in your account instantly, ready to trade, hold, or withdraw whenever you want." })
10346
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("h2", { id: `ctc-heading-${reactId}`, className: "ctc-title", children: title }),
10347
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("p", { className: "ctc-subtitle", children: subtitle })
10179
10348
  ] }),
10180
10349
  /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ctc-card", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "ctc-widget", children: [
10181
10350
  /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
@@ -10187,7 +10356,7 @@ var CryptoTradeConverter = ({
10187
10356
  "aria-live": "polite",
10188
10357
  children: [
10189
10358
  /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "ctc-status-dot", "aria-hidden": "true" }),
10190
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { children: snapshot.status === "idle" || snapshot.status === "connecting" ? "Connecting to live prices\u2026" : snapshot.statusMessage || (priceReady ? "Live prices" : "Waiting for live price\u2026") })
10359
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { children: snapshot.status === "idle" || snapshot.status === "connecting" ? copy.connecting : snapshot.statusMessage || (priceReady ? copy.livePrices : copy.waitingForLivePrice) })
10191
10360
  ]
10192
10361
  }
10193
10362
  ),
@@ -10227,12 +10396,13 @@ var CryptoTradeConverter = ({
10227
10396
  " ",
10228
10397
  /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { className: ["ctc-change", changeClass].filter(Boolean).join(" "), children: [
10229
10398
  formatPct(selected.change24hPct),
10230
- " (24h)"
10399
+ " ",
10400
+ copy.change24hSuffix
10231
10401
  ] })
10232
10402
  ] })
10233
10403
  ] })
10234
10404
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { className: "ctc-pair__meta", children: [
10235
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "ctc-pair__name", children: "Select a market" }),
10405
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "ctc-pair__name", children: copy.selectMarket }),
10236
10406
  /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "ctc-pair__price", children: "\u2014" })
10237
10407
  ] }),
10238
10408
  /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(ChevronIcon4, { className: "ctc-pair__chevron" })
@@ -10246,11 +10416,11 @@ var CryptoTradeConverter = ({
10246
10416
  id: listboxId,
10247
10417
  className: "ctc-listbox",
10248
10418
  role: "listbox",
10249
- "aria-label": "Choose a market",
10419
+ "aria-label": copy.chooseMarket,
10250
10420
  tabIndex: -1,
10251
10421
  onKeyDown: onPickerKeyDown,
10252
10422
  children: [
10253
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("li", { className: "ctc-listbox__header", role: "presentation", children: "Choose a market" }),
10423
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("li", { className: "ctc-listbox__header", role: "presentation", children: copy.chooseMarket }),
10254
10424
  sortedRows.map((row, index) => {
10255
10425
  const selectedOption = selected?.id === row.id;
10256
10426
  const active = index === activeOption;
@@ -10290,7 +10460,7 @@ var CryptoTradeConverter = ({
10290
10460
  }
10291
10461
  ) : null
10292
10462
  ] }),
10293
- /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "ctc-seg", role: "group", "aria-label": "Trade side", children: [
10463
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "ctc-seg", role: "group", "aria-label": copy.tradeSideGroup, children: [
10294
10464
  /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
10295
10465
  "button",
10296
10466
  {
@@ -10298,7 +10468,7 @@ var CryptoTradeConverter = ({
10298
10468
  className: side === "buy" ? "ctc-seg__btn is-active is-buy" : "ctc-seg__btn is-buy",
10299
10469
  "aria-pressed": side === "buy",
10300
10470
  onClick: () => setSide("buy"),
10301
- children: "Buy"
10471
+ children: copy.buy
10302
10472
  }
10303
10473
  ),
10304
10474
  /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
@@ -10308,7 +10478,7 @@ var CryptoTradeConverter = ({
10308
10478
  className: side === "sell" ? "ctc-seg__btn is-active is-sell" : "ctc-seg__btn is-sell",
10309
10479
  "aria-pressed": side === "sell",
10310
10480
  onClick: () => setSide("sell"),
10311
- children: "Sell"
10481
+ children: copy.sell
10312
10482
  }
10313
10483
  )
10314
10484
  ] }),
@@ -10319,7 +10489,7 @@ var CryptoTradeConverter = ({
10319
10489
  className: ["ctc-amount", conversion.error ? "is-invalid" : ""].filter(Boolean).join(" "),
10320
10490
  htmlFor: payId,
10321
10491
  children: [
10322
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "ctc-amount__label", children: "You pay" }),
10492
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "ctc-amount__label", children: copy.youPay }),
10323
10493
  /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { className: "ctc-amount__row", children: [
10324
10494
  /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
10325
10495
  "input",
@@ -10331,7 +10501,7 @@ var CryptoTradeConverter = ({
10331
10501
  autoComplete: "off",
10332
10502
  placeholder: "0.00",
10333
10503
  value: payValue,
10334
- "aria-label": "Primary trade amount",
10504
+ "aria-label": copy.primaryAmountAria,
10335
10505
  "aria-invalid": Boolean(conversion.error),
10336
10506
  "aria-describedby": statusId,
10337
10507
  onChange: (event) => {
@@ -10342,7 +10512,7 @@ var CryptoTradeConverter = ({
10342
10512
  ),
10343
10513
  /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "ctc-amount__unit", children: labels.pay })
10344
10514
  ] }),
10345
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "ctc-amount__meta", children: "Amount to spend" })
10515
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "ctc-amount__meta", children: copy.amountToSpend })
10346
10516
  ]
10347
10517
  }
10348
10518
  ),
@@ -10352,7 +10522,7 @@ var CryptoTradeConverter = ({
10352
10522
  className: ["ctc-amount", conversion.error ? "is-invalid" : ""].filter(Boolean).join(" "),
10353
10523
  htmlFor: receiveId,
10354
10524
  children: [
10355
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "ctc-amount__label", children: "You receive" }),
10525
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "ctc-amount__label", children: copy.youReceive }),
10356
10526
  /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { className: "ctc-amount__row", children: [
10357
10527
  /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
10358
10528
  "input",
@@ -10364,7 +10534,7 @@ var CryptoTradeConverter = ({
10364
10534
  autoComplete: "off",
10365
10535
  placeholder: "0.00",
10366
10536
  value: receiveValue,
10367
- "aria-label": "Converted trade amount",
10537
+ "aria-label": copy.convertedAmountAria,
10368
10538
  "aria-invalid": Boolean(conversion.error),
10369
10539
  "aria-describedby": `ctc-rate-${reactId}`,
10370
10540
  onChange: (event) => {
@@ -10407,7 +10577,37 @@ var CryptoTradeConverter = ({
10407
10577
 
10408
10578
  // templates/CryptoMarketsTable/CryptoMarketsTable.tsx
10409
10579
  var import_react38 = require("react");
10580
+
10581
+ // templates/CryptoMarketsTable/CryptoMarketsTable.types.ts
10582
+ var DEFAULT_CRYPTO_MARKETS_TABLE_TITLE = "Explore the markets";
10583
+ var DEFAULT_CRYPTO_MARKETS_TABLE_LABELS = {
10584
+ spot: "Spot",
10585
+ futures: "Futures",
10586
+ live: "Live",
10587
+ connecting: "Connecting\u2026",
10588
+ marketTypeGroup: "Market type",
10589
+ quoteCurrencyTabs: "Quote currency",
10590
+ scrollRegion: "Market prices. Scroll horizontally to see all columns.",
10591
+ columnName: "Name",
10592
+ columnPrice: "Price",
10593
+ column1h: "1h %",
10594
+ column24h: "24h %",
10595
+ column7d: "7d chart",
10596
+ unsupportedBrowser: "Please use a current browser to view market prices.",
10597
+ loadError: "Unable to load market data. Retrying\u2026",
10598
+ loading: "Loading market data\u2026",
10599
+ emptyPairsTemplate: "No {quote} pairs on {kind} yet\u2026",
10600
+ sparklineAriaTemplate: "{name} available hourly price history, up to 7 days"
10601
+ };
10602
+
10603
+ // templates/CryptoMarketsTable/CryptoMarketsTable.tsx
10410
10604
  var import_jsx_runtime63 = require("react/jsx-runtime");
10605
+ function fillTemplate4(template, values) {
10606
+ return template.replace(/\{(\w+)\}/g, (_, key) => values[key] ?? "");
10607
+ }
10608
+ function mergeLabels3(overrides) {
10609
+ return { ...DEFAULT_CRYPTO_MARKETS_TABLE_LABELS, ...overrides };
10610
+ }
10411
10611
  function CoinAvatar2({ base, icon }) {
10412
10612
  const [failed, setFailed] = (0, import_react38.useState)(false);
10413
10613
  if (failed) {
@@ -10513,8 +10713,11 @@ var CryptoMarketsTable = ({
10513
10713
  initialQuoteCurrency = "USDT",
10514
10714
  apiOrigin,
10515
10715
  maxRows,
10716
+ title = DEFAULT_CRYPTO_MARKETS_TABLE_TITLE,
10717
+ labels: labelsProp,
10516
10718
  className
10517
10719
  }) => {
10720
+ const copy = mergeLabels3(labelsProp);
10518
10721
  const reactId = (0, import_react38.useId)().replace(/:/g, "");
10519
10722
  const [kind, setKind] = (0, import_react38.useState)(initialMarket);
10520
10723
  const [quote, setQuote] = (0, import_react38.useState)(initialQuoteCurrency.toUpperCase());
@@ -10561,7 +10764,14 @@ var CryptoMarketsTable = ({
10561
10764
  }
10562
10765
  };
10563
10766
  const statusTone = snapshot.status === "live" ? "live" : snapshot.status === "reconnecting" || snapshot.status === "stale" ? "warn" : snapshot.status === "error" || snapshot.status === "unsupported" ? "error" : "muted";
10564
- const emptyMessage = snapshot.status === "unsupported" ? "Please use a current browser to view market prices." : snapshot.status === "error" ? "Unable to load market data. Retrying\u2026" : snapshot.status === "connecting" || snapshot.status === "idle" ? "Loading market data\u2026" : `No ${quote} pairs on ${kind} yet\u2026`;
10767
+ const emptyMessage = snapshot.status === "unsupported" ? copy.unsupportedBrowser : snapshot.status === "error" ? copy.loadError : snapshot.status === "connecting" || snapshot.status === "idle" ? copy.loading : fillTemplate4(copy.emptyPairsTemplate, { quote, kind });
10768
+ const columnLabels = [
10769
+ ["name", copy.columnName],
10770
+ ["last", copy.columnPrice],
10771
+ ["change1hPct", copy.column1h],
10772
+ ["change24hPct", copy.column24h],
10773
+ ["change7dPct", copy.column7d]
10774
+ ];
10565
10775
  return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
10566
10776
  "section",
10567
10777
  {
@@ -10570,26 +10780,26 @@ var CryptoMarketsTable = ({
10570
10780
  "aria-labelledby": `cmt-heading-${reactId}`,
10571
10781
  children: /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "cmt-container", children: [
10572
10782
  /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("header", { className: "cmt-header", children: [
10573
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("h2", { id: `cmt-heading-${reactId}`, className: "cmt-title", children: "Explore the markets" }),
10783
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("h2", { id: `cmt-heading-${reactId}`, className: "cmt-title", children: title }),
10574
10784
  /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("p", { className: `cmt-status cmt-status--${statusTone}`, role: "status", "aria-live": "polite", children: [
10575
10785
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "cmt-status-dot", "aria-hidden": "true" }),
10576
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { children: snapshot.status === "live" ? "Live" : snapshot.statusMessage || "Connecting\u2026" })
10786
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { children: snapshot.status === "live" ? copy.live : snapshot.statusMessage || copy.connecting })
10577
10787
  ] })
10578
10788
  ] }),
10579
10789
  /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "cmt-card", children: [
10580
10790
  /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "cmt-toolbar", children: [
10581
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "cmt-seg", role: "group", "aria-label": "Market type", children: ["spot", "futures"].map((value) => /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
10791
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "cmt-seg", role: "group", "aria-label": copy.marketTypeGroup, children: ["spot", "futures"].map((value) => /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
10582
10792
  "button",
10583
10793
  {
10584
10794
  type: "button",
10585
10795
  className: kind === value ? "cmt-seg__btn is-active" : "cmt-seg__btn",
10586
10796
  "aria-pressed": kind === value,
10587
10797
  onClick: () => setKind(value),
10588
- children: value === "spot" ? "Spot" : "Futures"
10798
+ children: value === "spot" ? copy.spot : copy.futures
10589
10799
  },
10590
10800
  value
10591
10801
  )) }),
10592
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "cmt-tabs", role: "tablist", "aria-label": "Quote currency", children: snapshot.quotes.map((q) => /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
10802
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "cmt-tabs", role: "tablist", "aria-label": copy.quoteCurrencyTabs, children: snapshot.quotes.map((q) => /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
10593
10803
  "button",
10594
10804
  {
10595
10805
  type: "button",
@@ -10609,15 +10819,9 @@ var CryptoMarketsTable = ({
10609
10819
  className: ["cmt-scroll", scrolled ? "is-scrolled" : ""].filter(Boolean).join(" "),
10610
10820
  tabIndex: 0,
10611
10821
  role: "region",
10612
- "aria-label": "Market prices. Scroll horizontally to see all columns.",
10822
+ "aria-label": copy.scrollRegion,
10613
10823
  children: /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("table", { className: "cmt-table", children: [
10614
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("tr", { children: [
10615
- ["name", "Name"],
10616
- ["last", "Price"],
10617
- ["change1hPct", "1h %"],
10618
- ["change24hPct", "24h %"],
10619
- ["change7dPct", "7d chart"]
10620
- ].map(([key, label]) => {
10824
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("tr", { children: columnLabels.map(([key, label]) => {
10621
10825
  const active = sortKey === key;
10622
10826
  return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
10623
10827
  "th",
@@ -10662,7 +10866,9 @@ var CryptoMarketsTable = ({
10662
10866
  {
10663
10867
  values: row.spark7d,
10664
10868
  up: (row.change7dPct ?? 0) >= 0,
10665
- label: `${row.name} available hourly price history, up to 7 days`,
10869
+ label: fillTemplate4(copy.sparklineAriaTemplate, {
10870
+ name: row.name
10871
+ }),
10666
10872
  reducedMotion
10667
10873
  }
10668
10874
  ) })
@@ -12315,10 +12521,17 @@ var AffiliatesSlider = ({
12315
12521
  CryptoMarketsTable,
12316
12522
  CryptoTradeConverter,
12317
12523
  DEFAULT_AWARDS,
12524
+ DEFAULT_CRYPTO_MARKETS_TABLE_LABELS,
12525
+ DEFAULT_CRYPTO_MARKETS_TABLE_TITLE,
12526
+ DEFAULT_CRYPTO_TRADE_CONVERTER_LABELS,
12527
+ DEFAULT_CRYPTO_TRADE_CONVERTER_SUBTITLE,
12528
+ DEFAULT_CRYPTO_TRADE_CONVERTER_TITLE,
12318
12529
  DEFAULT_CULTURE_CARDS,
12319
12530
  DEFAULT_EXCHANGE_RATE_WS_URL,
12320
12531
  DEFAULT_SYMBOLS_ENDPOINT,
12321
12532
  DEFAULT_TRADE_HREF,
12533
+ DEFAULT_TRADING_CALCULATOR_HOWTO_LABELS,
12534
+ DEFAULT_TRADING_CALCULATOR_LABELS,
12322
12535
  DayNightTransition,
12323
12536
  DocumentChips,
12324
12537
  DotLottieInView,