@discord/intl 0.1.2 → 0.2.0-canary.641ab2f

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.
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
17
+ var __read = (this && this.__read) || function (o, n) {
18
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
19
+ if (!m) return o;
20
+ var i = m.call(o), r, ar = [], e;
21
+ try {
22
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
23
+ }
24
+ catch (error) { e = { error: error }; }
25
+ finally {
26
+ try {
27
+ if (r && !r.done && (m = i["return"])) m.call(i);
28
+ }
29
+ finally { if (e) throw e.error; }
30
+ }
31
+ return ar;
32
+ };
33
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
34
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
35
+ if (ar || !(i in from)) {
36
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
37
+ ar[i] = from[i];
38
+ }
39
+ }
40
+ return to.concat(ar || Array.prototype.slice.call(from));
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.reactFormatter = exports.DEFAULT_REACT_RICH_TEXT_ELEMENTS = void 0;
44
+ exports.formatReact = formatReact;
45
+ exports.makeReactFormatter = makeReactFormatter;
46
+ var React = require("react");
47
+ var format_1 = require("../format");
48
+ var h = React.createElement;
49
+ exports.DEFAULT_REACT_RICH_TEXT_ELEMENTS = {
50
+ $_: function () { return ''; },
51
+ $b: function (content) { return h('strong', undefined, content); },
52
+ $code: function (content) { return h('code', undefined, content); },
53
+ $i: function (content) { return h('em', undefined, content); },
54
+ // $link will always be [href, <empty>, ...content]
55
+ $link: function (_a) {
56
+ var _b = __read(_a), href = _b[0], content = _b.slice(1);
57
+ return h('a', { href: href }, content);
58
+ },
59
+ $p: function (content) { return h('p', undefined, content); },
60
+ };
61
+ /**
62
+ * Creates a new `FormatBuilder` class that constructs a React element tree
63
+ * from the message using the given `richTextElements` to apply formatting.
64
+ * This allows consumers to inject their own design system components and
65
+ * overrides for rendering elements like links, paragraphs, and code blocks.
66
+ * @param richTextElements
67
+ */
68
+ function createReactBuilder(richTextElements) {
69
+ return /** @class */ (function (_super) {
70
+ __extends(class_1, _super);
71
+ function class_1() {
72
+ var _this = _super.apply(this, __spreadArray([], __read(arguments), false)) || this;
73
+ _this.result = [];
74
+ return _this;
75
+ }
76
+ class_1.prototype.pushRichTextTag = function (tag, children) {
77
+ this.result.push(richTextElements[tag](children));
78
+ };
79
+ class_1.prototype.pushLiteralText = function (text) {
80
+ this.result.push(text);
81
+ };
82
+ class_1.prototype.pushObject = function (value) {
83
+ // @ts-expect-error this is technically invalid, but we'll just assume that if a format returns
84
+ // an object, it'll be acting as some form of ReactNode.
85
+ this.result.push(value);
86
+ };
87
+ class_1.prototype.finish = function () {
88
+ return this.result;
89
+ };
90
+ return class_1;
91
+ }(format_1.FormatBuilder));
92
+ }
93
+ function formatReact(message, values, Builder) {
94
+ if (typeof message === 'string') {
95
+ return React.createElement(React.Fragment, undefined, message);
96
+ }
97
+ var parts = this.bindFormatValues(Builder, message, values);
98
+ return React.createElement(React.Fragment, undefined, parts);
99
+ }
100
+ /**
101
+ * Create a new React formatter with the given rich text elements replacing the defaults. Use this
102
+ * function to inject custom components for things like links and paragraphs, which may be best
103
+ * suited to use components from a Design System or other library rather than native DOM elements.
104
+ */
105
+ function makeReactFormatter(richTextElements) {
106
+ return {
107
+ format: formatReact,
108
+ builder: createReactBuilder(richTextElements),
109
+ };
110
+ }
111
+ exports.reactFormatter = makeReactFormatter(exports.DEFAULT_REACT_RICH_TEXT_ELEMENTS);
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Format the given message with the provided values, removing any styling
3
+ * and non-textual content from the message, returning a plain string.
4
+ */
5
+ import { AnyIntlMessage, FormatterImplementation, FunctionTypes, RichTextTagNames } from '../types';
6
+ import { FormatBuilder } from '../format';
7
+ import { IntlManager } from '../intl-manager';
8
+ /**
9
+ * Types for formatting functions when calling `bindFormatValues`, ensuring the
10
+ * functions always yield plain strings.
11
+ */
12
+ export type StringFunctionTypes = FunctionTypes<string>;
13
+ export declare class StringBuilder extends FormatBuilder<string> {
14
+ result: string;
15
+ pushRichTextTag(tag: RichTextTagNames, children: string[]): void;
16
+ pushLiteralText(text: string): void;
17
+ pushObject(value: object): void;
18
+ finish(): string[];
19
+ }
20
+ export declare function formatToPlainString(this: IntlManager, message: AnyIntlMessage, values: object): string;
21
+ export declare const stringFormatter: FormatterImplementation<StringFunctionTypes, string>;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
17
+ var __read = (this && this.__read) || function (o, n) {
18
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
19
+ if (!m) return o;
20
+ var i = m.call(o), r, ar = [], e;
21
+ try {
22
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
23
+ }
24
+ catch (error) { e = { error: error }; }
25
+ finally {
26
+ try {
27
+ if (r && !r.done && (m = i["return"])) m.call(i);
28
+ }
29
+ finally { if (e) throw e.error; }
30
+ }
31
+ return ar;
32
+ };
33
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
34
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
35
+ if (ar || !(i in from)) {
36
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
37
+ ar[i] = from[i];
38
+ }
39
+ }
40
+ return to.concat(ar || Array.prototype.slice.call(from));
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.stringFormatter = exports.StringBuilder = void 0;
44
+ exports.formatToPlainString = formatToPlainString;
45
+ var format_1 = require("../format");
46
+ var StringBuilder = /** @class */ (function (_super) {
47
+ __extends(StringBuilder, _super);
48
+ function StringBuilder() {
49
+ var _this = _super.apply(this, __spreadArray([], __read(arguments), false)) || this;
50
+ _this.result = '';
51
+ return _this;
52
+ }
53
+ StringBuilder.prototype.pushRichTextTag = function (tag, children) {
54
+ // Plain string formatting ignores rich text tags and just takes the
55
+ // visible content from the children. This means the `target` element
56
+ // of a link is ignored, otherwise all the children are just joined
57
+ // together directly.
58
+ if (tag === '$link') {
59
+ this.result += children.slice(1).join('');
60
+ return;
61
+ }
62
+ this.result += children.join('');
63
+ };
64
+ StringBuilder.prototype.pushLiteralText = function (text) {
65
+ this.result += text;
66
+ };
67
+ StringBuilder.prototype.pushObject = function (value) {
68
+ // Objects are only included in the result if they specify a toString value directly.
69
+ // Otherwise, they would be rendered as `[object Object]`, which is never helpful.
70
+ if ('toString' in value) {
71
+ this.result += value.toString();
72
+ }
73
+ };
74
+ StringBuilder.prototype.finish = function () {
75
+ return [this.result];
76
+ };
77
+ return StringBuilder;
78
+ }(format_1.FormatBuilder));
79
+ exports.StringBuilder = StringBuilder;
80
+ function formatToPlainString(message, values) {
81
+ if (typeof message === 'string')
82
+ return message;
83
+ var result = this.bindFormatValues(StringBuilder, message, values);
84
+ // StringBuilder always creates a single element array with the string value.
85
+ return result[0];
86
+ }
87
+ exports.stringFormatter = {
88
+ format: formatToPlainString,
89
+ builder: StringBuilder,
90
+ };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { IntlManager } from './intl-manager';
2
- import { IntlManagerReact } from './react';
3
- export { IntlManager, createLoader, DEFAULT_LOCALE } from './intl-manager';
4
- export { IntlManagerReact } from './react';
1
+ import * as React from 'react';
2
+ import { RichTextNode } from './formatters';
3
+ export * from './formatters';
4
+ export { IntlManager, DEFAULT_LOCALE, type FormatFunction } from './intl-manager';
5
+ export { createLoader, waitForAllDefaultIntlMessagesLoaded } from './message-loader';
5
6
  export type * from './types.d.ts';
