@dialpad/i18n 1.22.3 → 1.24.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 (46) hide show
  1. package/bin/force-pull-translations.js +2 -0
  2. package/bin/pull-translations.js +2 -0
  3. package/bin/should-pull.js +2 -0
  4. package/bin/translate-dialpadistan.js +2 -0
  5. package/bin/translation-screenshots-check.js +2 -0
  6. package/bin/upload-translation-service.js +2 -0
  7. package/dist/i18n.cjs +883 -878
  8. package/dist/i18n.cjs.map +1 -1
  9. package/dist/i18n.js +883 -878
  10. package/dist/i18n.js.map +1 -1
  11. package/dist/types/index.d.ts +2 -4
  12. package/dist/types/index.js +1 -2
  13. package/{README.md → docs/README.md} +280 -84
  14. package/index.ts +18 -5
  15. package/package.json +50 -26
  16. package/.eslintignore +0 -1
  17. package/.eslintrc.cjs +0 -12
  18. package/.prettierignore +0 -3
  19. package/.rush/temp/chunked-rush-logs/i18n.build.chunks.jsonl +0 -22
  20. package/.rush/temp/chunked-rush-logs/i18n.format.chunks.jsonl +0 -19
  21. package/.rush/temp/chunked-rush-logs/i18n.lint.chunks.jsonl +0 -2
  22. package/.rush/temp/package-deps_build.json +0 -24
  23. package/.rush/temp/package-deps_format.json +0 -24
  24. package/.rush/temp/package-deps_lint.json +0 -24
  25. package/.rush/temp/shrinkwrap-deps.json +0 -12
  26. package/CHANGELOG.json +0 -63
  27. package/CHANGELOG.md +0 -30
  28. package/base-tsconfig.json +0 -19
  29. package/dialpad-i18n-1.22.2.tgz +0 -0
  30. package/dist/types/src/locale-manager.d.ts +0 -53
  31. package/dist/types/src/locale-manager.js +0 -146
  32. package/eslint-tsconfig.json +0 -5
  33. package/index.html +0 -11
  34. package/rush-logs/i18n.build.error.log +0 -0
  35. package/rush-logs/i18n.build.log +0 -22
  36. package/rush-logs/i18n.format.error.log +0 -0
  37. package/rush-logs/i18n.format.log +0 -19
  38. package/rush-logs/i18n.lint.error.log +0 -0
  39. package/rush-logs/i18n.lint.log +0 -2
  40. package/src/__test__/locale-manager.find.test.ts +0 -78
  41. package/src/__test__/locale-manager.formatters.test.ts +0 -139
  42. package/src/__test__/locale-manager.multiple.test.ts +0 -349
  43. package/src/__test__/locale-manager.test.ts +0 -511
  44. package/src/locale-manager.ts +0 -198
  45. package/tsconfig.json +0 -10
  46. package/vite.config.ts +0 -39
package/dist/i18n.js CHANGED
@@ -763,7 +763,7 @@ var init_esm_shims$1 = __esm$1({
763
763
  }
764
764
  });
