@kashi-ui/elements 0.26.0 → 1.1.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 (72) hide show
  1. package/README.md +9 -0
  2. package/dist/appointment.js +13 -12
  3. package/dist/base.d.ts +408 -0
  4. package/dist/base.js +29 -0
  5. package/dist/basic.js +8 -9
  6. package/dist/calendar.js +21 -20
  7. package/dist/cdn/appointment-CrIZi8Bp.js +1 -0
  8. package/dist/cdn/base-DTQ50VdG.js +1 -0
  9. package/dist/cdn/basic-CrEW2RKF.js +1 -0
  10. package/dist/cdn/calendar-CYRrdGIf.js +16 -0
  11. package/dist/cdn/charts-D6KM26Vp.js +1 -0
  12. package/dist/cdn/combobox-6EFI2qqN.js +1 -0
  13. package/dist/cdn/controls-BwebEIlf.js +1 -0
  14. package/dist/cdn/display-DFuMkcj5.js +1 -0
  15. package/dist/cdn/fields-DhLIhHQ8.js +1 -0
  16. package/dist/cdn/forms-BHivKDdC.js +1 -0
  17. package/dist/cdn/holidays-DgbIAdlt.js +1 -0
  18. package/dist/cdn/inputs-R7nEHfbV.js +1 -0
  19. package/dist/cdn/kashi-elements.js +1 -1
  20. package/dist/cdn/map-H3xiZd8Y.js +12 -0
  21. package/dist/cdn/{menu-Cga7QOfs.js → menu-BAUSubXk.js} +1 -1
  22. package/dist/cdn/nav-NK-v48B5.js +1 -0
  23. package/dist/cdn/overlay-CBv8grz3.js +1 -0
  24. package/dist/cdn/pickers-BHzNt_X8.js +1 -0
  25. package/dist/cdn/table-Bt9WVLoo.js +1 -0
  26. package/dist/cdn/text-D4a_hlwL.js +1 -0
  27. package/dist/cdn/time-DJ3p1wvd.js +1 -0
  28. package/dist/cdn/words-BdADG_9U.js +1 -0
  29. package/dist/cdn.d.ts +1 -0
  30. package/dist/cdn.js +2 -0
  31. package/dist/charts.js +27 -24
  32. package/dist/combobox.d.ts +6 -5
  33. package/dist/combobox.js +29 -20
  34. package/dist/controls.js +15 -15
  35. package/dist/display.js +17 -14
  36. package/dist/fields.js +3 -3
  37. package/dist/forms.d.ts +3 -3
  38. package/dist/forms.js +54 -47
  39. package/dist/index.d.ts +4 -0
  40. package/dist/index.js +3 -0
  41. package/dist/inputs.d.ts +3 -3
  42. package/dist/inputs.js +31 -30
  43. package/dist/map.js +16 -13
  44. package/dist/nav.js +18 -16
  45. package/dist/overlay.js +5 -5
  46. package/dist/pickers.d.ts +1 -1
  47. package/dist/pickers.js +39 -38
  48. package/dist/table.js +7 -7
  49. package/dist/toast.js +3 -3
  50. package/package.json +4 -4
  51. package/dist/cdn/appointment-DkMxtSWi.js +0 -1
  52. package/dist/cdn/base-DfzNTdQk.js +0 -1
  53. package/dist/cdn/basic-B5n1okZO.js +0 -1
  54. package/dist/cdn/calendar-oMlnK1_D.js +0 -16
  55. package/dist/cdn/charts-SHKq2S4I.js +0 -1
  56. package/dist/cdn/combobox-DiGy7lAB.js +0 -1
  57. package/dist/cdn/controls-C6zwNYWs.js +0 -1
  58. package/dist/cdn/digits-DE1YGT94.js +0 -1
  59. package/dist/cdn/display-DZFW9EEX.js +0 -1
  60. package/dist/cdn/fields-D2hmrvVR.js +0 -1
  61. package/dist/cdn/forms-CeItYHFx.js +0 -1
  62. package/dist/cdn/holidays-BwsAEOI1.js +0 -1
  63. package/dist/cdn/inputs-DuP7P3ka.js +0 -1
  64. package/dist/cdn/jalali-BiM5Kfep.js +0 -1
  65. package/dist/cdn/map-w5X2fTQI.js +0 -12
  66. package/dist/cdn/nav-CwPZ20z-.js +0 -1
  67. package/dist/cdn/overlay-BDzwsBN5.js +0 -1
  68. package/dist/cdn/pickers-BOpaZ-7q.js +0 -1
  69. package/dist/cdn/table-BdF43L5q.js +0 -1
  70. package/dist/cdn/text-D1U32D6K.js +0 -1
  71. package/dist/cdn/time-DXw4vOne.js +0 -1
  72. package/dist/cdn/words-9OdzG7y6.js +0 -1
package/dist/forms.js CHANGED
@@ -1,5 +1,5 @@
1
- import { PLATE_LETTERS, fixKeyboardLayout, fixPersianText, formatNumber, formatPlate, formatTime, isValidPlate, looksLikeWrongLayout, onlyDigits, parseTime, plateType, toFaDigits, } from "@kashi-ui/persian";
2
- import { HTMLBase, afterParse, bool, define, emit, esc, fieldHTML, setMessages, syncHidden, uid } from "./base.js";
1
+ import { PLATE_LETTERS, fixKeyboardLayout, fixPersianText, formatNumber, formatPlate, formatTime, isValidPlate, looksLikeWrongLayout, onlyDigits, parseTime, plateType, toFaDigits } from "@kashi-ui/persian";
2
+ import { afterParse, bool, define, digitsOf, emit, esc, fieldHTML, HTMLBase, lang, localeDigits, msg, num, setMessages, syncHidden, uid } from "./base.js";
3
3
  import { searchText } from "./combobox.js";
4
4
  const CHECK = '<svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m5 10.5 3.2 3L15 7"/></svg>';
5
5
  const X = '<svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="m6 6 8 8M14 6l-8 8"/></svg>';