6
7
  /**
7
8
  * A type representing any message that has been formatted using one of the
@@ -18,7 +19,7 @@ export type * from './types.d.ts';
18
19
  * intl message, even if the actual value comes from elsewhere (like a
19
20
  * user-generated string).
20
21
  */
21
- export type ReactIntlMessage = string | ReturnType<IntlManagerReact<any>['format']>;
22
+ export type ReactIntlMessage = string | React.ReactElement;
22
23
  /**
23
24
  * The return value of `formatToParts` from `@discord/intl`, this type
24
25
  * represents any AST structure for a message rendered using this system.
@@ -29,4 +30,4 @@ export type ReactIntlMessage = string | ReturnType<IntlManagerReact<any>['format
29
30
  * from a call to `formatToParts`, meaning they are intended to be fully static
30
31
  * structures passed around for custom rendering functions to use.
31
32
  */
32
- export type IntlMessageAst = ReturnType<IntlManager<any, any>['formatToParts']>;
33
+ export type IntlMessageAst = RichTextNode;
package/dist/index.js CHANGED
@@ -1,9 +1,24 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
2
16
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.IntlManagerReact = exports.DEFAULT_LOCALE = exports.createLoader = exports.IntlManager = void 0;
17
+ exports.waitForAllDefaultIntlMessagesLoaded = exports.createLoader = exports.DEFAULT_LOCALE = exports.IntlManager = void 0;
18
+ __exportStar(require("./formatters"), exports);
4
19
  var intl_manager_1 = require("./intl-manager");