765
765
  var require_rfdc = __commonJS$1({
766
- "../../node_modules/.pnpm/rfdc@1.4.1/node_modules/rfdc/index.js"(exports, module) {
766
+ "../../node_modules/.pnpm/rfdc@1.4.1/node_modules/rfdc/index.js"(exports$1, module) {
767
767
  init_esm_shims$1();
768
768
  module.exports = rfdc2;
769
769
  function copyBuffer(cur) {
@@ -1269,7 +1269,7 @@ var init_esm_shims = __esm({
1269
1269
  }
1270
1270
  });
1271
1271
  var require_speakingurl = __commonJS({
1272
- "../../node_modules/.pnpm/speakingurl@14.0.1/node_modules/speakingurl/lib/speakingurl.js"(exports, module) {
1272
+ "../../node_modules/.pnpm/speakingurl@14.0.1/node_modules/speakingurl/lib/speakingurl.js"(exports$1, module) {
1273
1273
  init_esm_shims();
1274
1274
  (function(root) {
1275
1275
  var charMap = {
@@ -2790,11 +2790,11 @@ var require_speakingurl = __commonJS({
2790
2790
  } catch (e) {
2791
2791
  }
2792
2792
  }
2793
- })(exports);
2793
+ })(exports$1);
2794
2794
  }
2795
2795
  });
2796
2796
  var require_speakingurl2 = __commonJS({
2797
- "../../node_modules/.pnpm/speakingurl@14.0.1/node_modules/speakingurl/index.js"(exports, module) {
2797
+ "../../node_modules/.pnpm/speakingurl@14.0.1/node_modules/speakingurl/index.js"(exports$1, module) {
2798
2798
  init_esm_shims();
2799
2799
  module.exports = require_speakingurl();
2800
2800
  }
@@ -3356,7 +3356,7 @@ init_esm_shims();
3356
3356
  init_esm_shims();
3357
3357
  var TIMELINE_LAYERS_STATE_STORAGE_ID = "__VUE_DEVTOOLS_KIT_TIMELINE_LAYERS_STATE__";
3358
3358
  function getTimelineLayersStateFromStorage() {
3359
- if (!isBrowser || typeof localStorage === "undefined" || localStorage === null) {
3359
+ if (typeof window === "undefined" || !isBrowser || typeof localStorage === "undefined" || localStorage === null) {
3360
3360
  return {
3361
3361
  recordingState: false,
3362
3362
  mouseEventEnabled: false,
@@ -3366,7 +3366,7 @@ function getTimelineLayersStateFromStorage() {
3366
3366
  selected: ""
3367
3367
  };
3368
3368
  }
3369
- const state = localStorage.getItem(TIMELINE_LAYERS_STATE_STORAGE_ID);
3369
+ const state = typeof localStorage.getItem !== "undefined" ? localStorage.getItem(TIMELINE_LAYERS_STATE_STORAGE_ID) : null;
3370
3370
  return state ? JSON.parse(state) : {
3371
3371
  recordingState: false,
3372
3372
  mouseEventEnabled: false,
@@ -5577,889 +5577,889 @@ function createStorageWrapper() {
5577
5577
  }
5578
5578
  return globalThis.__i18nStorage;
5579
5579
  }
5580
- class FluentType2 {
5581
- /**
5582
- * Create a `FluentType` instance.
5583
- *
5584
- * @param value The JavaScript value to wrap.
5585
- */
5586
- constructor(value) {
5587
- this.value = value;
5588
- }
5589
- /**
5590
- * Unwrap the raw value stored by this `FluentType`.
5591
- */
5592
- valueOf() {
5593
- return this.value;
5594
- }
5595
- }
5596
- class FluentNone2 extends FluentType2 {
5597
- /**
5598
- * Create an instance of `FluentNone` with an optional fallback value.
5599
- * @param value The fallback value of this `FluentNone`.
5600
- */
5601
- constructor(value = "???") {
5602
- super(value);
5603
- }
5604
- /**
5605
- * Format this `FluentNone` to the fallback string.
5606
- */
5607
- toString(scope) {
5608
- return `{${this.value}}`;
5609
- }
5610
- }
5611
- class FluentNumber2 extends FluentType2 {
5612
- /**
5613
- * Create an instance of `FluentNumber` with options to the
5614
- * `Intl.NumberFormat` constructor.
5615
- *
5616
- * @param value The number value of this `FluentNumber`.
5617
- * @param opts Options which will be passed to `Intl.NumberFormat`.
5618
- */
5619
- constructor(value, opts = {}) {
5620
- super(value);
5621
- this.opts = opts;
5622
- }
5623
- /**
5624
- * Format this `FluentNumber` to a string.
5625
- */
5626
- toString(scope) {
5627
- try {
5628
- const nf = scope.memoizeIntlObject(Intl.NumberFormat, this.opts);
5629
- return nf.format(this.value);
5630
- } catch (err) {
5631
- scope.reportError(err);
5632
- return this.value.toString(10);
5580
+ const RE_MESSAGE_START = /^(-?[a-zA-Z][\w-]*) *= */gm;
5581
+ const RE_ATTRIBUTE_START = /\.([a-zA-Z][\w-]*) *= */y;
5582
+ const RE_VARIANT_START = /\*?\[/y;
5583
+ const RE_NUMBER_LITERAL = /(-?[0-9]+(?:\.([0-9]+))?)/y;
5584
+ const RE_IDENTIFIER = /([a-zA-Z][\w-]*)/y;
5585
+ const RE_REFERENCE = /([$-])?([a-zA-Z][\w-]*)(?:\.([a-zA-Z][\w-]*))?/y;
5586
+ const RE_FUNCTION_NAME = /^[A-Z][A-Z0-9_-]*$/;
5587
+ const RE_TEXT_RUN = /([^{}\n\r]+)/y;
5588
+ const RE_STRING_RUN = /([^\\"\n\r]*)/y;
5589
+ const RE_STRING_ESCAPE = /\\([\\"])/y;
5590
+ const RE_UNICODE_ESCAPE = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{6})/y;
5591
+ const RE_LEADING_NEWLINES = /^\n+/;
5592
+ const RE_TRAILING_SPACES = / +$/;
5593
+ const RE_BLANK_LINES = / *\r?\n/g;
5594
+ const RE_INDENT = /( *)$/;
5595
+ const TOKEN_BRACE_OPEN = /{\s*/y;
5596
+ const TOKEN_BRACE_CLOSE = /\s*}/y;
5597
+ const TOKEN_BRACKET_OPEN = /\[\s*/y;
5598
+ const TOKEN_BRACKET_CLOSE = /\s*] */y;
5599
+ const TOKEN_PAREN_OPEN = /\s*\(\s*/y;
5600
+ const TOKEN_ARROW = /\s*->\s*/y;
5601
+ const TOKEN_COLON = /\s*:\s*/y;
5602
+ const TOKEN_COMMA = /\s*,?\s*/y;
5603
+ const TOKEN_BLANK = /\s+/y;
5604
+ class FluentResource {
5605
+ constructor(source) {
5606
+ this.body = [];
5607
+ RE_MESSAGE_START.lastIndex = 0;
5608
+ let cursor = 0;
5609
+ while (true) {
5610
+ let next = RE_MESSAGE_START.exec(source);
5611
+ if (next === null) {
5612
+ break;
5613
+ }
5614
+ cursor = RE_MESSAGE_START.lastIndex;
5615
+ try {
5616
+ this.body.push(parseMessage(next[1]));
5617
+ } catch (err) {
5618
+ if (err instanceof SyntaxError) {
5619
+ continue;
5620
+ }
5621
+ throw err;
5622
+ }
5633
5623
  }
5634
- }
5635
- }
5636
- class FluentDateTime2 extends FluentType2 {
5637
- /**
5638
- * Create an instance of `FluentDateTime` with options to the
5639
- * `Intl.DateTimeFormat` constructor.
5640
- *
5641
- * @param value The number value of this `FluentDateTime`, in milliseconds.
5642
- * @param opts Options which will be passed to `Intl.DateTimeFormat`.
5643
- */
5644
- constructor(value, opts = {}) {
5645
- super(value);
5646
- this.opts = opts;
5647
- }
5648
- /**
5649
- * Format this `FluentDateTime` to a string.
5650
- */
5651
- toString(scope) {
5652
- try {
5653
- const dtf = scope.memoizeIntlObject(Intl.DateTimeFormat, this.opts);
5654
- return dtf.format(this.value);
5655
- } catch (err) {
5656
- scope.reportError(err);
5657
- return new Date(this.value).toISOString();
5624
+ function test(re) {
5625
+ re.lastIndex = cursor;
5626
+ return re.test(source);
5658
5627
  }
5659
- }
5660
- }
5661
- const MAX_PLACEABLES = 100;
5662
- const FSI = "⁨";
5663
- const PDI = "⁩";
5664
- function match(scope, selector, key) {
5665
- if (key === selector) {
5666
- return true;
5667
- }
5668
- if (key instanceof FluentNumber2 && selector instanceof FluentNumber2 && key.value === selector.value) {
5669
- return true;
5670
- }
5671
- if (selector instanceof FluentNumber2 && typeof key === "string") {
5672
- let category = scope.memoizeIntlObject(Intl.PluralRules, selector.opts).select(selector.value);
5673
- if (key === category) {
5674
- return true;
5628
+ function consumeChar(char, errorClass) {
5629
+ if (source[cursor] === char) {
5630
+ cursor++;
5631
+ return true;
5632
+ }
5633
+ if (errorClass) {
5634
+ throw new errorClass(`Expected ${char}`);
5635
+ }
5636
+ return false;
5675
5637
  }
5676
- }
5677
- return false;
5678
- }
5679
- function getDefault(scope, variants, star) {
5680
- if (variants[star]) {
5681
- return resolvePattern(scope, variants[star].value);
5682
- }
5683
- scope.reportError(new RangeError("No default"));
5684
- return new FluentNone2();
5685
- }
5686
- function getArguments(scope, args) {
5687
- const positional = [];
5688
- const named = /* @__PURE__ */ Object.create(null);
5689
- for (const arg of args) {
5690
- if (arg.type === "narg") {
5691
- named[arg.name] = resolveExpression(scope, arg.value);
5692
- } else {
5693
- positional.push(resolveExpression(scope, arg));
5638
+ function consumeToken(re, errorClass) {
5639
+ if (test(re)) {
5640
+ cursor = re.lastIndex;
5641
+ return true;
5642
+ }
5643
+ if (errorClass) {
5644
+ throw new errorClass(`Expected ${re.toString()}`);
5645
+ }
5646
+ return false;
5694
5647
  }
5695
- }
5696
- return { positional, named };
5697
- }
5698
- function resolveExpression(scope, expr) {
5699
- switch (expr.type) {
5700
- case "str":
5701
- return expr.value;
5702
- case "num":
5703
- return new FluentNumber2(expr.value, {
5704
- minimumFractionDigits: expr.precision
5705
- });
5706
- case "var":
5707
- return resolveVariableReference(scope, expr);
5708
- case "mesg":
5709
- return resolveMessageReference(scope, expr);
5710
- case "term":
5711
- return resolveTermReference(scope, expr);
5712
- case "func":
5713
- return resolveFunctionReference(scope, expr);
5714
- case "select":
5715
- return resolveSelectExpression(scope, expr);
5716
- default:
5717
- return new FluentNone2();
5718
- }
5719
- }
5720
- function resolveVariableReference(scope, { name }) {
5721
- let arg;
5722
- if (scope.params) {
5723
- if (Object.prototype.hasOwnProperty.call(scope.params, name)) {
5724
- arg = scope.params[name];
5725
- } else {
5726
- return new FluentNone2(`$${name}`);
5648
+ function match2(re) {
5649
+ re.lastIndex = cursor;
5650
+ let result = re.exec(source);
5651
+ if (result === null) {
5652
+ throw new SyntaxError(`Expected ${re.toString()}`);
5653
+ }
5654
+ cursor = re.lastIndex;
5655
+ return result;
5727
5656
  }
5728
- } else if (scope.args && Object.prototype.hasOwnProperty.call(scope.args, name)) {
5729
- arg = scope.args[name];
5730
- } else {
5731
- scope.reportError(new ReferenceError(`Unknown variable: $${name}`));
5732
- return new FluentNone2(`$${name}`);
5733
- }
5734
- if (arg instanceof FluentType2) {
5735
- return arg;
5736
- }
5737
- switch (typeof arg) {
5738
- case "string":
5739
- return arg;
5740
- case "number":
5741
- return new FluentNumber2(arg);
5742
- case "object":
5743
- if (arg instanceof Date) {
5744
- return new FluentDateTime2(arg.getTime());
5657
+ function match1(re) {
5658
+ return match2(re)[1];
5659
+ }
5660
+ function parseMessage(id) {
5661
+ let value = parsePattern();
5662
+ let attributes = parseAttributes();
5663
+ if (value === null && Object.keys(attributes).length === 0) {
5664
+ throw new SyntaxError("Expected message value or attributes");
5745
5665
  }
5746
- default:
5747
- scope.reportError(new TypeError(`Variable type not supported: $${name}, ${typeof arg}`));
5748
- return new FluentNone2(`$${name}`);
5749
- }
5750
- }
5751
- function resolveMessageReference(scope, { name, attr }) {
5752
- const message = scope.bundle._messages.get(name);
5753
- if (!message) {
5754
- scope.reportError(new ReferenceError(`Unknown message: ${name}`));
5755
- return new FluentNone2(name);
5756
- }
5757
- if (attr) {
5758
- const attribute = message.attributes[attr];
5759
- if (attribute) {
5760
- return resolvePattern(scope, attribute);
5666
+ return { id, value, attributes };
5761
5667
  }
5762
- scope.reportError(new ReferenceError(`Unknown attribute: ${attr}`));
5763
- return new FluentNone2(`${name}.${attr}`);
5764
- }
5765
- if (message.value) {
5766
- return resolvePattern(scope, message.value);
5767
- }
5768
- scope.reportError(new ReferenceError(`No value: ${name}`));
5769
- return new FluentNone2(name);
5770
- }
5771
- function resolveTermReference(scope, { name, attr, args }) {
5772
- const id = `-${name}`;
5773
- const term = scope.bundle._terms.get(id);
5774
- if (!term) {
5775
- scope.reportError(new ReferenceError(`Unknown term: ${id}`));
5776
- return new FluentNone2(id);
5777
- }
5778
- if (attr) {
5779
- const attribute = term.attributes[attr];
5780
- if (attribute) {
5781
- scope.params = getArguments(scope, args).named;
5782
- const resolved2 = resolvePattern(scope, attribute);
5783
- scope.params = null;
5784
- return resolved2;
5785
- }
5786
- scope.reportError(new ReferenceError(`Unknown attribute: ${attr}`));
5787
- return new FluentNone2(`${id}.${attr}`);
5788
- }
5789
- scope.params = getArguments(scope, args).named;
5790
- const resolved = resolvePattern(scope, term.value);
5791
- scope.params = null;
5792
- return resolved;
5793
- }
5794
- function resolveFunctionReference(scope, { name, args }) {
5795
- let func = scope.bundle._functions[name];
5796
- if (!func) {
5797
- scope.reportError(new ReferenceError(`Unknown function: ${name}()`));
5798
- return new FluentNone2(`${name}()`);
5799
- }
5800
- if (typeof func !== "function") {
5801
- scope.reportError(new TypeError(`Function ${name}() is not callable`));
5802
- return new FluentNone2(`${name}()`);
5803
- }
5804
- try {
5805
- let resolved = getArguments(scope, args);
5806
- return func(resolved.positional, resolved.named);
5807
- } catch (err) {
5808
- scope.reportError(err);
5809
- return new FluentNone2(`${name}()`);
5810
- }
5811
- }
5812
- function resolveSelectExpression(scope, { selector, variants, star }) {
5813
- let sel = resolveExpression(scope, selector);
5814
- if (sel instanceof FluentNone2) {
5815
- return getDefault(scope, variants, star);
5816
- }
5817
- for (const variant of variants) {
5818
- const key = resolveExpression(scope, variant.key);
5819
- if (match(scope, sel, key)) {
5820
- return resolvePattern(scope, variant.value);
5821
- }
5822
- }
5823
- return getDefault(scope, variants, star);
5824
- }
5825
- function resolveComplexPattern(scope, ptn) {
5826
- if (scope.dirty.has(ptn)) {
5827
- scope.reportError(new RangeError("Cyclic reference"));
5828
- return new FluentNone2();
5829
- }
5830
- scope.dirty.add(ptn);
5831
- const result = [];
5832
- const useIsolating = scope.bundle._useIsolating && ptn.length > 1;
5833
- for (const elem of ptn) {
5834
- if (typeof elem === "string") {
5835
- result.push(scope.bundle._transform(elem));
5836
- continue;
5668
+ function parseAttributes() {
5669
+ let attrs = /* @__PURE__ */ Object.create(null);
5670
+ while (test(RE_ATTRIBUTE_START)) {
5671
+ let name = match1(RE_ATTRIBUTE_START);
5672
+ let value = parsePattern();
5673
+ if (value === null) {
5674
+ throw new SyntaxError("Expected attribute value");
5675
+ }
5676
+ attrs[name] = value;
5677
+ }
5678
+ return attrs;
5837
5679
  }
5838
- scope.placeables++;
5839
- if (scope.placeables > MAX_PLACEABLES) {
5840
- scope.dirty.delete(ptn);
5841
- throw new RangeError(`Too many placeables expanded: ${scope.placeables}, max allowed is ${MAX_PLACEABLES}`);
5680
+ function parsePattern() {
5681
+ let first;
5682
+ if (test(RE_TEXT_RUN)) {
5683
+ first = match1(RE_TEXT_RUN);
5684
+ }
5685
+ if (source[cursor] === "{" || source[cursor] === "}") {
5686
+ return parsePatternElements(first ? [first] : [], Infinity);
5687
+ }
5688
+ let indent = parseIndent();
5689
+ if (indent) {
5690
+ if (first) {
5691
+ return parsePatternElements([first, indent], indent.length);
5692
+ }
5693
+ indent.value = trim(indent.value, RE_LEADING_NEWLINES);
5694
+ return parsePatternElements([indent], indent.length);
5695
+ }
5696
+ if (first) {
5697
+ return trim(first, RE_TRAILING_SPACES);
5698
+ }
5699
+ return null;
5842
5700
  }
5843
- if (useIsolating) {
5844
- result.push(FSI);
5701
+ function parsePatternElements(elements = [], commonIndent) {
5702
+ while (true) {
5703
+ if (test(RE_TEXT_RUN)) {
5704
+ elements.push(match1(RE_TEXT_RUN));
5705
+ continue;
5706
+ }
5707
+ if (source[cursor] === "{") {
5708
+ elements.push(parsePlaceable());
5709
+ continue;
5710
+ }
5711
+ if (source[cursor] === "}") {
5712
+ throw new SyntaxError("Unbalanced closing brace");
5713
+ }
5714
+ let indent = parseIndent();
5715
+ if (indent) {
5716
+ elements.push(indent);
5717
+ commonIndent = Math.min(commonIndent, indent.length);
5718
+ continue;
5719
+ }
5720
+ break;
5721
+ }
5722
+ let lastIndex = elements.length - 1;
5723
+ let lastElement = elements[lastIndex];
5724
+ if (typeof lastElement === "string") {
5725
+ elements[lastIndex] = trim(lastElement, RE_TRAILING_SPACES);
5726
+ }
5727
+ let baked = [];
5728
+ for (let element of elements) {
5729
+ if (element instanceof Indent) {
5730
+ element = element.value.slice(0, element.value.length - commonIndent);
5731
+ }
5732
+ if (element) {
5733
+ baked.push(element);
5734
+ }
5735
+ }
5736
+ return baked;
5845
5737
  }
5846
- result.push(resolveExpression(scope, elem).toString(scope));
5847
- if (useIsolating) {
5848
- result.push(PDI);
5738
+ function parsePlaceable() {
5739
+ consumeToken(TOKEN_BRACE_OPEN, SyntaxError);
5740
+ let selector = parseInlineExpression();
5741
+ if (consumeToken(TOKEN_BRACE_CLOSE)) {
5742
+ return selector;
5743
+ }
5744
+ if (consumeToken(TOKEN_ARROW)) {
5745
+ let variants = parseVariants();
5746
+ consumeToken(TOKEN_BRACE_CLOSE, SyntaxError);
5747
+ return {
5748
+ type: "select",
5749
+ selector,
5750
+ ...variants
5751
+ };
5752
+ }
5753
+ throw new SyntaxError("Unclosed placeable");
5849
5754
  }
5850
- }
5851
- scope.dirty.delete(ptn);
5852
- return result.join("");
5853
- }
5854
- function resolvePattern(scope, value) {
5855
- if (typeof value === "string") {
5856
- return scope.bundle._transform(value);
5857
- }
5858
- return resolveComplexPattern(scope, value);
5859
- }
5860
- class Scope2 {
5861
- constructor(bundle, errors, args) {
5862
- this.dirty = /* @__PURE__ */ new WeakSet();
5863
- this.params = null;
5864
- this.placeables = 0;
5865
- this.bundle = bundle;
5866
- this.errors = errors;
5867
- this.args = args;
5868
- }
5869
- reportError(error) {
5870
- if (!this.errors || !(error instanceof Error)) {
5871
- throw error;
5755
+ function parseInlineExpression() {
5756
+ if (source[cursor] === "{") {
5757
+ return parsePlaceable();
5758
+ }
5759
+ if (test(RE_REFERENCE)) {
5760
+ let [, sigil, name, attr = null] = match2(RE_REFERENCE);
5761
+ if (sigil === "$") {
5762
+ return { type: "var", name };
5763
+ }
5764
+ if (consumeToken(TOKEN_PAREN_OPEN)) {
5765
+ let args = parseArguments();
5766
+ if (sigil === "-") {
5767
+ return { type: "term", name, attr, args };
5768
+ }
5769
+ if (RE_FUNCTION_NAME.test(name)) {
5770
+ return { type: "func", name, args };
5771
+ }
5772
+ throw new SyntaxError("Function names must be all upper-case");
5773
+ }
5774
+ if (sigil === "-") {
5775
+ return {
5776
+ type: "term",
5777
+ name,
5778
+ attr,
5779
+ args: []
5780
+ };
5781
+ }
5782
+ return { type: "mesg", name, attr };
5783
+ }
5784
+ return parseLiteral();
5872
5785
  }
5873
- this.errors.push(error);
5874
- }
5875
- memoizeIntlObject(ctor, opts) {
5876
- let cache2 = this.bundle._intls.get(ctor);
5877
- if (!cache2) {
5878
- cache2 = {};
5879
- this.bundle._intls.set(ctor, cache2);
5786
+ function parseArguments() {
5787
+ let args = [];
5788
+ while (true) {
5789
+ switch (source[cursor]) {
5790
+ case ")":
5791
+ cursor++;
5792
+ return args;
5793
+ case void 0:
5794
+ throw new SyntaxError("Unclosed argument list");
5795
+ }
5796
+ args.push(parseArgument());
5797
+ consumeToken(TOKEN_COMMA);
5798
+ }
5880
5799
  }
5881
- let id = JSON.stringify(opts);
5882
- if (!cache2[id]) {
5883
- cache2[id] = new ctor(this.bundle.locales, opts);
5800
+ function parseArgument() {
5801
+ let expr = parseInlineExpression();
5802
+ if (expr.type !== "mesg") {
5803
+ return expr;
5804
+ }
5805
+ if (consumeToken(TOKEN_COLON)) {
5806
+ return {
5807
+ type: "narg",
5808
+ name: expr.name,
5809
+ value: parseLiteral()
5810
+ };
5811
+ }
5812
+ return expr;
5884
5813
  }
5885
- return cache2[id];
5886
- }
5887
- }
5888
- function values(opts, allowed) {
5889
- const unwrapped = /* @__PURE__ */ Object.create(null);
5890
- for (const [name, opt] of Object.entries(opts)) {
5891
- if (allowed.includes(name)) {
5892
- unwrapped[name] = opt.valueOf();
5814
+ function parseVariants() {
5815
+ let variants = [];
5816
+ let count = 0;
5817
+ let star;
5818
+ while (test(RE_VARIANT_START)) {
5819
+ if (consumeChar("*")) {
5820
+ star = count;
5821
+ }
5822
+ let key = parseVariantKey();
5823
+ let value = parsePattern();
5824
+ if (value === null) {
5825
+ throw new SyntaxError("Expected variant value");
5826
+ }
5827
+ variants[count++] = { key, value };
5828
+ }
5829
+ if (count === 0) {
5830
+ return null;
5831
+ }
5832
+ if (star === void 0) {
5833
+ throw new SyntaxError("Expected default variant");
5834
+ }
5835
+ return { variants, star };
5836
+ }
5837
+ function parseVariantKey() {
5838
+ consumeToken(TOKEN_BRACKET_OPEN, SyntaxError);
5839
+ let key;
5840
+ if (test(RE_NUMBER_LITERAL)) {
5841
+ key = parseNumberLiteral();
5842
+ } else {
5843
+ key = {
5844
+ type: "str",
5845
+ value: match1(RE_IDENTIFIER)
5846
+ };
5847
+ }
5848
+ consumeToken(TOKEN_BRACKET_CLOSE, SyntaxError);
5849
+ return key;
5850
+ }
5851
+ function parseLiteral() {
5852
+ if (test(RE_NUMBER_LITERAL)) {
5853
+ return parseNumberLiteral();
5854
+ }
5855
+ if (source[cursor] === '"') {
5856
+ return parseStringLiteral();
5857
+ }
5858
+ throw new SyntaxError("Invalid expression");
5859
+ }
5860
+ function parseNumberLiteral() {
5861
+ let [, value, fraction = ""] = match2(RE_NUMBER_LITERAL);
5862
+ let precision = fraction.length;
5863
+ return {
5864
+ type: "num",
5865
+ value: parseFloat(value),
5866
+ precision
5867
+ };
5868
+ }
5869
+ function parseStringLiteral() {
5870
+ consumeChar('"', SyntaxError);
5871
+ let value = "";
5872
+ while (true) {
5873
+ value += match1(RE_STRING_RUN);
5874
+ if (source[cursor] === "\\") {
5875
+ value += parseEscapeSequence();
5876
+ continue;
5877
+ }
5878
+ if (consumeChar('"')) {
5879
+ return { type: "str", value };
5880
+ }
5881
+ throw new SyntaxError("Unclosed string literal");
5882
+ }
5883
+ }
5884
+ function parseEscapeSequence() {
5885
+ if (test(RE_STRING_ESCAPE)) {
5886
+ return match1(RE_STRING_ESCAPE);
5887
+ }
5888
+ if (test(RE_UNICODE_ESCAPE)) {
5889
+ let [, codepoint4, codepoint6] = match2(RE_UNICODE_ESCAPE);
5890
+ let codepoint = parseInt(codepoint4 || codepoint6, 16);
5891
+ return codepoint <= 55295 || 57344 <= codepoint ? String.fromCodePoint(codepoint) : "�";
5892
+ }
5893
+ throw new SyntaxError("Unknown escape sequence");
5894
+ }
5895
+ function parseIndent() {
5896
+ let start = cursor;
5897
+ consumeToken(TOKEN_BLANK);
5898
+ switch (source[cursor]) {
5899
+ case ".":
5900
+ case "[":
5901
+ case "*":
5902
+ case "}":
5903
+ case void 0:
5904
+ return false;
5905
+ case "{":
5906
+ return makeIndent(source.slice(start, cursor));
5907
+ }
5908
+ if (source[cursor - 1] === " ") {
5909
+ return makeIndent(source.slice(start, cursor));
5910
+ }
5911
+ return false;
5912
+ }
5913
+ function trim(text, re) {
5914
+ return text.replace(re, "");
5915
+ }
5916
+ function makeIndent(blank) {
5917
+ let value = blank.replace(RE_BLANK_LINES, "\n");
5918
+ let length = RE_INDENT.exec(blank)[1].length;
5919
+ return new Indent(value, length);
5893
5920
  }
5894
5921
  }
5895
- return unwrapped;
5896
- }
5897
- const NUMBER_ALLOWED = [
5898
- "unitDisplay",
5899
- "currencyDisplay",
5900
- "useGrouping",
5901
- "minimumIntegerDigits",
5902
- "minimumFractionDigits",
5903
- "maximumFractionDigits",
5904
- "minimumSignificantDigits",
5905
- "maximumSignificantDigits"
5906
- ];
5907
- function NUMBER(args, opts) {
5908
- let arg = args[0];
5909
- if (arg instanceof FluentNone2) {
5910
- return new FluentNone2(`NUMBER(${arg.valueOf()})`);
5911
- }
5912
- if (arg instanceof FluentNumber2) {
5913
- return new FluentNumber2(arg.valueOf(), {
5914
- ...arg.opts,
5915
- ...values(opts, NUMBER_ALLOWED)
5916
- });
5917
- }
5918
- if (arg instanceof FluentDateTime2) {
5919
- return new FluentNumber2(arg.valueOf(), {
5920
- ...values(opts, NUMBER_ALLOWED)
5921
- });
5922
- }
5923
- throw new TypeError("Invalid argument to NUMBER");
5924
- }
5925
- const DATETIME_ALLOWED = [
5926
- "dateStyle",
5927
- "timeStyle",
5928
- "fractionalSecondDigits",
5929
- "dayPeriod",
5930
- "hour12",
5931
- "weekday",
5932
- "era",
5933
- "year",
5934
- "month",
5935
- "day",
5936
- "hour",
5937
- "minute",
5938
- "second",
5939
- "timeZoneName"
5940
- ];
5941
- function DATETIME(args, opts) {
5942
- let arg = args[0];
5943
- if (arg instanceof FluentNone2) {
5944
- return new FluentNone2(`DATETIME(${arg.valueOf()})`);
5945
- }
5946
- if (arg instanceof FluentDateTime2) {
5947
- return new FluentDateTime2(arg.valueOf(), {
5948
- ...arg.opts,
5949
- ...values(opts, DATETIME_ALLOWED)
5950
- });
5951
- }
5952
- if (arg instanceof FluentNumber2) {
5953
- return new FluentDateTime2(arg.valueOf(), {
5954
- ...values(opts, DATETIME_ALLOWED)
5955
- });
5956
- }
5957
- throw new TypeError("Invalid argument to DATETIME");
5958
5922
  }
5959
- const cache = /* @__PURE__ */ new Map();
5960
- function getMemoizerForLocale(locales) {
5961
- const stringLocale = Array.isArray(locales) ? locales.join(" ") : locales;
5962
- let memoizer = cache.get(stringLocale);
5963
- if (memoizer === void 0) {
5964
- memoizer = /* @__PURE__ */ new Map();
5965
- cache.set(stringLocale, memoizer);
5923
+ class Indent {
5924
+ constructor(value, length) {
5925
+ this.value = value;
5926
+ this.length = length;
5966
5927
  }
5967
- return memoizer;
5968
5928
  }
5969
- class FluentBundle2 {
5929
+ class FluentType2 {
5970
5930
  /**
5971
- * Create an instance of `FluentBundle`.
5972
- *
5973
- * The `locales` argument is used to instantiate `Intl` formatters used by
5974
- * translations. The `options` object can be used to configure the bundle.
5975
- *
5976
- * Examples:
5977
- *
5978
- * let bundle = new FluentBundle(["en-US", "en"]);
5979
- *
5980
- * let bundle = new FluentBundle(locales, {useIsolating: false});
5981
- *
5982
- * let bundle = new FluentBundle(locales, {
5983
- * useIsolating: true,
5984
- * functions: {
5985
- * NODE_ENV: () => process.env.NODE_ENV
5986
- * }
5987
- * });
5988
- *
5989
- * Available options:
5990
- *
5991
- * - `functions` - an object of additional functions available to
5992
- * translations as builtins.
5993
- *
5994
- * - `useIsolating` - boolean specifying whether to use Unicode isolation
5995
- * marks (FSI, PDI) for bidi interpolations. Default: `true`.
5931
+ * Create a `FluentType` instance.
5996
5932
  *
5997
- * - `transform` - a function used to transform string parts of patterns.
5933
+ * @param value The JavaScript value to wrap.
5998
5934
  */
5999
- constructor(locales, { functions, useIsolating = true, transform = (v) => v } = {}) {
6000
- this._terms = /* @__PURE__ */ new Map();
6001
- this._messages = /* @__PURE__ */ new Map();
6002
- this.locales = Array.isArray(locales) ? locales : [locales];
6003
- this._functions = {
6004
- NUMBER,
6005
- DATETIME,
6006
- ...functions
6007
- };
6008
- this._useIsolating = useIsolating;
6009
- this._transform = transform;
6010
- this._intls = getMemoizerForLocale(locales);
5935
+ constructor(value) {
5936
+ this.value = value;
6011
5937
  }
6012
5938
  /**
6013
- * Check if a message is present in the bundle.
6014
- *
6015
- * @param id - The identifier of the message to check.
5939
+ * Unwrap the raw value stored by this `FluentType`.
6016
5940
  */
6017
- hasMessage(id) {
6018
- return this._messages.has(id);
5941
+ valueOf() {
5942
+ return this.value;
6019
5943
  }
5944
+ }
5945
+ class FluentNone2 extends FluentType2 {
6020
5946
  /**
6021
- * Return a raw unformatted message object from the bundle.
6022
- *
6023
- * Raw messages are `{value, attributes}` shapes containing translation units
6024
- * called `Patterns`. `Patterns` are implementation-specific; they should be
6025
- * treated as black boxes and formatted with `FluentBundle.formatPattern`.
6026
- *
6027
- * @param id - The identifier of the message to check.
5947
+ * Create an instance of `FluentNone` with an optional fallback value.
5948
+ * @param value The fallback value of this `FluentNone`.
6028
5949
  */
6029
- getMessage(id) {
6030
- return this._messages.get(id);
5950
+ constructor(value = "???") {
5951
+ super(value);
6031
5952
  }
6032
5953
  /**
6033
- * Add a translation resource to the bundle.
6034
- *
6035
- * The translation resource must be an instance of `FluentResource`.
6036
- *
6037
- * let res = new FluentResource("foo = Foo");
6038
- * bundle.addResource(res);
6039
- * bundle.getMessage("foo");
6040
- * // → {value: .., attributes: {..}}
6041
- *
6042
- * Available options:
6043
- *
6044
- * - `allowOverrides` - boolean specifying whether it's allowed to override
6045
- * an existing message or term with a new value. Default: `false`.
5954
+ * Format this `FluentNone` to the fallback string.
5955
+ */
5956
+ toString(scope) {
5957
+ return `{${this.value}}`;
5958
+ }
5959
+ }
5960
+ class FluentNumber2 extends FluentType2 {
5961
+ /**
5962
+ * Create an instance of `FluentNumber` with options to the
5963
+ * `Intl.NumberFormat` constructor.
6046
5964
  *
6047
- * @param res - FluentResource object.
6048
- * @param options
5965
+ * @param value The number value of this `FluentNumber`.
5966
+ * @param opts Options which will be passed to `Intl.NumberFormat`.
6049
5967
  */
6050
- addResource(res, { allowOverrides = false } = {}) {
6051
- const errors = [];
6052
- for (let i = 0; i < res.body.length; i++) {
6053
- let entry = res.body[i];
6054
- if (entry.id.startsWith("-")) {
6055
- if (allowOverrides === false && this._terms.has(entry.id)) {
6056
- errors.push(new Error(`Attempt to override an existing term: "${entry.id}"`));
6057
- continue;
6058
- }
6059
- this._terms.set(entry.id, entry);
6060
- } else {
6061
- if (allowOverrides === false && this._messages.has(entry.id)) {
6062
- errors.push(new Error(`Attempt to override an existing message: "${entry.id}"`));
6063
- continue;
6064
- }
6065
- this._messages.set(entry.id, entry);
6066
- }
5968
+ constructor(value, opts = {}) {
5969
+ super(value);
5970
+ this.opts = opts;
5971
+ }
5972
+ /**
5973
+ * Format this `FluentNumber` to a string.
5974
+ */
5975
+ toString(scope) {
5976
+ try {
5977
+ const nf = scope.memoizeIntlObject(Intl.NumberFormat, this.opts);
5978
+ return nf.format(this.value);
5979
+ } catch (err) {
5980
+ scope.reportError(err);
5981
+ return this.value.toString(10);
6067
5982
  }
6068
- return errors;
6069
5983
  }
5984
+ }
5985
+ class FluentDateTime2 extends FluentType2 {
6070
5986
  /**
6071
- * Format a `Pattern` to a string.
6072
- *
6073
- * Format a raw `Pattern` into a string. `args` will be used to resolve
6074
- * references to variables passed as arguments to the translation.
6075
- *
6076
- * In case of errors `formatPattern` will try to salvage as much of the
6077
- * translation as possible and will still return a string. For performance
6078
- * reasons, the encountered errors are not returned but instead are appended
6079
- * to the `errors` array passed as the third argument.
6080
- *
6081
- * let errors = [];
6082
- * bundle.addResource(
6083
- * new FluentResource("hello = Hello, {$name}!"));
6084
- *
6085
- * let hello = bundle.getMessage("hello");
6086
- * if (hello.value) {
6087
- * bundle.formatPattern(hello.value, {name: "Jane"}, errors);
6088
- * // Returns "Hello, Jane!" and `errors` is empty.
6089
- *
6090
- * bundle.formatPattern(hello.value, undefined, errors);
6091
- * // Returns "Hello, {$name}!" and `errors` is now:
6092
- * // [<ReferenceError: Unknown variable: name>]
6093
- * }
5987
+ * Create an instance of `FluentDateTime` with options to the
5988
+ * `Intl.DateTimeFormat` constructor.
6094
5989
  *
6095
- * If `errors` is omitted, the first encountered error will be thrown.
5990
+ * @param value The number value of this `FluentDateTime`, in milliseconds.
5991
+ * @param opts Options which will be passed to `Intl.DateTimeFormat`.
6096
5992
  */
6097
- formatPattern(pattern, args = null, errors = null) {
6098
- if (typeof pattern === "string") {
6099
- return this._transform(pattern);
6100
- }
6101
- let scope = new Scope2(this, errors, args);
5993
+ constructor(value, opts = {}) {
5994
+ super(value);
5995
+ this.opts = opts;
5996
+ }
5997
+ /**
5998
+ * Format this `FluentDateTime` to a string.
5999
+ */
6000
+ toString(scope) {
6102
6001
  try {
6103
- let value = resolveComplexPattern(scope, pattern);
6104
- return value.toString(scope);
6002
+ const dtf = scope.memoizeIntlObject(Intl.DateTimeFormat, this.opts);
6003
+ return dtf.format(this.value);
6105
6004
  } catch (err) {
6106
- if (scope.errors && err instanceof Error) {
6107
- scope.errors.push(err);
6108
- return new FluentNone2().toString(scope);
6109
- }
6110
- throw err;
6005
+ scope.reportError(err);
6006
+ return new Date(this.value).toISOString();
6111
6007
  }
6112
6008
  }
6113
6009
  }
6114
- const RE_MESSAGE_START = /^(-?[a-zA-Z][\w-]*) *= */gm;
6115
- const RE_ATTRIBUTE_START = /\.([a-zA-Z][\w-]*) *= */y;
6116
- const RE_VARIANT_START = /\*?\[/y;
6117
- const RE_NUMBER_LITERAL = /(-?[0-9]+(?:\.([0-9]+))?)/y;
6118
- const RE_IDENTIFIER = /([a-zA-Z][\w-]*)/y;
6119
- const RE_REFERENCE = /([$-])?([a-zA-Z][\w-]*)(?:\.([a-zA-Z][\w-]*))?/y;
6120
- const RE_FUNCTION_NAME = /^[A-Z][A-Z0-9_-]*$/;
6121
- const RE_TEXT_RUN = /([^{}\n\r]+)/y;
6122
- const RE_STRING_RUN = /([^\\"\n\r]*)/y;
6123
- const RE_STRING_ESCAPE = /\\([\\"])/y;
6124
- const RE_UNICODE_ESCAPE = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{6})/y;
6125
- const RE_LEADING_NEWLINES = /^\n+/;
6126
- const RE_TRAILING_SPACES = / +$/;
6127
- const RE_BLANK_LINES = / *\r?\n/g;
6128
- const RE_INDENT = /( *)$/;
6129
- const TOKEN_BRACE_OPEN = /{\s*/y;
6130
- const TOKEN_BRACE_CLOSE = /\s*}/y;
6131
- const TOKEN_BRACKET_OPEN = /\[\s*/y;
6132
- const TOKEN_BRACKET_CLOSE = /\s*] */y;
6133
- const TOKEN_PAREN_OPEN = /\s*\(\s*/y;
6134
- const TOKEN_ARROW = /\s*->\s*/y;
6135
- const TOKEN_COLON = /\s*:\s*/y;
6136
- const TOKEN_COMMA = /\s*,?\s*/y;
6137
- const TOKEN_BLANK = /\s+/y;
6138
- class FluentResource {
6139
- constructor(source) {
6140
- this.body = [];
6141
- RE_MESSAGE_START.lastIndex = 0;
6142
- let cursor = 0;
6143
- while (true) {
6144
- let next = RE_MESSAGE_START.exec(source);
6145
- if (next === null) {
6146
- break;
6147
- }
6148
- cursor = RE_MESSAGE_START.lastIndex;
6149
- try {
6150
- this.body.push(parseMessage(next[1]));
6151
- } catch (err) {
6152
- if (err instanceof SyntaxError) {
6153
- continue;
6154
- }
6155
- throw err;
6156
- }
6010
+ const MAX_PLACEABLES = 100;
6011
+ const FSI = "⁨";
6012
+ const PDI = "⁩";
6013
+ function match(scope, selector, key) {
6014
+ if (key === selector) {
6015
+ return true;
6016
+ }
6017
+ if (key instanceof FluentNumber2 && selector instanceof FluentNumber2 && key.value === selector.value) {
6018
+ return true;
6019
+ }
6020
+ if (selector instanceof FluentNumber2 && typeof key === "string") {
6021
+ let category = scope.memoizeIntlObject(Intl.PluralRules, selector.opts).select(selector.value);
6022
+ if (key === category) {
6023
+ return true;
6157
6024
  }
6158
- function test(re) {
6159
- re.lastIndex = cursor;
6160
- return re.test(source);
6025
+ }
6026
+ return false;
6027
+ }
6028
+ function getDefault(scope, variants, star) {
6029
+ if (variants[star]) {
6030
+ return resolvePattern(scope, variants[star].value);
6031
+ }
6032
+ scope.reportError(new RangeError("No default"));
6033
+ return new FluentNone2();
6034
+ }
6035
+ function getArguments(scope, args) {
6036
+ const positional = [];
6037
+ const named = /* @__PURE__ */ Object.create(null);
6038
+ for (const arg of args) {
6039
+ if (arg.type === "narg") {
6040
+ named[arg.name] = resolveExpression(scope, arg.value);
6041
+ } else {
6042
+ positional.push(resolveExpression(scope, arg));
6161
6043
  }
6162
- function consumeChar(char, errorClass) {
6163
- if (source[cursor] === char) {
6164
- cursor++;
6165
- return true;
6166
- }
6167
- if (errorClass) {
6168
- throw new errorClass(`Expected ${char}`);
6169
- }
6170
- return false;
6044
+ }
6045
+ return { positional, named };
6046
+ }
6047
+ function resolveExpression(scope, expr) {
6048
+ switch (expr.type) {
6049
+ case "str":
6050
+ return expr.value;
6051
+ case "num":
6052
+ return new FluentNumber2(expr.value, {
6053
+ minimumFractionDigits: expr.precision
6054
+ });
6055
+ case "var":
6056
+ return resolveVariableReference(scope, expr);
6057
+ case "mesg":
6058
+ return resolveMessageReference(scope, expr);
6059
+ case "term":
6060
+ return resolveTermReference(scope, expr);
6061
+ case "func":
6062
+ return resolveFunctionReference(scope, expr);
6063
+ case "select":
6064
+ return resolveSelectExpression(scope, expr);
6065
+ default:
6066
+ return new FluentNone2();
6067
+ }
6068
+ }
6069
+ function resolveVariableReference(scope, { name }) {
6070
+ let arg;
6071
+ if (scope.params) {
6072
+ if (Object.prototype.hasOwnProperty.call(scope.params, name)) {
6073
+ arg = scope.params[name];
6074
+ } else {
6075
+ return new FluentNone2(`$${name}`);
6171
6076
  }
6172
- function consumeToken(re, errorClass) {
6173
- if (test(re)) {
6174
- cursor = re.lastIndex;
6175
- return true;
6176
- }
6177
- if (errorClass) {
6178
- throw new errorClass(`Expected ${re.toString()}`);
6077
+ } else if (scope.args && Object.prototype.hasOwnProperty.call(scope.args, name)) {
6078
+ arg = scope.args[name];
6079
+ } else {
6080
+ scope.reportError(new ReferenceError(`Unknown variable: $${name}`));
6081
+ return new FluentNone2(`$${name}`);
6082
+ }
6083
+ if (arg instanceof FluentType2) {
6084
+ return arg;
6085
+ }
6086
+ switch (typeof arg) {
6087
+ case "string":
6088
+ return arg;
6089
+ case "number":
6090
+ return new FluentNumber2(arg);
6091
+ case "object":
6092
+ if (arg instanceof Date) {
6093
+ return new FluentDateTime2(arg.getTime());
6179
6094
  }
6180
- return false;
6095
+ default:
6096
+ scope.reportError(new TypeError(`Variable type not supported: $${name}, ${typeof arg}`));
6097
+ return new FluentNone2(`$${name}`);
6098
+ }
6099
+ }
6100
+ function resolveMessageReference(scope, { name, attr }) {
6101
+ const message = scope.bundle._messages.get(name);
6102
+ if (!message) {
6103
+ scope.reportError(new ReferenceError(`Unknown message: ${name}`));
6104
+ return new FluentNone2(name);
6105
+ }
6106
+ if (attr) {
6107
+ const attribute = message.attributes[attr];
6108
+ if (attribute) {
6109
+ return resolvePattern(scope, attribute);
6181
6110
  }
6182
- function match2(re) {
6183
- re.lastIndex = cursor;
6184
- let result = re.exec(source);
6185
- if (result === null) {
6186
- throw new SyntaxError(`Expected ${re.toString()}`);
6187
- }
6188
- cursor = re.lastIndex;
6189
- return result;
6111
+ scope.reportError(new ReferenceError(`Unknown attribute: ${attr}`));
6112
+ return new FluentNone2(`${name}.${attr}`);
6113
+ }
6114
+ if (message.value) {
6115
+ return resolvePattern(scope, message.value);
6116
+ }
6117
+ scope.reportError(new ReferenceError(`No value: ${name}`));
6118
+ return new FluentNone2(name);
6119
+ }
6120
+ function resolveTermReference(scope, { name, attr, args }) {
6121
+ const id = `-${name}`;
6122
+ const term = scope.bundle._terms.get(id);
6123
+ if (!term) {
6124
+ scope.reportError(new ReferenceError(`Unknown term: ${id}`));
6125
+ return new FluentNone2(id);
6126
+ }
6127
+ if (attr) {
6128
+ const attribute = term.attributes[attr];
6129
+ if (attribute) {
6130
+ scope.params = getArguments(scope, args).named;
6131
+ const resolved2 = resolvePattern(scope, attribute);
6132
+ scope.params = null;
6133
+ return resolved2;
6190
6134
  }
6191
- function match1(re) {
6192
- return match2(re)[1];
6135
+ scope.reportError(new ReferenceError(`Unknown attribute: ${attr}`));
6136
+ return new FluentNone2(`${id}.${attr}`);
6137
+ }
6138
+ scope.params = getArguments(scope, args).named;
6139
+ const resolved = resolvePattern(scope, term.value);
6140
+ scope.params = null;
6141
+ return resolved;
6142
+ }
6143
+ function resolveFunctionReference(scope, { name, args }) {
6144
+ let func = scope.bundle._functions[name];
6145
+ if (!func) {
6146
+ scope.reportError(new ReferenceError(`Unknown function: ${name}()`));
6147
+ return new FluentNone2(`${name}()`);
6148
+ }
6149
+ if (typeof func !== "function") {
6150
+ scope.reportError(new TypeError(`Function ${name}() is not callable`));
6151
+ return new FluentNone2(`${name}()`);
6152
+ }
6153
+ try {
6154
+ let resolved = getArguments(scope, args);
6155
+ return func(resolved.positional, resolved.named);
6156
+ } catch (err) {
6157
+ scope.reportError(err);
6158
+ return new FluentNone2(`${name}()`);
6159
+ }
6160
+ }
6161
+ function resolveSelectExpression(scope, { selector, variants, star }) {
6162
+ let sel = resolveExpression(scope, selector);
6163
+ if (sel instanceof FluentNone2) {
6164
+ return getDefault(scope, variants, star);
6165
+ }
6166
+ for (const variant of variants) {
6167
+ const key = resolveExpression(scope, variant.key);
6168
+ if (match(scope, sel, key)) {
6169
+ return resolvePattern(scope, variant.value);
6193
6170
  }
6194
- function parseMessage(id) {
6195
- let value = parsePattern();
6196
- let attributes = parseAttributes();
6197
- if (value === null && Object.keys(attributes).length === 0) {
6198
- throw new SyntaxError("Expected message value or attributes");
6199
- }
6200
- return { id, value, attributes };
6171
+ }
6172
+ return getDefault(scope, variants, star);
6173
+ }
6174
+ function resolveComplexPattern(scope, ptn) {
6175
+ if (scope.dirty.has(ptn)) {
6176
+ scope.reportError(new RangeError("Cyclic reference"));
6177
+ return new FluentNone2();
6178
+ }
6179
+ scope.dirty.add(ptn);
6180
+ const result = [];
6181
+ const useIsolating = scope.bundle._useIsolating && ptn.length > 1;
6182
+ for (const elem of ptn) {
6183
+ if (typeof elem === "string") {
6184
+ result.push(scope.bundle._transform(elem));
6185
+ continue;
6201
6186
  }
6202
- function parseAttributes() {
6203
- let attrs = /* @__PURE__ */ Object.create(null);
6204
- while (test(RE_ATTRIBUTE_START)) {
6205
- let name = match1(RE_ATTRIBUTE_START);
6206
- let value = parsePattern();
6207
- if (value === null) {
6208
- throw new SyntaxError("Expected attribute value");
6209
- }
6210
- attrs[name] = value;
6211
- }
6212
- return attrs;
6187
+ scope.placeables++;
6188
+ if (scope.placeables > MAX_PLACEABLES) {
6189
+ scope.dirty.delete(ptn);
6190
+ throw new RangeError(`Too many placeables expanded: ${scope.placeables}, max allowed is ${MAX_PLACEABLES}`);
6213
6191
  }
6214
- function parsePattern() {
6215
- let first;
6216
- if (test(RE_TEXT_RUN)) {
6217
- first = match1(RE_TEXT_RUN);
6218
- }
6219
- if (source[cursor] === "{" || source[cursor] === "}") {
6220
- return parsePatternElements(first ? [first] : [], Infinity);
6221
- }
6222
- let indent = parseIndent();
6223
- if (indent) {
6224
- if (first) {
6225
- return parsePatternElements([first, indent], indent.length);
6226
- }
6227
- indent.value = trim(indent.value, RE_LEADING_NEWLINES);
6228
- return parsePatternElements([indent], indent.length);
6229
- }
6230
- if (first) {
6231
- return trim(first, RE_TRAILING_SPACES);
6232
- }
6233
- return null;
6192
+ if (useIsolating) {
6193
+ result.push(FSI);
6234
6194
  }
6235
- function parsePatternElements(elements = [], commonIndent) {
6236
- while (true) {
6237
- if (test(RE_TEXT_RUN)) {
6238
- elements.push(match1(RE_TEXT_RUN));
6239
- continue;
6240
- }
6241
- if (source[cursor] === "{") {
6242
- elements.push(parsePlaceable());
6243
- continue;
6244
- }
6245
- if (source[cursor] === "}") {
6246
- throw new SyntaxError("Unbalanced closing brace");
6247
- }
6248
- let indent = parseIndent();
6249
- if (indent) {
6250
- elements.push(indent);
6251
- commonIndent = Math.min(commonIndent, indent.length);
6252
- continue;
6253
- }
6254
- break;
6255
- }
6256
- let lastIndex = elements.length - 1;
6257
- let lastElement = elements[lastIndex];
6258
- if (typeof lastElement === "string") {
6259
- elements[lastIndex] = trim(lastElement, RE_TRAILING_SPACES);
6260
- }
6261
- let baked = [];
6262
- for (let element of elements) {
6263
- if (element instanceof Indent) {
6264
- element = element.value.slice(0, element.value.length - commonIndent);
6265
- }
6266
- if (element) {
6267
- baked.push(element);
6268
- }
6269
- }
6270
- return baked;
6195
+ result.push(resolveExpression(scope, elem).toString(scope));
6196
+ if (useIsolating) {
6197
+ result.push(PDI);
6271
6198
  }
6272
- function parsePlaceable() {
6273
- consumeToken(TOKEN_BRACE_OPEN, SyntaxError);
6274
- let selector = parseInlineExpression();
6275
- if (consumeToken(TOKEN_BRACE_CLOSE)) {
6276
- return selector;
6277
- }
6278
- if (consumeToken(TOKEN_ARROW)) {
6279
- let variants = parseVariants();
6280
- consumeToken(TOKEN_BRACE_CLOSE, SyntaxError);
6281
- return {
6282
- type: "select",
6283
- selector,
6284
- ...variants
6285
- };
6286
- }
6287
- throw new SyntaxError("Unclosed placeable");
6199
+ }
6200
+ scope.dirty.delete(ptn);
6201
+ return result.join("");
6202
+ }
6203
+ function resolvePattern(scope, value) {
6204
+ if (typeof value === "string") {
6205
+ return scope.bundle._transform(value);
6206
+ }
6207
+ return resolveComplexPattern(scope, value);
6208
+ }
6209
+ class Scope2 {
6210
+ constructor(bundle, errors, args) {
6211
+ this.dirty = /* @__PURE__ */ new WeakSet();
6212
+ this.params = null;
6213
+ this.placeables = 0;
6214
+ this.bundle = bundle;
6215
+ this.errors = errors;
6216
+ this.args = args;
6217
+ }
6218
+ reportError(error) {
6219
+ if (!this.errors || !(error instanceof Error)) {
6220
+ throw error;
6288
6221
  }
6289
- function parseInlineExpression() {
6290
- if (source[cursor] === "{") {
6291
- return parsePlaceable();
6292
- }
6293
- if (test(RE_REFERENCE)) {
6294
- let [, sigil, name, attr = null] = match2(RE_REFERENCE);
6295
- if (sigil === "$") {
6296
- return { type: "var", name };
6297
- }
6298
- if (consumeToken(TOKEN_PAREN_OPEN)) {
6299
- let args = parseArguments();
6300
- if (sigil === "-") {
6301
- return { type: "term", name, attr, args };
6302
- }
6303
- if (RE_FUNCTION_NAME.test(name)) {
6304
- return { type: "func", name, args };
6305
- }
6306
- throw new SyntaxError("Function names must be all upper-case");
6307
- }
6308
- if (sigil === "-") {
6309
- return {
6310
- type: "term",
6311
- name,
6312
- attr,
6313
- args: []
6314
- };
6315
- }
6316
- return { type: "mesg", name, attr };
6317
- }
6318
- return parseLiteral();
6222
+ this.errors.push(error);
6223
+ }
6224
+ memoizeIntlObject(ctor, opts) {
6225
+ let cache2 = this.bundle._intls.get(ctor);
6226
+ if (!cache2) {
6227
+ cache2 = {};
6228
+ this.bundle._intls.set(ctor, cache2);
6319
6229
  }
6320
- function parseArguments() {
6321
- let args = [];
6322
- while (true) {
6323
- switch (source[cursor]) {
6324
- case ")":
6325
- cursor++;
6326
- return args;
6327
- case void 0:
6328
- throw new SyntaxError("Unclosed argument list");
6329
- }
6330
- args.push(parseArgument());
6331
- consumeToken(TOKEN_COMMA);
6332
- }
6230
+ let id = JSON.stringify(opts);
6231
+ if (!cache2[id]) {
6232
+ cache2[id] = new ctor(this.bundle.locales, opts);
6333
6233
  }
6334
- function parseArgument() {
6335
- let expr = parseInlineExpression();
6336
- if (expr.type !== "mesg") {
6337
- return expr;
6338
- }
6339
- if (consumeToken(TOKEN_COLON)) {
6340
- return {
6341
- type: "narg",
6342
- name: expr.name,
6343
- value: parseLiteral()
6344
- };
6345
- }
6346
- return expr;
6234
+ return cache2[id];
6235
+ }
6236
+ }
6237
+ function values(opts, allowed) {
6238
+ const unwrapped = /* @__PURE__ */ Object.create(null);
6239
+ for (const [name, opt] of Object.entries(opts)) {
6240
+ if (allowed.includes(name)) {
6241
+ unwrapped[name] = opt.valueOf();
6347
6242
  }
6348
- function parseVariants() {
6349
- let variants = [];
6350
- let count = 0;
6351
- let star;
6352
- while (test(RE_VARIANT_START)) {
6353
- if (consumeChar("*")) {
6354
- star = count;
6355
- }
6356
- let key = parseVariantKey();
6357
- let value = parsePattern();
6358
- if (value === null) {
6359
- throw new SyntaxError("Expected variant value");
6243
+ }
6244
+ return unwrapped;
6245
+ }
6246
+ const NUMBER_ALLOWED = [
6247
+ "unitDisplay",
6248
+ "currencyDisplay",
6249
+ "useGrouping",
6250
+ "minimumIntegerDigits",
6251
+ "minimumFractionDigits",
6252
+ "maximumFractionDigits",
6253
+ "minimumSignificantDigits",
6254
+ "maximumSignificantDigits"
6255
+ ];
6256
+ function NUMBER(args, opts) {
6257
+ let arg = args[0];
6258
+ if (arg instanceof FluentNone2) {
6259
+ return new FluentNone2(`NUMBER(${arg.valueOf()})`);
6260
+ }
6261
+ if (arg instanceof FluentNumber2) {
6262
+ return new FluentNumber2(arg.valueOf(), {
6263
+ ...arg.opts,
6264
+ ...values(opts, NUMBER_ALLOWED)
6265
+ });
6266
+ }
6267
+ if (arg instanceof FluentDateTime2) {
6268
+ return new FluentNumber2(arg.valueOf(), {
6269
+ ...values(opts, NUMBER_ALLOWED)
6270
+ });
6271
+ }
6272
+ throw new TypeError("Invalid argument to NUMBER");
6273
+ }
6274
+ const DATETIME_ALLOWED = [
6275
+ "dateStyle",
6276
+ "timeStyle",
6277
+ "fractionalSecondDigits",
6278
+ "dayPeriod",
6279
+ "hour12",
6280
+ "weekday",
6281
+ "era",
6282
+ "year",
6283
+ "month",
6284
+ "day",
6285
+ "hour",
6286
+ "minute",
6287
+ "second",
6288
+ "timeZoneName"
6289
+ ];
6290
+ function DATETIME(args, opts) {
6291
+ let arg = args[0];
6292
+ if (arg instanceof FluentNone2) {
6293
+ return new FluentNone2(`DATETIME(${arg.valueOf()})`);
6294
+ }
6295
+ if (arg instanceof FluentDateTime2) {
6296
+ return new FluentDateTime2(arg.valueOf(), {
6297
+ ...arg.opts,
6298
+ ...values(opts, DATETIME_ALLOWED)
6299
+ });
6300
+ }
6301
+ if (arg instanceof FluentNumber2) {
6302
+ return new FluentDateTime2(arg.valueOf(), {
6303
+ ...values(opts, DATETIME_ALLOWED)
6304
+ });
6305
+ }
6306
+ throw new TypeError("Invalid argument to DATETIME");
6307
+ }
6308
+ const cache = /* @__PURE__ */ new Map();
6309
+ function getMemoizerForLocale(locales) {
6310
+ const stringLocale = Array.isArray(locales) ? locales.join(" ") : locales;
6311
+ let memoizer = cache.get(stringLocale);
6312
+ if (memoizer === void 0) {
6313
+ memoizer = /* @__PURE__ */ new Map();
6314
+ cache.set(stringLocale, memoizer);
6315
+ }
6316
+ return memoizer;
6317
+ }
6318
+ class FluentBundle2 {
6319
+ /**
6320
+ * Create an instance of `FluentBundle`.
6321
+ *
6322
+ * The `locales` argument is used to instantiate `Intl` formatters used by
6323
+ * translations. The `options` object can be used to configure the bundle.
6324
+ *
6325
+ * Examples:
6326
+ *
6327
+ * let bundle = new FluentBundle(["en-US", "en"]);
6328
+ *
6329
+ * let bundle = new FluentBundle(locales, {useIsolating: false});
6330
+ *
6331
+ * let bundle = new FluentBundle(locales, {
6332
+ * useIsolating: true,
6333
+ * functions: {
6334
+ * NODE_ENV: () => process.env.NODE_ENV
6335
+ * }
6336
+ * });
6337
+ *
6338
+ * Available options:
6339
+ *
6340
+ * - `functions` - an object of additional functions available to
6341
+ * translations as builtins.
6342
+ *
6343
+ * - `useIsolating` - boolean specifying whether to use Unicode isolation
6344
+ * marks (FSI, PDI) for bidi interpolations. Default: `true`.
6345
+ *
6346
+ * - `transform` - a function used to transform string parts of patterns.
6347
+ */
6348
+ constructor(locales, { functions, useIsolating = true, transform = (v) => v } = {}) {
6349
+ this._terms = /* @__PURE__ */ new Map();
6350
+ this._messages = /* @__PURE__ */ new Map();
6351
+ this.locales = Array.isArray(locales) ? locales : [locales];
6352
+ this._functions = {
6353
+ NUMBER,
6354
+ DATETIME,
6355
+ ...functions
6356
+ };
6357
+ this._useIsolating = useIsolating;
6358
+ this._transform = transform;
6359
+ this._intls = getMemoizerForLocale(locales);
6360
+ }
6361
+ /**
6362
+ * Check if a message is present in the bundle.
6363
+ *
6364
+ * @param id - The identifier of the message to check.
6365
+ */
6366
+ hasMessage(id) {
6367
+ return this._messages.has(id);
6368
+ }
6369
+ /**
6370
+ * Return a raw unformatted message object from the bundle.
6371
+ *
6372
+ * Raw messages are `{value, attributes}` shapes containing translation units
6373
+ * called `Patterns`. `Patterns` are implementation-specific; they should be
6374
+ * treated as black boxes and formatted with `FluentBundle.formatPattern`.
6375
+ *
6376
+ * @param id - The identifier of the message to check.
6377
+ */
6378
+ getMessage(id) {
6379
+ return this._messages.get(id);
6380
+ }
6381
+ /**
6382
+ * Add a translation resource to the bundle.
6383
+ *
6384
+ * The translation resource must be an instance of `FluentResource`.
6385
+ *
6386
+ * let res = new FluentResource("foo = Foo");
6387
+ * bundle.addResource(res);
6388
+ * bundle.getMessage("foo");
6389
+ * // → {value: .., attributes: {..}}
6390
+ *
6391
+ * Available options:
6392
+ *
6393
+ * - `allowOverrides` - boolean specifying whether it's allowed to override
6394
+ * an existing message or term with a new value. Default: `false`.
6395
+ *
6396
+ * @param res - FluentResource object.
6397
+ * @param options
6398
+ */
6399
+ addResource(res, { allowOverrides = false } = {}) {
6400
+ const errors = [];
6401
+ for (let i = 0; i < res.body.length; i++) {
6402
+ let entry = res.body[i];
6403
+ if (entry.id.startsWith("-")) {
6404
+ if (allowOverrides === false && this._terms.has(entry.id)) {
6405
+ errors.push(new Error(`Attempt to override an existing term: "${entry.id}"`));
6406
+ continue;
6360
6407
  }
6361
- variants[count++] = { key, value };
6362
- }
6363
- if (count === 0) {
6364
- return null;
6365
- }
6366
- if (star === void 0) {
6367
- throw new SyntaxError("Expected default variant");
6368
- }
6369
- return { variants, star };
6370
- }
6371
- function parseVariantKey() {
6372
- consumeToken(TOKEN_BRACKET_OPEN, SyntaxError);
6373
- let key;
6374
- if (test(RE_NUMBER_LITERAL)) {
6375
- key = parseNumberLiteral();
6408
+ this._terms.set(entry.id, entry);
6376
6409
  } else {
6377
- key = {
6378
- type: "str",
6379
- value: match1(RE_IDENTIFIER)
6380
- };
6381
- }
6382
- consumeToken(TOKEN_BRACKET_CLOSE, SyntaxError);
6383
- return key;
6384
- }
6385
- function parseLiteral() {
6386
- if (test(RE_NUMBER_LITERAL)) {
6387
- return parseNumberLiteral();
6388
- }
6389
- if (source[cursor] === '"') {
6390
- return parseStringLiteral();
6391
- }
6392
- throw new SyntaxError("Invalid expression");
6393
- }
6394
- function parseNumberLiteral() {
6395
- let [, value, fraction = ""] = match2(RE_NUMBER_LITERAL);
6396
- let precision = fraction.length;
6397
- return {
6398
- type: "num",
6399
- value: parseFloat(value),
6400
- precision
6401
- };
6402
- }
6403
- function parseStringLiteral() {
6404
- consumeChar('"', SyntaxError);
6405
- let value = "";
6406
- while (true) {
6407
- value += match1(RE_STRING_RUN);
6408
- if (source[cursor] === "\\") {
6409
- value += parseEscapeSequence();
6410
+ if (allowOverrides === false && this._messages.has(entry.id)) {
6411
+ errors.push(new Error(`Attempt to override an existing message: "${entry.id}"`));
6410
6412
  continue;
6411
6413
  }
6412
- if (consumeChar('"')) {
6413
- return { type: "str", value };
6414
- }
6415
- throw new SyntaxError("Unclosed string literal");
6414
+ this._messages.set(entry.id, entry);
6416
6415
  }
6417
6416
  }
6418
- function parseEscapeSequence() {
6419
- if (test(RE_STRING_ESCAPE)) {
6420
- return match1(RE_STRING_ESCAPE);
6421
- }
6422
- if (test(RE_UNICODE_ESCAPE)) {
6423
- let [, codepoint4, codepoint6] = match2(RE_UNICODE_ESCAPE);
6424
- let codepoint = parseInt(codepoint4 || codepoint6, 16);
6425
- return codepoint <= 55295 || 57344 <= codepoint ? String.fromCodePoint(codepoint) : "�";
6426
- }
6427
- throw new SyntaxError("Unknown escape sequence");
6417
+ return errors;
6418
+ }
6419
+ /**
6420
+ * Format a `Pattern` to a string.
6421
+ *
6422
+ * Format a raw `Pattern` into a string. `args` will be used to resolve
6423
+ * references to variables passed as arguments to the translation.
6424
+ *
6425
+ * In case of errors `formatPattern` will try to salvage as much of the
6426
+ * translation as possible and will still return a string. For performance
6427
+ * reasons, the encountered errors are not returned but instead are appended
6428
+ * to the `errors` array passed as the third argument.
6429
+ *
6430
+ * let errors = [];
6431
+ * bundle.addResource(
6432
+ * new FluentResource("hello = Hello, {$name}!"));
6433
+ *
6434
+ * let hello = bundle.getMessage("hello");
6435
+ * if (hello.value) {
6436
+ * bundle.formatPattern(hello.value, {name: "Jane"}, errors);
6437
+ * // Returns "Hello, Jane!" and `errors` is empty.
6438
+ *
6439
+ * bundle.formatPattern(hello.value, undefined, errors);
6440
+ * // Returns "Hello, {$name}!" and `errors` is now:
6441
+ * // [<ReferenceError: Unknown variable: name>]
6442
+ * }
6443
+ *
6444
+ * If `errors` is omitted, the first encountered error will be thrown.
6445
+ */
6446
+ formatPattern(pattern, args = null, errors = null) {
6447
+ if (typeof pattern === "string") {
6448
+ return this._transform(pattern);
6428
6449
  }
6429
- function parseIndent() {
6430
- let start = cursor;
6431
- consumeToken(TOKEN_BLANK);
6432
- switch (source[cursor]) {
6433
- case ".":
6434
- case "[":
6435
- case "*":
6436
- case "}":
6437
- case void 0:
6438
- return false;
6439
- case "{":
6440
- return makeIndent(source.slice(start, cursor));
6441
- }
6442
- if (source[cursor - 1] === " ") {
6443
- return makeIndent(source.slice(start, cursor));
6450
+ let scope = new Scope2(this, errors, args);
6451
+ try {
6452
+ let value = resolveComplexPattern(scope, pattern);
6453
+ return value.toString(scope);
6454
+ } catch (err) {
6455
+ if (scope.errors && err instanceof Error) {
6456
+ scope.errors.push(err);
6457
+ return new FluentNone2().toString(scope);
6444
6458
  }
6445
- return false;
6446
- }
6447
- function trim(text, re) {
6448
- return text.replace(re, "");
6449
- }
6450
- function makeIndent(blank) {
6451
- let value = blank.replace(RE_BLANK_LINES, "\n");
6452
- let length = RE_INDENT.exec(blank)[1].length;
6453
- return new Indent(value, length);
6459
+ throw err;
6454
6460
  }
6455
6461
  }
6456
6462
  }
6457
- class Indent {
6458
- constructor(value, length) {
6459
- this.value = value;
6460
- this.length = length;
6461
- }
6462
- }
6463
6463
  class RawBundleSource {
6464
6464
  constructor(params) {
6465
6465
  __publicField(this, "bundles", /* @__PURE__ */ new Map());
@@ -6783,6 +6783,63 @@ class BaseLocaleManager {
6783
6783
  return `${locales}|${[...namespaces].sort()}`;
6784
6784
  }
6785
6785
  }
6786
+ const DEFAULT_FETCH = (key, init) => fetch(`/locales/${key}`, init);
6787
+ class HTTPBundleSource {
6788
+ constructor(params) {
6789
+ __publicField(this, "fetch");
6790
+ __publicField(this, "resources", /* @__PURE__ */ new Map());
6791
+ this.fetch = params.fetch ?? DEFAULT_FETCH;
6792
+ }
6793
+ addSource(resource) {
6794
+ throw new Error("Method not implemented.");
6795
+ }
6796
+ getKey(locale, namespace) {
6797
+ return `${namespace}/${locale}`;
6798
+ }
6799
+ getBundles(locales, namespaces) {
6800
+ const bundles = [];
6801
+ const promises = [];
6802
+ for (const locale of locales) {
6803
+ const bundle = new FluentBundle2(locale);
6804
+ bundles.push(bundle);
6805
+ for (const namespace of namespaces) {
6806
+ const key = this.getKey(locale, namespace);
6807
+ const resource = this.resources.get(key);
6808
+ if (resource) bundle.addResource(resource);
6809
+ else promises.push([bundle, key, this.fetchResource(key)]);
6810
+ }
6811
+ }
6812
+ void this.awaitResources(promises);
6813
+ return bundles;
6814
+ }
6815
+ async awaitResources(promises) {
6816
+ for (const [bundle, key, promise] of promises) {
6817
+ let resource = null;
6818
+ try {
6819
+ resource = await promise;
6820
+ } catch (error) {
6821
+ console.warn(`exception while fetching resource for "${key}"`);
6822
+ console.error(error);
6823
+ }
6824
+ if (resource === null) {
6825
+ console.warn(`couldn't load resource for "${key}"`);
6826
+ } else {
6827
+ bundle.addResource(resource);
6828
+ }
6829
+ }
6830
+ }
6831
+ async fetchResource(key) {
6832
+ const response = await this.fetch(key);
6833
+ if (response.ok) {
6834
+ const resource = new FluentResource(await response.text());
6835
+ this.resources.set(key, resource);
6836
+ return resource;
6837
+ } else {
6838
+ console.warn(`could not load i18n for ${key}`);
6839
+ return null;
6840
+ }
6841
+ }
6842
+ }
6786
6843
  const INJECTION_KEY_PREFIX = "GLOBAL_LOCALE_MANAGER";
6787
6844
  const globalLocaleManagers = /* @__PURE__ */ new Map();
6788
6845
  class LocaleManager extends BaseLocaleManager {
@@ -6915,68 +6972,16 @@ function useI18N(namespace = "default") {
6915
6972
  function parseInjectionName(namespace) {
6916
6973
  return `${INJECTION_KEY_PREFIX}.${namespace}`;
6917
6974
  }
6918
- const DEFAULT_FETCH = (key, init) => fetch(`/locales/${key}`, init);
6919
- class HTTPBundleSource {
6920
- constructor(params) {
6921
- __publicField(this, "fetch");
6922
- __publicField(this, "resources", /* @__PURE__ */ new Map());
6923
- this.fetch = params.fetch ?? DEFAULT_FETCH;
6924
- }
6925
- addSource(resource) {
6926
- throw new Error("Method not implemented.");
6927
- }
6928
- getKey(locale, namespace) {
6929
- return `${namespace}/${locale}`;
6930
- }
6931
- getBundles(locales, namespaces) {
6932
- const bundles = [];
6933
- const promises = [];
6934
- for (const locale of locales) {
6935
- const bundle = new FluentBundle2(locale);
6936
- bundles.push(bundle);
6937
- for (const namespace of namespaces) {
6938
- const key = this.getKey(locale, namespace);
6939
- const resource = this.resources.get(key);
6940
- if (resource) bundle.addResource(resource);
6941
- else promises.push([bundle, key, this.fetchResource(key)]);
6942
- }
6943
- }
6944
- void this.awaitResources(promises);
6945
- return bundles;
6946
- }
6947
- async awaitResources(promises) {
6948
- for (const [bundle, key, promise] of promises) {
6949
- let resource = null;
6950
- try {
6951
- resource = await promise;
6952
- } catch (error) {
6953
- console.warn(`exception while fetching resource for "${key}"`);
6954
- console.error(error);
6955
- }
6956
- if (resource === null) {
6957
- console.warn(`couldn't load resource for "${key}"`);
6958
- } else {
6959
- bundle.addResource(resource);
6960
- }
6961
- }
6962
- }
6963
- async fetchResource(key) {
6964
- const response = await this.fetch(key);
6965
- if (response.ok) {
6966
- const resource = new FluentResource(await response.text());
6967
- this.resources.set(key, resource);
6968
- return resource;
6969
- } else {
6970
- console.warn(`could not load i18n for ${key}`);
6971
- return null;
6972
- }
6973
- }
6974
- }
6975
6975
  export {
6976
+ BaseLocaleManager,
6976
6977
  HTTPBundleSource,
6977
6978
  INJECTION_KEY_PREFIX,
6978
6979
  LocaleManager,
6980
+ MemoryStorageWrapper,
6979
6981
  RawBundleSource,
6982
+ createStorageWrapper,
6983
+ findLocaleManager,
6984
+ globalLocaleManagers,
6980
6985
  useI18N
6981
6986
  };
6982
6987
  //# sourceMappingURL=i18n.js.map