@@ -80,7 +80,7 @@ export class KashiMultiSelect extends HTMLBase {
80
80
  render() {
81
81
  const id = this.key;
82
82
  const ariaLabel = this.getAttribute("aria-label");
83
- const label = this.hasAttribute("label") ? this.getAttribute("label") : ariaLabel ? null : "انتخاب";
83
+ const label = this.hasAttribute("label") ? this.getAttribute("label") : ariaLabel ? null : msg().multiSelect.label;
84
84
  const off = this.hasAttribute("disabled");
85
85
  const control = `<div class="k-combobox k-multiselect"><div class="k-tag-input"><input id="${id}" class="k-tag-input__control" role="combobox" aria-autocomplete="list" aria-expanded="false" aria-controls="${id}-list" autocomplete="off"${off ? " disabled" : ""}${!label && ariaLabel ? ` aria-label="${esc(ariaLabel)}"` : ""}></div><ul id="${id}-list" role="listbox" aria-multiselectable="true" class="k-listbox" hidden style="inset-block-start: calc(100% + 6px)"${label ? ` aria-label="${esc(label)}"` : ""}></ul><span id="${id}-count" class="k-sr-only"></span><span class="k-sr-only" aria-live="polite"></span></div>`;
86
86
  this.querySelector(":scope > .k-field")?.remove();
@@ -91,9 +91,9 @@ export class KashiMultiSelect extends HTMLBase {
91
91
  this.box.addEventListener("click", (e) => {
92
92
  const rm = e.target.closest("[data-remove]");
93
93
  if (rm)
94
- this.set(this.chosen.filter((v) => v !== rm.dataset.remove), `${this.labelOf(rm.dataset.remove)} حذف شد`);
94
+ this.set(this.chosen.filter((v) => v !== rm.dataset.remove), msg().common.removed(this.labelOf(rm.dataset.remove)));
95
95
  else if (e.target.closest("[data-clear]"))
96
- this.set([], "همه حذف شد");
96
+ this.set([], msg().multiSelect.clearedAll);
97
97
  this.input.focus();
98
98
  });
99
99
  this.input.addEventListener("input", () => {
@@ -127,10 +127,10 @@ export class KashiMultiSelect extends HTMLBase {
127
127
  return;
128
128
  const on = this.chosen.includes(o.value);
129
129
  if (!on && this.full)
130
- return this.announce(`حداکثر ${toFaDigits(Number(this.getAttribute("max")))} مورد`);
130
+ return this.announce(msg().common.max(num(this, Number(this.getAttribute("max")))));
131
131
  this.query = "";
132
132
  this.input.value = "";
133
- this.set(on ? this.chosen.filter((v) => v !== o.value) : [...this.chosen, o.value], `${o.label} ${on ? "حذف شد" : "انتخاب شد"}`);
133
+ this.set(on ? this.chosen.filter((v) => v !== o.value) : [...this.chosen, o.value], on ? msg().common.removed(o.label) : msg().common.selected(o.label));
134
134
  }
135
135
  set(next, message) {
136
136
  this.chosen = next;
@@ -186,18 +186,18 @@ export class KashiMultiSelect extends HTMLBase {
186
186
  }
187
187
  else if (e.key === "Backspace" && !this.input.value && this.chosen.length) {
188
188
  const last = this.chosen.at(-1);
189
- this.set(this.chosen.slice(0, -1), `${this.labelOf(last)} حذف شد`);
189
+ this.set(this.chosen.slice(0, -1), msg().common.removed(this.labelOf(last)));
190
190
  }
191
191
  }
192
192
  paint() {
193
193
  const off = this.hasAttribute("disabled");
194
194
  this.box.querySelectorAll(".k-badge, [data-clear]").forEach((el) => el.remove());
195
- const badges = this.chosen.map((v) => `<span class="k-badge k-badge--brand${off ? "" : " k-badge--removable"}">${esc(this.labelOf(v))}${off ? "" : `<button type="button" class="k-badge__remove" data-remove="${esc(v)}" aria-label="حذف ${esc(this.labelOf(v))}">${X}</button>`}</span>`).join("");
195
+ const badges = this.chosen.map((v) => `<span class="k-badge k-badge--brand${off ? "" : " k-badge--removable"}">${esc(this.labelOf(v))}${off ? "" : `<button type="button" class="k-badge__remove" data-remove="${esc(v)}" aria-label="${esc(msg().common.remove(this.labelOf(v)))}">${X}</button>`}</span>`).join("");
196
196
  this.input.insertAdjacentHTML("beforebegin", badges);
197
197
  if (this.chosen.length > 1 && !off)
198
- this.box.insertAdjacentHTML("beforeend", `<button type="button" class="k-input__action" data-clear aria-label="پاک کردن همه">${X}</button>`);
198
+ this.box.insertAdjacentHTML("beforeend", `<button type="button" class="k-input__action" data-clear aria-label="${esc(msg().common.clearAll)}">${X}</button>`);
199
199
  this.input.placeholder = this.chosen.length ? "" : (this.getAttribute("placeholder") ?? "");
200
- this.querySelector(`#${this.key}-count`).textContent = `${toFaDigits(this.chosen.length)} مورد انتخاب شده`;
200
+ this.querySelector(`#${this.key}-count`).textContent = msg().multiSelect.selected(num(this, this.chosen.length));
201
201
  const error = this.getAttribute("error");
202
202
  this.box.toggleAttribute("data-invalid", !!error);
203
203
  setMessages(this.querySelector(":scope > .k-field"), this.input, this.key, error, this.getAttribute("hint"), `${this.key}-count`);
@@ -218,7 +218,7 @@ export class KashiMultiSelect extends HTMLBase {
218
218
  const on = this.chosen.includes(o.value);
219
219
  return `<li id="${this.key}-list-${i}" data-i="${i}" role="option" aria-selected="${on}"${o.disabled || (!on && full) ? ' aria-disabled="true"' : ""}${i === this.active ? " data-active" : ""} class="k-option k-option--check"><span class="k-multiselect__box" aria-hidden="true">${on ? CHECK : ""}</span><span class="k-option__body"><span>${mark(o.label)}</span>${o.description ? `<span class="k-option__desc">${esc(o.description)}</span>` : ""}</span></li>`;
220
220
  }).join("")
221
- : '<li class="k-listbox__empty" role="presentation">نتیجه‌ای پیدا نشد.</li>';
221
+ : `<li class="k-listbox__empty" role="presentation">${esc(msg().common.noResults)}</li>`;
222
222
  const act = this.active >= 0 ? this.listbox.querySelector(`[data-i="${this.active}"]`) : null;
223
223
  if (act) {
224
224
  this.input.setAttribute("aria-activedescendant", act.id);
@@ -283,7 +283,7 @@ export class KashiSlider extends HTMLBase {
283
283
  }
284
284
  fmt(n) {
285
285
  const unit = this.getAttribute("unit");
286
- return `${formatNumber(n)}${unit ? ` ${unit}` : ""}`;
286
+ return `${formatNumber(n, { digits: digitsOf(this) })}${unit ? ` ${unit}` : ""}`;
287
287
  }
288
288
  render() {
289
289
  const label = this.getAttribute("label");
@@ -294,11 +294,11 @@ export class KashiSlider extends HTMLBase {
294
294
  const input = (which) => {
295
295
  const v = which === "lo" ? this.lo : this.hi;
296
296
  const n = name ? (range ? `${name}_${which === "lo" ? "min" : "max"}` : name) : "";
297
- return `<input type="range" class="k-slider__input" data-which="${which}" min="${this.min}" max="${this.max}" step="${this.num("step", 1)}" value="${v}"${off ? " disabled" : ""}${n ? ` name="${esc(n)}"` : ""}${range ? ` aria-label="${which === "lo" ? "حداقل" : "حداکثر"}${label ? ` ${esc(label)}` : ""}"` : label ? ` aria-labelledby="${this.key}-label"` : ""} aria-valuetext="${esc(this.fmt(v))}">`;
297
+ return `<input type="range" class="k-slider__input" data-which="${which}" min="${this.min}" max="${this.max}" step="${this.num("step", 1)}" value="${v}"${off ? " disabled" : ""}${n ? ` name="${esc(n)}"` : ""}${range ? ` aria-label="${esc(which === "lo" ? msg().slider.from : msg().slider.to)}${label ? ` ${esc(label)}` : ""}"` : label ? ` aria-labelledby="${this.key}-label"` : ""} aria-valuetext="${esc(this.fmt(v))}">`;
298
298
  };
299
299
  const marks = (this.getAttribute("marks") ?? "").split(/[,،]/).map((s) => s.trim()).filter(Boolean).map(Number);
300
300
  const showValue = this.getAttribute("show-value") !== "false";
301
- this.innerHTML = `<div class="k-slider"${range ? ' data-range=""' : ""}>${label || showValue ? `<div class="k-slider__head">${label ? `<span class="k-label" id="${this.key}-label">${esc(label)}</span>` : ""}${showValue ? `<span class="k-slider__value" aria-hidden="true">${esc(range ? `${this.fmt(this.lo)} تا ${this.fmt(this.hi)}` : this.fmt(this.hi))}</span>` : ""}</div>` : ""}<div class="k-slider__track" style="--_from: ${range ? pct(this.lo) : "0%"}; --_to: ${pct(this.hi)}"><span class="k-slider__fill" aria-hidden="true"></span>${range ? input("lo") : ""}${input("hi")}</div>${marks.length ? `<div class="k-slider__marks" aria-hidden="true">${marks.map((m) => `<span>${esc(this.fmt(m))}</span>`).join("")}</div>` : ""}</div>`;
301
+ this.innerHTML = `<div class="k-slider"${range ? ' data-range=""' : ""}>${label || showValue ? `<div class="k-slider__head">${label ? `<span class="k-label" id="${this.key}-label">${esc(label)}</span>` : ""}${showValue ? `<span class="k-slider__value" aria-hidden="true">${esc(range ? `${this.fmt(this.lo)}${msg().common.range}${this.fmt(this.hi)}` : this.fmt(this.hi))}</span>` : ""}</div>` : ""}<div class="k-slider__track" style="--_from: ${range ? pct(this.lo) : "0%"}; --_to: ${pct(this.hi)}"><span class="k-slider__fill" aria-hidden="true"></span>${range ? input("lo") : ""}${input("hi")}</div>${marks.length ? `<div class="k-slider__marks" aria-hidden="true">${marks.map((m) => `<span>${esc(this.fmt(m))}</span>`).join("")}</div>` : ""}</div>`;
302
302
  this.rendered = true;
303
303
  this.querySelectorAll(".k-slider__input").forEach((el) => el.addEventListener("input", () => {
304
304
  const n = Number(el.value);
@@ -316,7 +316,7 @@ export class KashiSlider extends HTMLBase {
316
316
  track.style.setProperty("--_to", pct(this.hi));
317
317
  const out = this.querySelector(".k-slider__value");
318
318
  if (out)
319
- out.textContent = range ? `${this.fmt(this.lo)} تا ${this.fmt(this.hi)}` : this.fmt(this.hi);
319
+ out.textContent = range ? `${this.fmt(this.lo)}${msg().common.range}${this.fmt(this.hi)}` : this.fmt(this.hi);
320
320
  emit(this, "kashi-change", { value: this.value });
321
321
  }));
322
322
  }
@@ -362,7 +362,7 @@ export class KashiChipGroup extends HTMLBase {
362
362
  b.setAttribute("aria-pressed", String(b.hasAttribute("data-pressed") || b.getAttribute("aria-pressed") === "true"));
363
363
  b.insertAdjacentHTML("afterbegin", '<svg class="k-chip__check" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m5 10.5 3.2 3L15 7"/></svg>');
364
364
  if (b.dataset.count)
365
- b.insertAdjacentHTML("beforeend", `<span class="k-chip__count">${toFaDigits(b.dataset.count)}</span>`);
365
+ b.insertAdjacentHTML("beforeend", `<span class="k-chip__count">${num(this, b.dataset.count ?? "")}</span>`);
366
366
  });
367
367
  this.addEventListener("click", (e) => {
368
368
  const b = e.target.closest(".k-chip");
@@ -384,10 +384,10 @@ export class KashiChipGroup extends HTMLBase {
384
384
  }
385
385
  KashiChipGroup.observedAttributes = ["label", "single", "name"];
386
386
  const RULES = [
387
- [`حداقل ${toFaDigits(8)} نویسه`, (p) => p.length >= 8],
388
- ["حروف بزرگ و کوچک انگلیسی", (p) => /[a-z]/.test(p) && /[A-Z]/.test(p)],
389
- ["دست‌کم یک عدد", (p) => /\d/.test(p)],
390
- ["دست‌کم یک نماد، مثل ! یا @", (p) => /[^A-Za-z0-9\s؀-ۿ]/.test(p)],
387
+ [(m) => m.length(localeDigits() === "fa" ? toFaDigits(8) : "8"), (p) => p.length >= 8],
388
+ [(m) => m.cases, (p) => /[a-z]/.test(p) && /[A-Z]/.test(p)],
389
+ [(m) => m.digit, (p) => /\d/.test(p)],
390
+ [(m) => m.symbol, (p) => /[^A-Za-z0-9\s؀-ۿ]/.test(p)],
391
391
  ];
392
392
  /** قدرت رمز زیر فیلد رمز؛ با for="شناسهٔ فیلد" به آن وصل می‌شود و با هر تایپ به‌روز می‌شود */
393
393
  export class KashiPasswordStrength extends HTMLBase {
@@ -433,11 +433,12 @@ export class KashiPasswordStrength extends HTMLBase {
433
433
  }
434
434
  render(p) {
435
435
  const score = this.score(p);
436
- const levels = ["ضعیف", "متوسط", "خوب", "قوی"];
436
+ const P = msg().password;
437
+ const levels = P.levels;
437
438
  const persian = /[؀-ۿ]/.test(p);
438
- this.innerHTML = `<div class="k-strength" data-score="${score}"><div class="k-strength__bars" aria-hidden="true">${"<span class=\"k-strength__bar\"></span>".repeat(4)}</div><p class="k-strength__label" aria-live="polite" style="margin: 0">${score ? `قدرت رمز: <strong>${levels[score - 1]}</strong>` : ""}</p>${persian ? '<p class="k-hint k-hint--error" role="alert">رمز حروف فارسی دارد؛ شاید صفحه‌کلید روی فارسی مانده است.</p>' : ""}${this.getAttribute("show-rules") === "false" ? "" : `<ul class="k-strength__rules">${RULES.map(([label, t]) => {
439
+ this.innerHTML = `<div class="k-strength" data-score="${score}"><div class="k-strength__bars" aria-hidden="true">${"<span class=\"k-strength__bar\"></span>".repeat(4)}</div><p class="k-strength__label" aria-live="polite" style="margin: 0">${score ? esc(P.strength("\u0000")).replace("\u0000", `<strong>${esc(levels[score - 1])}</strong>`) : ""}</p>${persian ? `<p class="k-hint k-hint--error" role="alert">${esc(P.persian)}</p>` : ""}${this.getAttribute("show-rules") === "false" ? "" : `<ul class="k-strength__rules">${RULES.map(([label, t]) => {
439
440
  const met = t(p);
440
- return `<li class="k-strength__rule"${met ? ' data-met=""' : ""}>${met ? CHECK : '<svg viewBox="0 0 20 20" aria-hidden="true"><circle cx="10" cy="10" r="2.5" fill="currentColor"/></svg>'}<span>${label}<span class="k-sr-only">${met ? "، رعایت شده" : "، رعایت نشده"}</span></span></li>`;
441
+ return `<li class="k-strength__rule"${met ? ' data-met=""' : ""}>${met ? CHECK : '<svg viewBox="0 0 20 20" aria-hidden="true"><circle cx="10" cy="10" r="2.5" fill="currentColor"/></svg>'}<span>${esc(label(P))}<span class="k-sr-only">${met ? P.met : P.unmet}</span></span></li>`;
441
442
  }).join("")}</ul>`}</div>`;
442
443
  }
443
444
  }
@@ -519,13 +520,15 @@ class TextField extends HTMLBase {
519
520
  emit(this, "kashi-change", { value: next });
520
521
  }
521
522
  }
522
- const KINDS = { arabic: "حرف عربی", zwnj: "نیم‌فاصله", punctuation: "علامت", digits: "رقم", spacing: "فاصله" };
523
+ const KINDS = ["arabic", "zwnj", "punctuation", "digits", "spacing"];
523
524
  /** متن چندخطی با ویرایش نگارشی: ی و ک عربی، نیم‌فاصله، علامت‌ها و ارقام را می‌شمارد و با یک دکمه اصلاح می‌کند */
524
525
  export class KashiPersianTextarea extends TextField {
525
526
  constructor() {
526
527
  super(...arguments);
527
528
  this.multiline = true;
528
- this.defaultLabel = "متن";
529
+ }
530
+ get defaultLabel() {
531
+ return msg().persianInput.text;
529
532
  }
530
533
  render() {
531
534
  super.render();
@@ -547,9 +550,10 @@ export class KashiPersianTextarea extends TextField {
547
550
  return this.getAttribute("hint") ? esc(this.getAttribute("hint")) : null;
548
551
  const r = this.result();
549
552
  if (!r.count)
550
- return '<span class="k-textfix" data-state="clean"><span class="k-textfix__text">نگارش متن درست است.</span></span>';
551
- const summary = Object.keys(KINDS).filter((k) => r.fixes[k]).map((k) => `${toFaDigits(r.fixes[k])} ${KINDS[k]}`).join("، ");
552
- return `<span class="k-textfix" data-state="fix"><span class="k-textfix__text">${toFaDigits(r.count)} مورد قابل اصلاح: ${summary}</span><button type="button" class="k-btn k-btn--tertiary k-btn--xs" data-fix>اصلاح نگارش</button></span>`;
553
+ return `<span class="k-textfix" data-state="clean"><span class="k-textfix__text">${esc(msg().textFix.clean)}</span></span>`;
554
+ const T = msg().textFix;
555
+ const summary = KINDS.filter((k) => r.fixes[k]).map((k) => `${num(this, r.fixes[k])} ${T[k]}`).join(msg().common.list);
556
+ return `<span class="k-textfix" data-state="fix"><span class="k-textfix__text">${esc(T.count(num(this, r.count), summary))}</span><button type="button" class="k-btn k-btn--tertiary k-btn--xs" data-fix>${esc(T.fix)}</button></span>`;
553
557
  }
554
558
  }
555
559
  KashiPersianTextarea.observedAttributes = ["label", "hint", "error", "placeholder", "required", "disabled", "name", "value", "rows", "fix-on-blur", "fix-digits", "aria-label"];
@@ -558,7 +562,9 @@ export class KashiKeyboardFix extends TextField {
558
562
  constructor() {
559
563
  super(...arguments);
560
564
  this.multiline = false;
561
- this.defaultLabel = "متن";
565
+ }
566
+ get defaultLabel() {
567
+ return msg().persianInput.text;
562
568
  }
563
569
  render() {
564
570
  super.render();
@@ -573,7 +579,7 @@ export class KashiKeyboardFix extends TextField {
573
579
  const show = this.getAttribute("suggest") === "always" ? latin : looksLikeWrongLayout(t);
574
580
  if (!show)
575
581
  return this.getAttribute("hint") ? esc(this.getAttribute("hint")) : null;
576
- return `<span class="k-kbfix" role="status">منظورتان <button type="button" class="k-kbfix__btn" data-fix>«${esc(fixKeyboardLayout(t))}»</button> بود؟</span>`;
582
+ return `<span class="k-kbfix" role="status">${esc(msg().keyboardFix.before)} <button type="button" class="k-kbfix__btn" data-fix>«${esc(fixKeyboardLayout(t))}»</button>${lang() === "en" ? "" : " "}${esc(msg().keyboardFix.after)}</span>`;
577
583
  }
578
584
  }
579
585
  KashiKeyboardFix.observedAttributes = ["label", "hint", "error", "placeholder", "required", "disabled", "name", "value", "suggest", "aria-label"];
@@ -619,7 +625,7 @@ export class KashiTimeInput extends HTMLBase {
619
625
  return t ? formatTime(t) : null;
620
626
  }
621
627
  show(s) {
622
- return s ? (this.getAttribute("digits") === "latin" ? s : toFaDigits(s)) : "";
628
+ return s ? (digitsOf(this) === "latin" ? s : toFaDigits(s)) : "";
623
629
  }
624
630
  get lo() {
625
631
  const t = parseTime(this.getAttribute("min") ?? "");
@@ -632,8 +638,8 @@ export class KashiTimeInput extends HTMLBase {
632
638
  render() {
633
639
  const id = this.key;
634
640
  const ariaLabel = this.getAttribute("aria-label");
635
- const label = this.hasAttribute("label") ? this.getAttribute("label") : ariaLabel ? null : "ساعت";
636
- const fa = this.getAttribute("digits") !== "latin";
641
+ const label = this.hasAttribute("label") ? this.getAttribute("label") : ariaLabel ? null : msg().persianInput.time;
642
+ const fa = digitsOf(this) === "fa";
637
643
  const control = `<div class="k-input"><input id="${id}" class="k-input__control" type="text" inputmode="numeric" dir="ltr" autocomplete="off" placeholder="${esc(this.getAttribute("placeholder") ?? (fa ? "۰۹:۳۰" : "09:30"))}"${this.hasAttribute("required") ? " required" : ""}${this.hasAttribute("disabled") ? " disabled" : ""}${!label && ariaLabel ? ` aria-label="${esc(ariaLabel)}"` : ""}><span class="k-input__addon">${CLOCK}</span></div>`;
638
644
  this.querySelector(":scope > .k-field")?.remove();
639
645
  this.insertAdjacentHTML("afterbegin", fieldHTML({ id, label, required: this.hasAttribute("required"), control }));
@@ -680,11 +686,11 @@ export class KashiTimeInput extends HTMLBase {
680
686
  paint(syncText = true) {
681
687
  if (syncText)
682
688
  this.input.value = this.show(this.current);
683
- const msg = this.invalid === "range"
684
- ? `ساعت باید بین ${this.show(formatTime(fromMin(this.lo)))} و ${this.show(formatTime(fromMin(this.hi)))} باشد.`
685
- : this.invalid ? "ساعت معتبر نیست؛ آن را به شکل ۰۹:۳۰ وارد کنید." : null;
686
- this.input.setCustomValidity(msg ?? "");
687
- setMessages(this.querySelector(":scope > .k-field"), this.input, this.key, this.getAttribute("error") || msg, this.getAttribute("hint"));
689
+ const text = this.invalid === "range"
690
+ ? msg().invalid.timeRange(this.show(formatTime(fromMin(this.lo))), this.show(formatTime(fromMin(this.hi))))
691
+ : this.invalid ? msg().invalid.time : null;
692
+ this.input.setCustomValidity(text ?? "");
693
+ setMessages(this.querySelector(":scope > .k-field"), this.input, this.key, this.getAttribute("error") || text, this.getAttribute("hint"));
688
694
  syncHidden(this, this.getAttribute("name"), this.current ?? "");
689
695
  }
690
696
  }
@@ -735,8 +741,9 @@ export class KashiPlateInput extends HTMLBase {
735
741
  const p = this.plate;
736
742
  const off = this.hasAttribute("disabled") ? " disabled" : "";
737
743
  const seg = (key, len, aria, cls = "", first = false) => `<input${first ? ` id="${k}-first"` : ""} class="k-plate__seg ${cls}" data-key="${key}" data-len="${len}" inputmode="numeric" autocomplete="off" aria-label="${aria}" placeholder="${toFaDigits("0".repeat(len))}" value="${toFaDigits(p[key])}"${off}>`;
738
- const label = this.getAttribute("label") ?? "پلاک خودرو";
739
- const control = `<div class="k-plate" role="group" aria-label="${esc(label)}" data-type="${plateType(p.letter)}"><span class="k-plate__flag" aria-hidden="true"><span class="k-plate__flag-colors"></span>I.R.<br>IRAN</span>${seg("first", 2, "دو رقم اول پلاک", "", true)}<select class="k-plate__letter" data-key="letter" aria-label="حرف پلاک"${off}><option value="">–</option>${PLATE_LETTERS.map((l) => `<option value="${l}"${l === p.letter ? " selected" : ""}>${l === "ه" ? "هـ" : l}</option>`).join("")}</select>${seg("middle", 3, "سه رقم پلاک", "k-plate__seg--3")}<span class="k-plate__region"><span class="k-plate__region-label" aria-hidden="true">ایران</span>${seg("region", 2, "کد استان")}</span></div><span class="k-sr-only" aria-live="polite"></span>`;
744
+ const PL = msg().plate;
745
+ const label = this.getAttribute("label") ?? PL.label;
746
+ const control = `<div class="k-plate" role="group" aria-label="${esc(label)}" data-type="${plateType(p.letter)}"><span class="k-plate__flag" aria-hidden="true"><span class="k-plate__flag-colors"></span>I.R.<br>IRAN</span>${seg("first", 2, PL.first, "", true)}<select class="k-plate__letter" data-key="letter" aria-label="${esc(PL.letter)}"${off}><option value="">–</option>${PLATE_LETTERS.map((l) => `<option value="${l}"${l === p.letter ? " selected" : ""}>${l === "ه" ? "هـ" : l}</option>`).join("")}</select>${seg("middle", 3, PL.middle, "k-plate__seg--3")}<span class="k-plate__region"><span class="k-plate__region-label" aria-hidden="true">ایران</span>${seg("region", 2, PL.region)}</span></div><span class="k-sr-only" aria-live="polite"></span>`;
740
747
  this.querySelector(":scope > .k-field")?.remove();
741
748
  this.insertAdjacentHTML("afterbegin", fieldHTML({ id: `${k}-first`, label, control }));
742
749
  const parts = [...this.querySelectorAll("[data-key]")];
@@ -786,7 +793,7 @@ export class KashiPlateInput extends HTMLBase {
786
793
  group.dataset.type = plateType(p.letter);
787
794
  const complete = p.first.length === 2 && !!p.letter && p.middle.length === 3 && p.region.length === 2;
788
795
  const showInvalid = (this.touched || complete) && Object.values(p).some(Boolean) && !this.valid;
789
- const error = this.getAttribute("error") || (showInvalid ? "پلاک خودرو معتبر نیست." : null);
796
+ const error = this.getAttribute("error") || (showInvalid ? msg().invalid.plate : null);
790
797
  group.toggleAttribute("data-invalid", !!error);
791
798
  setMessages(this.querySelector(":scope > .k-field"), group, this.key, error, this.getAttribute("hint"));
792
799
  this.querySelector(".k-field > .k-sr-only").textContent = this.valid ? formatPlate(p) : "";
@@ -834,10 +841,10 @@ export class KashiInlineEdit extends HTMLBase {
834
841
  this.render();
835
842
  }
836
843
  render(focus = false) {
837
- const label = this.getAttribute("label") ?? "متن";
844
+ const label = this.getAttribute("label") ?? msg().persianInput.text;
838
845
  this.rendered = true;
839
846
  this.editing = false;
840
- this.innerHTML = `<span class="k-inline-edit"><button type="button" class="k-inline-edit__view" aria-label="${esc(`${label}: ${this.text || "خالی"}، ویرایش`)}">${this.text ? esc(this.text) : `<span class="k-inline-edit__placeholder">${esc(this.getAttribute("placeholder") ?? "خالی")}</span>`}${PENCIL}</button></span>`;
847
+ this.innerHTML = `<span class="k-inline-edit"><button type="button" class="k-inline-edit__view" aria-label="${esc(`${label}: ${this.text || msg().inlineEdit.empty}${msg().common.list}${msg().common.edit}`)}">${this.text ? esc(this.text) : `<span class="k-inline-edit__placeholder">${esc(this.getAttribute("placeholder") ?? msg().inlineEdit.empty)}</span>`}${PENCIL}</button></span>`;
841
848
  const view = this.querySelector("button");
842
849
  view.addEventListener("click", () => this.edit());
843
850
  if (focus)
@@ -845,9 +852,9 @@ export class KashiInlineEdit extends HTMLBase {
845
852
  }
846
853
  edit(error, draft = this.text) {
847
854
  this.editing = true;
848
- const label = this.getAttribute("label") ?? "متن";
855
+ const label = this.getAttribute("label") ?? msg().persianInput.text;
849
856
  const errId = uid("kashi-ie-err");
850
- this.innerHTML = `<span class="k-inline-edit"><span class="k-field" style="gap: 4px"><span class="k-input"${error ? ' data-state="invalid"' : ""}><input class="k-input__control" aria-label="${esc(label)}" placeholder="${esc(this.getAttribute("placeholder") ?? "")}"${error ? ` aria-invalid="true" aria-describedby="${errId}"` : ""}></span>${error ? `<span class="k-hint k-hint--error" id="${errId}">${esc(error)}</span>` : ""}</span><span class="k-inline-edit__actions"><button type="button" class="k-btn k-btn--primary k-btn--icon k-btn--sm" data-save aria-label="ثبت">${CHECK}</button><button type="button" class="k-btn k-btn--secondary k-btn--icon k-btn--sm" data-cancel aria-label="انصراف">${X}</button></span></span>`;
857
+ this.innerHTML = `<span class="k-inline-edit"><span class="k-field" style="gap: 4px"><span class="k-input"${error ? ' data-state="invalid"' : ""}><input class="k-input__control" aria-label="${esc(label)}" placeholder="${esc(this.getAttribute("placeholder") ?? "")}"${error ? ` aria-invalid="true" aria-describedby="${errId}"` : ""}></span>${error ? `<span class="k-hint k-hint--error" id="${errId}">${esc(error)}</span>` : ""}</span><span class="k-inline-edit__actions"><button type="button" class="k-btn k-btn--primary k-btn--icon k-btn--sm" data-save aria-label="${esc(msg().common.save)}">${CHECK}</button><button type="button" class="k-btn k-btn--secondary k-btn--icon k-btn--sm" data-cancel aria-label="${esc(msg().common.cancel)}">${X}</button></span></span>`;
851
858
  const input = this.querySelector("input");
852
859
  input.value = draft;
853
860
  input.focus();
@@ -883,7 +890,7 @@ export class KashiInlineEdit extends HTMLBase {
883
890
  }
884
891
  catch {
885
892
  this.text = prev;
886
- return this.edit("ذخیره نشد؛ دوباره امتحان کنید.", raw);
893
+ return this.edit(msg().inlineEdit.failed, raw);
887
894
  }
888
895
  }
889
896
  this.render(true);
package/dist/index.d.ts CHANGED
@@ -17,6 +17,10 @@ import { KashiCopyButton, KashiDialog, KashiTabs, KashiTooltip } from "./overlay
17
17
  import { KashiToaster, toast } from "./toast.js";
18
18
  export { KashiCardNumber, KashiIban, KashiLandline, KashiLegalId, KashiMobile, KashiNationalId, KashiPostalCode, KashiPrice, KashiOtp, KashiProvinceSelect, KashiCombobox, KashiCitySelect, KashiIranMap, KashiAddressForm, KashiCalendar, KashiDatePicker, KashiCountdown, KashiDate, KashiMoney, KashiRelativeTime, KashiCopyButton, KashiDialog, KashiTabs, KashiTooltip, KashiToaster, toast, KashiDropdownMenu, KashiPopover, KashiTagInput, KashiNumberInput, KashiRating, KashiPagination, KashiDataTable, KashiMultiSelect, KashiSlider, KashiChipGroup, KashiPasswordStrength, KashiPersianTextarea, KashiKeyboardFix, KashiTimeInput, KashiPlateInput, KashiInlineEdit, KashiDateRangePicker, KashiMonthPicker, KashiFileUpload, KashiColorPicker, KashiBarChart, KashiLineChart, KashiPieChart, KashiBarList, KashiProportionBar, KashiSparkline, KashiActivityHeatmap, KashiCommandPalette, KashiContextMenu, KashiCarousel, KashiTreeView, KashiTour, KashiSplitter, KashiSideNav, KashiInput, KashiTextarea, KashiBanner, KashiAppointmentPicker, };
19
19
  export { KashiDigitsInput } from "./inputs.js";
20
+ /** زبان متن‌های داخلی همهٔ عنصرها: setLocale("en") */
21
+ export { setLocale } from "./base.js";
22
+ export { faMessages, enMessages } from "@kashi-ui/persian";
23
+ export type { KashiMessages, KashiMessagesInput, KashiLocale } from "@kashi-ui/persian";
20
24
  export type { ToastOptions, ToastTone } from "./toast.js";
21
25
  export type { ComboboxOption } from "./combobox.js";
22
26
  export type { TableColumn } from "./table.js";
package/dist/index.js CHANGED
@@ -19,6 +19,9 @@ import { KashiCopyButton, KashiDialog, KashiTabs, KashiTooltip } from "./overlay
19
19
  import { KashiToaster, toast } from "./toast.js";
20
20
  export { KashiCardNumber, KashiIban, KashiLandline, KashiLegalId, KashiMobile, KashiNationalId, KashiPostalCode, KashiPrice, KashiOtp, KashiProvinceSelect, KashiCombobox, KashiCitySelect, KashiIranMap, KashiAddressForm, KashiCalendar, KashiDatePicker, KashiCountdown, KashiDate, KashiMoney, KashiRelativeTime, KashiCopyButton, KashiDialog, KashiTabs, KashiTooltip, KashiToaster, toast, KashiDropdownMenu, KashiPopover, KashiTagInput, KashiNumberInput, KashiRating, KashiPagination, KashiDataTable, KashiMultiSelect, KashiSlider, KashiChipGroup, KashiPasswordStrength, KashiPersianTextarea, KashiKeyboardFix, KashiTimeInput, KashiPlateInput, KashiInlineEdit, KashiDateRangePicker, KashiMonthPicker, KashiFileUpload, KashiColorPicker, KashiBarChart, KashiLineChart, KashiPieChart, KashiBarList, KashiProportionBar, KashiSparkline, KashiActivityHeatmap, KashiCommandPalette, KashiContextMenu, KashiCarousel, KashiTreeView, KashiTour, KashiSplitter, KashiSideNav, KashiInput, KashiTextarea, KashiBanner, KashiAppointmentPicker, };
21
21
  export { KashiDigitsInput } from "./inputs.js";
22
+ /** زبان متن‌های داخلی همهٔ عنصرها: setLocale("en") */
23
+ export { setLocale } from "./base.js";
24
+ export { faMessages, enMessages } from "@kashi-ui/persian";
22
25
  /** نام همهٔ عنصرها؛ مثلاً برای isCustomElement در Vue */
23
26
  export const KASHI_ELEMENTS = [
24
27
  "kashi-national-id", "kashi-legal-id", "kashi-mobile", "kashi-landline", "kashi-card-number", "kashi-iban",
package/dist/inputs.d.ts CHANGED
@@ -6,13 +6,13 @@ type Meta = {
6
6
  bank?: Bank;
7
7
  } | null;
8
8
  interface Kind {
9
- label: string;
9
+ label: () => string;
10
10
  maxDigits: number;
11
11
  format: (raw: string) => string;
12
12
  normalize?: (digits: string) => string;
13
13
  /** معتبر بودن مقدار کامل */
14
14
  valid: (raw: string) => boolean;
15
- invalidMessage: string;
15
+ invalidMessage: () => string;
16
16
  placeholder: {
17
17
  fa: string;
18
18
  latin: string;
@@ -52,7 +52,7 @@ export declare abstract class KashiDigitsInput extends HTMLBase {
52
52
  protected isValid(): boolean;
53
53
  focus(options?: FocusOptions): void;
54
54
  protected clean(text: string): string;
55
- private get digits();
55
+ protected get digits(): "fa" | "latin";
56
56
  private shown;
57
57
  private render;
58
58
  private onInput;
package/dist/inputs.js CHANGED
@@ -1,5 +1,5 @@
1
- import { formatCardNumber, formatIban, formatLandline, formatMobile, formatNumber, formatPostalCode, getBankByCard, getBankByIban, getLandlineProvince, getMobileOperator, isValidCardNumber, isValidIban, isValidLandline, isValidLegalId, isValidMobile, isValidNationalId, isValidPostalCode, normalizeLandline, normalizeMobile, numberToWords, onlyDigits, toFaDigits, } from "@kashi-ui/persian";
2
- import { HTMLBase, bool, define, emit, esc, fieldHTML, setMessages, syncHidden, uid } from "./base.js";
1
+ import { formatCardNumber, formatIban, formatLandline, formatMobile, formatNumber, formatPostalCode, bankName, getBankByCard, getBankByIban, getLandlineProvince, getMobileOperator, operatorName, isValidCardNumber, isValidIban, isValidLandline, isValidLegalId, isValidMobile, isValidNationalId, isValidPostalCode, normalizeLandline, normalizeMobile, numberToWords, onlyDigits, toFaDigits, } from "@kashi-ui/persian";
2
+ import { bool, define, emit, esc, fieldHTML, HTMLBase, lang, msg, setMessages, syncHidden, uid } from "./base.js";
3
3
  const fa = (s) => toFaDigits(s);
4
4
  /** موقعیت مکان‌نما پس از n رقم در متن قالب‌بندی‌شده */
5
5
  function caretAfter(text, n) {
@@ -69,7 +69,7 @@ export class KashiDigitsInput extends HTMLBase {
69
69
  }
70
70
  get digits() {
71
71
  const d = this.getAttribute("digits");
72
- return d === "fa" || d === "latin" ? d : this.kind.digits;
72
+ return d === "fa" || d === "latin" ? d : lang() === "en" ? "latin" : this.kind.digits;
73
73
  }
74
74
  shown() {
75
75
  const f = this.kind.format(this.raw);
@@ -79,7 +79,7 @@ export class KashiDigitsInput extends HTMLBase {
79
79
  const k = this.kind;
80
80
  const id = this.key;
81
81
  const ariaLabel = this.getAttribute("aria-label");
82
- const label = this.hasAttribute("label") ? this.getAttribute("label") : ariaLabel ? null : k.label;
82
+ const label = this.hasAttribute("label") ? this.getAttribute("label") : ariaLabel ? null : k.label();
83
83
  const size = this.getAttribute("size");
84
84
  const required = this.hasAttribute("required");
85
85
  const disabled = this.hasAttribute("disabled");
@@ -119,7 +119,7 @@ export class KashiDigitsInput extends HTMLBase {
119
119
  /** پیام خطای فعلی؛ فیلد مبلغ آن را برای محدوده بازنویسی می‌کند */
120
120
  invalidText(touched) {
121
121
  const show = this.raw.length > 0 && (touched || this.raw.length === this.kind.maxDigits) && !this.isValid();
122
- return show ? (this.getAttribute("invalid-message") ?? this.kind.invalidMessage) : null;
122
+ return show ? (this.getAttribute("invalid-message") ?? this.kind.invalidMessage()) : null;
123
123
  }
124
124
  hintText() {
125
125
  return this.getAttribute("hint");
@@ -174,11 +174,11 @@ export class KashiNationalId extends KashiDigitsInput {
174
174
  constructor() {
175
175
  super(...arguments);
176
176
  this.kind = {
177
- label: "کد ملی",
177
+ label: () => msg().persianInput["national-id"],
178
178
  maxDigits: 10,
179
179
  format: (d) => d,
180
180
  valid: (d) => isValidNationalId(d),
181
- invalidMessage: "کد ملی معتبر نیست.",
181
+ invalidMessage: () => msg().invalid.nationalId,
182
182
  placeholder: { fa: "۰۰۰۰۰۰۰۰۰۰", latin: "0000000000" },
183
183
  digits: "fa",
184
184
  };
@@ -189,11 +189,11 @@ export class KashiLegalId extends KashiDigitsInput {
189
189
  constructor() {
190
190
  super(...arguments);
191
191
  this.kind = {
192
- label: "شناسهٔ ملی شرکت",
192
+ label: () => msg().persianInput["legal-id"],
193
193
  maxDigits: 11,
194
194
  format: (d) => d,
195
195
  valid: (d) => isValidLegalId(d),
196
- invalidMessage: "شناسهٔ ملی معتبر نیست.",
196
+ invalidMessage: () => msg().invalid.legalId,
197
197
  placeholder: { fa: "۰۰۰۰۰۰۰۰۰۰۰", latin: "00000000000" },
198
198
  digits: "fa",
199
199
  };
@@ -204,12 +204,12 @@ export class KashiMobile extends KashiDigitsInput {
204
204
  constructor() {
205
205
  super(...arguments);
206
206
  this.kind = {
207
- label: "شمارهٔ موبایل",
207
+ label: () => msg().persianInput.mobile,
208
208
  maxDigits: 11,
209
209
  normalize: normalizeMobile,
210
210
  format: formatMobile,
211
211
  valid: (d) => isValidMobile(d),
212
- invalidMessage: "شماره موبایل معتبر نیست.",
212
+ invalidMessage: () => msg().invalid.mobile,
213
213
  placeholder: { fa: "۰۹۱۲ ۳۴۵ ۶۷۸۹", latin: "0912 345 6789" },
214
214
  digits: "fa",
215
215
  type: "tel",
@@ -217,7 +217,7 @@ export class KashiMobile extends KashiDigitsInput {
217
217
  autocomplete: "tel-national",
218
218
  meta: (d) => {
219
219
  const op = getMobileOperator(d);
220
- return op ? { text: op.name } : null;
220
+ return op ? { text: operatorName(op, lang()) } : null;
221
221
  },
222
222
  detail: (d) => ({ operator: getMobileOperator(d)?.name ?? null }),
223
223
  };
@@ -228,12 +228,12 @@ export class KashiLandline extends KashiDigitsInput {
228
228
  constructor() {
229
229
  super(...arguments);
230
230
  this.kind = {
231
- label: "تلفن ثابت",
231
+ label: () => msg().persianInput.landline,
232
232
  maxDigits: 11,
233
233
  normalize: normalizeLandline,
234
234
  format: formatLandline,
235
235
  valid: (d) => isValidLandline(d),
236
- invalidMessage: "شمارهٔ تلفن ثابت معتبر نیست.",
236
+ invalidMessage: () => msg().invalid.landline,
237
237
  placeholder: { fa: "۰۲۱ ۸۸۷۷ ۶۶۵۵", latin: "021 8877 6655" },
238
238
  digits: "fa",
239
239
  type: "tel",
@@ -252,17 +252,17 @@ export class KashiCardNumber extends KashiDigitsInput {
252
252
  constructor() {
253
253
  super(...arguments);
254
254
  this.kind = {
255
- label: "شمارهٔ کارت",
255
+ label: () => msg().persianInput.card,
256
256
  maxDigits: 16,
257
257
  format: formatCardNumber,
258
258
  valid: (d) => isValidCardNumber(d),
259
- invalidMessage: "شماره کارت معتبر نیست.",
259
+ invalidMessage: () => msg().invalid.card,
260
260
  placeholder: { fa: "۰۰۰۰ ۰۰۰۰ ۰۰۰۰ ۰۰۰۰", latin: "0000 0000 0000 0000" },
261
261
  digits: "fa",
262
262
  autocomplete: "cc-number",
263
263
  meta: (d) => {
264
264
  const bank = getBankByCard(d);
265
- return bank ? { text: bank.name, bank } : null;
265
+ return bank ? { text: bankName(bank, lang()), bank } : null;
266
266
  },
267
267
  detail: (d) => ({ bank: getBankByCard(d)?.name ?? null }),
268
268
  };
@@ -273,16 +273,16 @@ export class KashiIban extends KashiDigitsInput {
273
273
  constructor() {
274
274
  super(...arguments);
275
275
  this.kind = {
276
- label: "شمارهٔ شبا",
276
+ label: () => msg().persianInput.iban,
277
277
  maxDigits: 24,
278
278
  format: (d) => formatIban(d),
279
279
  valid: (d) => isValidIban(d),
280
- invalidMessage: "شماره شبا معتبر نیست.",
280
+ invalidMessage: () => msg().invalid.iban,
281
281
  placeholder: { fa: "IR00 0000 0000 0000 0000 0000 00", latin: "IR00 0000 0000 0000 0000 0000 00" },
282
282
  digits: "latin",
283
283
  meta: (d) => {
284
284
  const bank = getBankByIban(d);
285
- return bank ? { text: bank.name, bank } : null;
285
+ return bank ? { text: bankName(bank, lang()), bank } : null;
286
286
  },
287
287
  submit: (d) => (d ? `IR${d}` : ""),
288
288
  detail: (d) => ({ bank: getBankByIban(d)?.name ?? null }),
@@ -297,11 +297,11 @@ export class KashiPostalCode extends KashiDigitsInput {
297
297
  constructor() {
298
298
  super(...arguments);
299
299
  this.kind = {
300
- label: "کد پستی",
300
+ label: () => msg().persianInput.postal,
301
301
  maxDigits: 10,
302
302
  format: formatPostalCode,
303
303
  valid: (d) => isValidPostalCode(d),
304
- invalidMessage: "کد پستی معتبر نیست.",
304
+ invalidMessage: () => msg().invalid.postal,
305
305
  placeholder: { fa: "۱۲۳۴۵-۶۷۸۹۰", latin: "12345-67890" },
306
306
  digits: "fa",
307
307
  autocomplete: "postal-code",
@@ -313,16 +313,16 @@ export class KashiPrice extends KashiDigitsInput {
313
313
  constructor() {
314
314
  super(...arguments);
315
315
  this.kind = {
316
- label: "مبلغ",
316
+ label: () => msg().persianInput.price,
317
317
  maxDigits: 15,
318
318
  normalize: (d) => d.replace(/^0+(?=\d)/, ""),
319
- format: (d) => (d ? formatNumber(d, { digits: "latin" }).replace(/,/g, "٬") : ""),
319
+ format: (d) => (d ? formatNumber(d, { digits: "latin" }).replace(/,/g, this.digits === "fa" ? "٬" : ",") : ""),
320
320
  valid: () => this.inRange(),
321
- invalidMessage: "",
321
+ invalidMessage: () => "",
322
322
  placeholder: { fa: "۰", latin: "0" },
323
323
  digits: "fa",
324
324
  meta: (_d, host) => {
325
- const unit = host.getAttribute("unit") ?? "تومان";
325
+ const unit = host.getAttribute("unit") ?? msg().money.toman;
326
326
  return unit ? { text: unit } : null;
327
327
  },
328
328
  detail: (d) => ({ value: d ? Number(d) : null }),
@@ -349,13 +349,14 @@ export class KashiPrice extends KashiDigitsInput {
349
349
  if (custom)
350
350
  return custom;
351
351
  const min = this.num("min"), max = this.num("max");
352
- const f = (n) => fa(formatNumber(n));
353
- return `مبلغ باید ${min !== undefined ? `حداقل ${f(min)}` : ""}${min !== undefined && max !== undefined ? " و " : ""}${max !== undefined ? `حداکثر ${f(max)}` : ""} باشد.`;
352
+ const f = (n) => (this.digits === "fa" ? fa(formatNumber(n)) : formatNumber(n, { digits: "latin" }));
353
+ const I = msg().invalid;
354
+ return min !== undefined && max !== undefined ? I.priceRange(f(min), f(max)) : min !== undefined ? I.priceMin(f(min)) : I.priceMax(f(max));
354
355
  }
355
356
  hintText() {
356
357
  if (this.raw && bool(this, "show-words", true)) {
357
- const unit = this.getAttribute("unit") ?? "تومان";
358
- return `${numberToWords(Number(this.raw))}${unit ? ` ${unit}` : ""}`;
358
+ const unit = this.getAttribute("unit") ?? msg().money.toman;
359
+ return `${numberToWords(Number(this.raw), { locale: lang() })}${unit ? ` ${unit}` : ""}`;
359
360
  }
360
361
  return this.getAttribute("hint");
361
362
  }