5
20
  Object.defineProperty(exports, "IntlManager", { enumerable: true, get: function () { return intl_manager_1.IntlManager; } });
6
- Object.defineProperty(exports, "createLoader", { enumerable: true, get: function () { return intl_manager_1.createLoader; } });
7
21
  Object.defineProperty(exports, "DEFAULT_LOCALE", { enumerable: true, get: function () { return intl_manager_1.DEFAULT_LOCALE; } });
8
- var react_1 = require("./react");
9
- Object.defineProperty(exports, "IntlManagerReact", { enumerable: true, get: function () { return react_1.IntlManagerReact; } });
22
+ var message_loader_1 = require("./message-loader");
23
+ Object.defineProperty(exports, "createLoader", { enumerable: true, get: function () { return message_loader_1.createLoader; } });
24
+ Object.defineProperty(exports, "waitForAllDefaultIntlMessagesLoaded", { enumerable: true, get: function () { return message_loader_1.waitForAllDefaultIntlMessagesLoaded; } });
@@ -1,34 +1,35 @@
1
1
  import { IntlShape } from '@formatjs/intl';
2
- import { LocaleId, LocaleImportMap, MessageLoader } from './message-loader';
3
- import type { FunctionTypeMap, IntlMessageGetter, RequiredFormatValues, RichTextElementMap, TypedIntlMessageGetter } from './types';
4
- /**
5
- * Types for formatting functions when calling `formatToParts`, ensuring the
6
- * functions yield value AST nodes.
7
- */
8
- type AstFunctionTypes = {
9
- link: undefined | object | ((children: object) => Array<string | any>);
10
- hook: undefined | object | ((children: object) => Array<string | any>);
11
- handler: undefined | object | ((children: object) => Array<string | any>);
12
- };
2
+ import type { FormatterImplementation, IntlMessageGetter, RequiredFormatValues, TypedIntlMessageGetter } from './types';
3
+ import { InternalIntlMessage } from './message';
4
+ import { FormatBuilderConstructor } from './format';
13
5
  /**
14
6
  * Fallback locale used for all internationalization when an operation in the
15
7
  * requested locale is not possible.
16
8
  */
17
9
  export declare const DEFAULT_LOCALE: string;
