@spintax/core 0.10.0 → 0.12.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.
package/dist/index.d.cts CHANGED
@@ -206,8 +206,8 @@ interface Analysis extends ExtractResult {
206
206
  */
207
207
  declare function normalizeBaseLang(locale?: string | null): string;
208
208
  /**
209
- * How many `{plural …}` forms this locale takes — 3 for the Slavic one/few/other
210
- * family (ru/uk/be + sr/hr/bs), 2 for everything else.
209
+ * How many `{plural …}` forms this locale takes — 6 for Arabic (zero/one/two/few/many/other),
210
+ * 3 for the Slavic one/few/other family (ru/uk/be + sr/hr/bs), 2 for everything else.
211
211
  *
212
212
  * Takes a RAW locale and normalizes internally, unlike the internal helper of the
213
213
  * same name: a public function that silently answered 2 for `sr-Latn` would be a
package/dist/index.d.ts CHANGED
@@ -206,8 +206,8 @@ interface Analysis extends ExtractResult {
206
206
  */
207
207
  declare function normalizeBaseLang(locale?: string | null): string;
208
208
  /**
209
- * How many `{plural …}` forms this locale takes — 3 for the Slavic one/few/other
210
- * family (ru/uk/be + sr/hr/bs), 2 for everything else.
209
+ * How many `{plural …}` forms this locale takes — 6 for Arabic (zero/one/two/few/many/other),
210
+ * 3 for the Slavic one/few/other family (ru/uk/be + sr/hr/bs), 2 for everything else.
211
211
  *
212
212
  * Takes a RAW locale and normalizes internally, unlike the internal helper of the
213
213
  * same name: a public function that silently answered 2 for `sr-Latn` would be a
package/dist/index.js CHANGED
@@ -742,6 +742,8 @@ function normalizeBaseLang(locale) {
742
742
  }
743
743
  function pluralArity(baseLang) {
744
744
  switch (baseLang) {
745
+ case "ar":
746
+ return 6;
745
747
  case "ru":
746
748
  case "uk":
747
749
  case "be":
@@ -759,6 +761,13 @@ function pluralFor(baseLang, n, forms) {
759
761
  const mod10 = abs % 10;
760
762
  const mod100 = abs % 100;
761
763
  switch (baseLang) {
764
+ case "ar":
765
+ if (abs === 0) return forms[0] ?? "";
766
+ if (abs === 1) return forms[1] ?? "";
767
+ if (abs === 2) return forms[2] ?? "";
768
+ if (mod100 >= 3 && mod100 <= 10) return forms[3] ?? "";
769
+ if (mod100 >= 11) return forms[4] ?? "";
770
+ return forms[5] ?? "";
762
771
  case "ru":
763
772
  case "uk":
764
773
  case "be":
@@ -1378,6 +1387,37 @@ function trimFragment(fragment) {
1378
1387
  if (fragment.lead === 0 && fragment.trail === 0) return fragment;
1379
1388
  return new Window(fragment, fragment.lead, fragment.length - fragment.trail);
1380
1389
  }
1390
+ function firstCodePointOf(fragment) {
1391
+ const hi = charCodeAtOf(fragment, 0);
1392
+ if (hi >= 55296 && hi <= 56319) {
1393
+ const lo = charCodeAtOf(fragment, 1);
1394
+ if (lo >= 56320 && lo <= 57343) return (hi - 55296) * 1024 + (lo - 56320) + 65536;
1395
+ }
1396
+ return hi;
1397
+ }
1398
+ function charCodeAtOf(fragment, index) {
1399
+ let piece = fragment;
1400
+ let at = index;
1401
+ for (; ; ) {
1402
+ if (at < 0 || at >= lengthOf(piece)) return -1;
1403
+ if (typeof piece === "string") return piece.charCodeAt(at);
1404
+ if (piece instanceof Window) {
1405
+ at += piece.from;
1406
+ piece = piece.base;
1407
+ continue;
1408
+ }
1409
+ let offset = 0;
1410
+ for (const child of piece.pieces) {
1411
+ const length = lengthOf(child);
1412
+ if (at < offset + length) {
1413
+ piece = child;
1414
+ at -= offset;
1415
+ break;
1416
+ }
1417
+ offset += length;
1418
+ }
1419
+ }
1420
+ }
1381
1421
  function flatten(fragment) {
1382
1422
  if (typeof fragment === "string") return fragment;
1383
1423
  const out = [];
@@ -1771,7 +1811,12 @@ function assemblePermutation(node, rendered, opts) {
1771
1811
  max = Math.max(min, Math.min(max, total));
1772
1812
  const pick = randomInt(opts.rng, min, max);
1773
1813
  shuffle(elements, opts.rng);
1774
- return joinWithSeparators(elements.slice(0, pick), config.sep, config.lastsep ?? config.sep);
1814
+ return joinWithSeparators(
1815
+ elements.slice(0, pick),
1816
+ config.sep,
1817
+ config.lastsep ?? config.sep,
1818
+ normalizeBaseLang(opts.locale)
1819
+ );
1775
1820
  }
1776
1821
  function shuffle(arr, rng) {
1777
1822
  for (let i = arr.length - 1; i > 0; i -= 1) {
@@ -1781,7 +1826,7 @@ function shuffle(arr, rng) {
1781
1826
  arr[j] = tmp;
1782
1827
  }
1783
1828
  }
1784
- function joinWithSeparators(elements, globalSep, globalLastsep) {
1829
+ function joinWithSeparators(elements, globalSep, globalLastsep, lang) {
1785
1830
  const count = elements.length;
1786
1831
  if (count === 0) return "";
1787
1832
  if (count === 1) return elements[0].text;
@@ -1789,14 +1834,24 @@ function joinWithSeparators(elements, globalSep, globalLastsep) {
1789
1834
  for (let i = 1; i < count; i += 1) {
1790
1835
  const el = elements[i];
1791
1836
  const sep = el.sep ?? (i === count - 1 ? globalLastsep : globalSep);
1792
- pieces.push(padSeparator(sep), el.text);
1837
+ pieces.push(padSeparator(sep, lang, el.text), el.text);
1793
1838
  }
1794
1839
  return joinFragments(pieces);
1795
1840
  }
1796
- function padSeparator(sep) {
1841
+ var UNSPACED_SCRIPT_RE = /^[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}ーー\p{Script=Thai}\p{Script=Lao}\p{Script=Khmer}\p{Script=Myanmar}]+$/u;
1842
+ var PROCLITICS = /* @__PURE__ */ new Map([
1843
+ ["ar", { words: /* @__PURE__ */ new Set(["\u0648", "\u0641"]), letter: /^(?=\p{L})\p{Script=Arabic}$/u }],
1844
+ ["he", { words: /* @__PURE__ */ new Set(["\u05D5"]), letter: /^(?=\p{L})\p{Script=Hebrew}$/u }]
1845
+ ]);
1846
+ function padSeparator(sep, lang, next) {
1797
1847
  const trimmed = phpTrim(sep);
1798
1848
  if (trimmed === "") return sep;
1799
- if (/^\p{L}+$/u.test(trimmed)) return ` ${trimmed} `;
1849
+ const proclitic = PROCLITICS.get(lang);
1850
+ if (proclitic !== void 0 && proclitic.words.has(trimmed)) {
1851
+ const first = firstCodePointOf(next);
1852
+ return first >= 0 && proclitic.letter.test(String.fromCodePoint(first)) ? ` ${trimmed}` : ` ${trimmed} `;
1853
+ }
1854
+ if (/^\p{L}+$/u.test(trimmed) && !UNSPACED_SCRIPT_RE.test(trimmed)) return ` ${trimmed} `;
1800
1855
  return sep;
1801
1856
  }
1802
1857