18
- export declare class IntlManager<DefaultElements extends RichTextElementMap, FunctionTypes extends FunctionTypeMap> {
10
+ type FormatterReturnType<F extends FormatterImplementation<any, any>> = F extends FormatterImplementation<any, infer Return> ? Return : never;
11
+ type FormatterFunctionTypes<F extends FormatterImplementation<any, any>> = F extends FormatterImplementation<infer Functions, any> ? Functions : never;
12
+ export type FormatFunction<F extends FormatterImplementation<any, any>> = <T extends IntlMessageGetter>(this: IntlManager, message: T, values: RequiredFormatValues<T, FormatterFunctionTypes<F>>) => FormatterReturnType<F>;
13
+ type ThisWithFormatters<This, T extends Record<string, FormatterImplementation<any, any>>> = This & {
14
+ [K in keyof T]: FormatFunction<T[K]>;
15
+ };
16
+ export declare class IntlManager {
19
17
  defaultLocale: string;
20
18
  currentLocale: string;
21
19
  intl: IntlShape;
20
+ _localeSubscriptions: Set<(locale: string) => void>;
21
+ constructor(defaultLocale?: string);
22
22
  /**
23
- * When formatting tag elements like `<b>value</b>`, these functions will
24
- * automatically be used by all messages, unless they are explicitly removed
25
- * for a specific call, either by overriding the value or by calling a
26
- * dedicated method like `formatToPlainString` which will remove all
27
- * rich elements from the string and return only the plain text result.
23
+ * Add a set of formatter implementations to this manager, making each available as a direct
24
+ * property
28
25
  */
29
- defaultRichTextElements: DefaultElements;
30
- _localeSubscriptions: Set<(locale: string) => void>;
31
- constructor(defaultLocale: string, defaultRichTextElements: DefaultElements);
26
+ withFormatters<const T extends Record<string, FormatterImplementation<any, any>>>(formatters: T): ThisWithFormatters<this, T>;
27
+ /**
28
+ * Return a new function bound to this manager that uses the given `FormatterImplementation` to
29
+ * format a message after it has been resolved for the current locale and potentially processed in
30
+ * other ways by the manager.
31
+ */
32
+ makeFormatFunction<F extends FormatterImplementation<any, any>>({ format, builder, }: F): FormatFunction<FormatterReturnType<F>>;
32
33
  /**
33
34
  * Set the locale for this package to use. This is a global change, and all
34
35
  * methods on this object will use this locale for formatting.
@@ -40,49 +41,10 @@ export declare class IntlManager<DefaultElements extends RichTextElementMap, Fun
40
41
  */
41
42
  onLocaleChange: (callback: (locale: string) => void) => () => boolean;
42
43
  /**
43
- * Format the given message in the current locale with the provided values.
44
- * The returned values is _always_ an Array of parts, even if the message is
45
- * a simple string value.
46
- *
47
- * This function is the basis of how messages are normally formatted, and can
48
- * be used anywhere. However, it is not reactive and only functions on the
49
- * data that is currently loaded and known. For a reactive function that
50
- * automatically updates when the locale changes or when new data is loaded,
51
- * use `format`, which will wrap the formatting in a React component that
52
- * subscribes to the current locale and state of loaded messages.
44
+ * For static messages with no rich text and no dynamic placeholders, use this method to
45
+ * immediately return the plain string value of the message in the current locale.
53
46
  */
54
- formatToParts<T extends TypedIntlMessageGetter<undefined>>(message: T): Array<string | any>;
55
- formatToParts<T extends IntlMessageGetter>(message: T, values: RequiredFormatValues<T, DefaultElements, AstFunctionTypes>): Array<string | any>;
56
- /**
57
- * For messages with no formatting values (i.e., plain strings, they can skip
58
- * a majority of the processing work and just resolve the message itself for
59
- * the current locale, then return the plain string directly.
60
- *
61
- * This is separate from `formatToPlainString`, which still allows for
62
- * formatting variables and other elements but reduces the output to only
63
- * include textual elements in a plain string.
64
- */
65
- string(message: TypedIntlMessageGetter<undefined>): string;
66
- /**
67
- * Format the given message with the provided values, removing any styling
68
- * and non-textual content from the message, returning a plain string.
69
- */
70
- formatToPlainString<T extends TypedIntlMessageGetter<undefined>>(message: T): string;
71
- formatToPlainString<T extends IntlMessageGetter>(message: T, values: RequiredFormatValues<T, DefaultElements, FunctionTypes>): string;
72
- /**
73
- * Similar to `formatToPlainString`, format the given message with the provided
74
- * values, but convert all rich text formatting back to Markdown syntax rather
75
- * than rendering the actual rich content. The result is a plain string that
76
- * can be sent through a separate Markdown renderer to get an equivalent
77
- * result to formatting this message directly.
78
- */
79
- formatToMarkdownString<T extends TypedIntlMessageGetter<undefined>>(message: T): string;
80
- formatToMarkdownString<T extends IntlMessageGetter>(message: T, values: RequiredFormatValues<T, DefaultElements, FunctionTypes>): string;
47
+ string<T extends TypedIntlMessageGetter<undefined>>(message: T): string;
48
+ bindFormatValues<T>(Builder: FormatBuilderConstructor<T>, message: InternalIntlMessage, values: Record<string, any>): T[];
81
49
  }
82
- /**
83
- * Create a new MessageLoader, which handles lazily loading messages for
84
- * different locales and sanity checks as needed to provide accessors for each
85
- * message defined in `messageKeys`.
86
- */
87
- export declare function createLoader(messageKeys: string[], localeImportMap: LocaleImportMap, defaultLocale: LocaleId): MessageLoader;
88
50
  export {};
@@ -1,15 +1,4 @@
1
1
  "use strict";
2
- var __assign = (this && this.__assign) || function () {
3
- __assign = Object.assign || function(t) {
4
- for (var s, i = 1, n = arguments.length; i < n; i++) {
5
- s = arguments[i];
6
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
- t[p] = s[p];
8
- }
9
- return t;
10
- };
11
- return __assign.apply(this, arguments);
12
- };
13
2
  var __values = (this && this.__values) || function(o) {
14
3
  var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
15
4
  if (m) return m.call(o);
@@ -21,19 +10,34 @@ var __values = (this && this.__values) || function(o) {
21
10
  };
22
11
  throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
23
12
  };
13
+ var __read = (this && this.__read) || function (o, n) {
14
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
15
+ if (!m) return o;
16
+ var i = m.call(o), r, ar = [], e;
17
+ try {
18
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
19
+ }
20
+ catch (error) { e = { error: error }; }
21
+ finally {
22
+ try {
23
+ if (r && !r.done && (m = i["return"])) m.call(i);
24
+ }
25
+ finally { if (e) throw e.error; }
26
+ }
27
+ return ar;
28
+ };
24
29
  Object.defineProperty(exports, "__esModule", { value: true });
25
30
  exports.IntlManager = exports.DEFAULT_LOCALE = void 0;
26
- exports.createLoader = createLoader;
27
31
  var intl_1 = require("@formatjs/intl");
28
32
  var intl_messageformat_1 = require("intl-messageformat");
29
- var message_loader_1 = require("./message-loader");
33
+ var format_1 = require("./format");
30
34
  /**
31
35
  * Fallback locale used for all internationalization when an operation in the
32
36
  * requested locale is not possible.
33
37
  */
34
38
  exports.DEFAULT_LOCALE = 'en-US';
35
39
  var IntlManager = /** @class */ (function () {
36
- function IntlManager(defaultLocale, defaultRichTextElements) {
40
+ function IntlManager(defaultLocale) {
37
41
  if (defaultLocale === void 0) { defaultLocale = exports.DEFAULT_LOCALE; }
38
42
  var _this = this;
39
43
  /**
@@ -50,24 +54,18 @@ var IntlManager = /** @class */ (function () {
50
54
  defaultLocale: defaultLocale,
51
55
  locale: defaultLocale,
52
56
  });
53
- this.defaultRichTextElements = defaultRichTextElements;
54
57
  this._localeSubscriptions = new Set();
55
58
  }
56
59
  /**
57
- * Set the locale for this package to use. This is a global change, and all
58
- * methods on this object will use this locale for formatting.
60
+ * Add a set of formatter implementations to this manager, making each available as a direct
61
+ * property
59
62
  */
60
- IntlManager.prototype.setLocale = function (locale) {
61
- this.currentLocale = locale;
62
- this.intl = (0, intl_1.createIntl)({ defaultLocale: this.defaultLocale, locale: locale });
63
- this.emitLocaleChange(locale);
64
- };
65
- IntlManager.prototype.emitLocaleChange = function (locale) {
63
+ IntlManager.prototype.withFormatters = function (formatters) {
66
64
  var e_1, _a;
67
65
  try {
68
- for (var _b = __values(this._localeSubscriptions), _c = _b.next(); !_c.done; _c = _b.next()) {
69
- var callback = _c.value;
70
- callback(locale);
66
+ for (var _b = __values(Object.entries(formatters)), _c = _b.next(); !_c.done; _c = _b.next()) {
67
+ var _d = __read(_c.value, 2), name = _d[0], formatter = _d[1];
68
+ this[name] = this.makeFormatFunction(formatter);
71
69
  }
72
70
  }
73
71
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -77,86 +75,60 @@ var IntlManager = /** @class */ (function () {
77
75
  }
78
76
  finally { if (e_1) throw e_1.error; }
79
77
  }
78
+ return this;
80
79
  };
81
- IntlManager.prototype.formatToParts = function (message, values) {
80
+ /**
81
+ * Return a new function bound to this manager that uses the given `FormatterImplementation` to
82
+ * format a message after it has been resolved for the current locale and potentially processed in
83
+ * other ways by the manager.
84
+ */
85
+ IntlManager.prototype.makeFormatFunction = function (_a) {
86
+ var _this = this;
87
+ var format = _a.format, builder = _a.builder;
88
+ var formatter = format.bind(this);
89
+ return function (message, values) {
90
+ return formatter(message(_this.currentLocale), values, builder);
91
+ };
92
+ };
93
+ /**
94
+ * Set the locale for this package to use. This is a global change, and all
95
+ * methods on this object will use this locale for formatting.
96
+ */
97
+ IntlManager.prototype.setLocale = function (locale) {
98
+ this.currentLocale = locale;
99
+ this.intl = (0, intl_1.createIntl)({ defaultLocale: this.defaultLocale, locale: locale });
100
+ this.emitLocaleChange(locale);
101
+ };
102
+ IntlManager.prototype.emitLocaleChange = function (locale) {
82
103
  var e_2, _a;
83
- if (typeof message === 'string')
84
- return [message];
85
- var resolvedMessage = typeof message === 'function' ? message(this.currentLocale) : message;
86
- if (typeof resolvedMessage === 'string')
87
- return [resolvedMessage];
88
- var resolvedValues = values != null
89
- ? __assign(__assign({}, this.defaultRichTextElements), values) : this.defaultRichTextElements;
90
- var parts = resolvedMessage.formatToParts(this.intl.formatters, this.intl.formats, resolvedValues);
91
- var result = [];
92
- var inLiteral = false;
93
104
  try {
94
- for (var parts_1 = __values(parts), parts_1_1 = parts_1.next(); !parts_1_1.done; parts_1_1 = parts_1.next()) {
95
- var part = parts_1_1.value;
96
- // This condition merges consecutive literal elements (static strings)
97
- // into single parts to reduce the number of nodes in the result. This
98
- // condition will never be true on the first loop, ensuring that the
99
- // array must at least have one entry before it attempts to concatenate
100
- // onto that value again.
101
- if (inLiteral && (inLiteral = part.type === intl_messageformat_1.PART_TYPE.literal)) {
102
- result[result.length - 1] += part.value;
103
- continue;
104
- }
105
- inLiteral = part.type === intl_messageformat_1.PART_TYPE.literal;
106
- result.push(part.value);
105
+ for (var _b = __values(this._localeSubscriptions), _c = _b.next(); !_c.done; _c = _b.next()) {
106
+ var callback = _c.value;
107
+ callback(locale);
107
108
  }
108
109
  }
109
110
  catch (e_2_1) { e_2 = { error: e_2_1 }; }
110
111
  finally {
111
112
  try {
112
- if (parts_1_1 && !parts_1_1.done && (_a = parts_1.return)) _a.call(parts_1);
113
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
113
114
  }
114
115
  finally { if (e_2) throw e_2.error; }
115
116
  }
116
- return result;
117
117
  };
118
118
  /**
119
- * For messages with no formatting values (i.e., plain strings, they can skip
120
- * a majority of the processing work and just resolve the message itself for
121
- * the current locale, then return the plain string directly.
122
- *
123
- * This is separate from `formatToPlainString`, which still allows for
124
- * formatting variables and other elements but reduces the output to only
125
- * include textual elements in a plain string.
119
+ * For static messages with no rich text and no dynamic placeholders, use this method to
120
+ * immediately return the plain string value of the message in the current locale.
126
121
  */
127
122
  IntlManager.prototype.string = function (message) {
128
- // TODO(faulty): Optimize this so that plain strings are hotpathed even faster.
129
- return this.formatToPlainString(message);
130
- };
131
- IntlManager.prototype.formatToPlainString = function (message, values) {
132
- if (typeof message === 'string')
133
- return message;
134
- var resolvedMessage = message(this.currentLocale);
135
- if (typeof resolvedMessage === 'string')
136
- return resolvedMessage;
137
- // No need to pass in `defaultRichTextElements`, since the stylistic tags
138
- // will be removed from the string anyway.
139
- return resolvedMessage.formatToPlainString(this.intl.formatters, this.intl.formats, values);
123
+ // @ts-expect-error Figure out how to make this typing exact. This
124
+ // currently relies on the generic typing being sound enough to know that
125
+ // the message can only contain a single static text node and no
126
+ // placeholders or rich text.
127
+ return message(this.currentLocale).ast[0].value;
140
128
  };
141
- IntlManager.prototype.formatToMarkdownString = function (message, values) {
142
- // TODO(faulty): Implement the markdown syntax conversion here.
143
- if (typeof message === 'string')
144
- return message;
145
- var resolvedMessage = message(this.currentLocale);
146
- if (typeof resolvedMessage === 'string')
147
- return resolvedMessage;
148
- // No need to pass in `defaultRichTextElements`, since the stylistic tags
149
- // will be removed from the string anyway.
150
- return resolvedMessage.formatToPlainString(this.intl.formatters, this.intl.formats, values);
129
+ IntlManager.prototype.bindFormatValues = function (Builder, message, values) {
130
+ return (0, format_1.bindFormatValues)(Builder, message.ast, [this.currentLocale, this.defaultLocale], this.intl.formatters, this.intl.formats, values);
151
131
  };
152
132
  return IntlManager;
153
133
  }());
154
134
  exports.IntlManager = IntlManager;
155
- /**
156
- * Create a new MessageLoader, which handles lazily loading messages for
157
- * different locales and sanity checks as needed to provide accessors for each
158
- * message defined in `messageKeys`.
159
- */
160
- function createLoader(messageKeys, localeImportMap, defaultLocale) {
161
- return new message_loader_1.MessageLoader(messageKeys, localeImportMap, defaultLocale);
162
- }
@@ -32,6 +32,13 @@ export interface FormatJsTime {
32
32
  value: string;
33
33
  style?: string;
34
34
  }
35
+ export interface FormatJsSelect {
36
+ type: FormatJsNodeType.Select;
37
+ value: string;
38
+ options: Record<string, {
39
+ value: FormatJsNode[];
40
+ }>;
41
+ }
35
42
  export type FormatJsPluralType = 'cardinal' | 'ordinal';
36
43
  export interface FormatJsPlural {
37
44
  type: FormatJsNodeType.Plural;
@@ -50,7 +57,7 @@ export interface FormatJsTag {
50
57
  value: string;
51
58
  children: FormatJsNode[];
52
59
  }
53
- export type FormatJsNode = FormatJsLiteral | FormatJsArgument | FormatJsNumber | FormatJsDate | FormatJsTime | FormatJsPlural | FormatJsPound | FormatJsTag;
60
+ export type FormatJsNode = FormatJsLiteral | FormatJsArgument | FormatJsNumber | FormatJsDate | FormatJsTime | FormatJsSelect | FormatJsPlural | FormatJsPound | FormatJsTag;
54
61
  export declare const FORMAT_JS_POUND: FormatJsPound;
55
62
  /**
56
63
  * Hydrate the given keyless JSON into a FormatJS-compatible AST structure.