@discord/intl 0.10.2 → 0.10.3-canary.1346695

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.
@@ -14,13 +14,30 @@ export type FormatFunction<F extends FormatterImplementation<any, any>> = <T ext
14
14
  type ThisWithFormatters<This, T extends Record<string, FormatterImplementation<any, any>>> = This & {
15
15
  [K in keyof T]: FormatFunction<T[K]>;
16
16
  };
17
+ export interface IntlManagerOptions {
18
+ /**
19
+ * The locale to initially have this manager use. Useful to set when information about the user's
20
+ * likely locale is available sooner than when that information is definitely known (at which
21
+ * point `setLocale` should be called instead).
22
+ *
23
+ * @default DEFAULT_LOCALE
24
+ */
25
+ initialLocale?: string;
26
+ /**
27
+ * The locale in which most messages are _defined_, used as an indication of where fallbacks
28
+ * should be loaded from when they can't be found in the requested `currentLocale`.
29
+ *
30
+ * @default DEFAULT_LOCALE
31
+ */
32
+ defaultLocale?: string;
33
+ }
17
34
  export declare class IntlManager {
18
35
  defaultLocale: string;
19
36
  currentLocale: string;
20
37
  intl: IntlShape;
21
38
  formatConfig: FormatConfig;
22
39
  _localeSubscriptions: Set<(locale: string) => void>;
23
- constructor(defaultLocale?: string);
40
+ constructor({ initialLocale, defaultLocale, }: IntlManagerOptions);
24
41
  /**
25
42
  * Add a set of formatter implementations to this manager, making each available as a direct
26
43
  * property
@@ -10,7 +10,7 @@ const format_config_1 = require("./format-config");
10
10
  */
11
11
  exports.DEFAULT_LOCALE = 'en-US';
12
12
  class IntlManager {
13
- constructor(defaultLocale = exports.DEFAULT_LOCALE) {
13
+ constructor({ initialLocale = exports.DEFAULT_LOCALE, defaultLocale = exports.DEFAULT_LOCALE, }) {
14
14
  /**
15
15
  * Subscribe to changes in the current locale for this manager.
16
16
  */
@@ -18,8 +18,8 @@ class IntlManager {
18
18
  this._localeSubscriptions.add(callback);
19
19
  return () => this._localeSubscriptions.delete(callback);
20
20
  };
21
+ this.currentLocale = initialLocale;
21
22
  this.defaultLocale = defaultLocale;
22
- this.currentLocale = defaultLocale;
23
23
  this.formatConfig = format_config_1.DEFAULT_FORMAT_CONFIG;
24
24
  this.intl = (0, intl_1.createIntl)({
25
25
  formats: format_config_1.DEFAULT_FORMAT_CONFIG,
@@ -117,6 +117,7 @@ export declare class MessageLoader {
117
117
  * Subscribe to events about when a locale has loaded.
118
118
  */
119
119
  onChange(callback: () => void): () => void;
120
+ isLocaleLoading(locale: LocaleId): boolean;
120
121
  isLocaleLoaded(locale: LocaleId, requireCurrent?: boolean): boolean;
121
122
  waitForLocaleLoaded(locale: LocaleId, requireCurrent?: boolean): Promise<void>;
122
123
  /**
@@ -24,7 +24,8 @@ class MessageLoader {
24
24
  this._localeLoadingPromises = {};
25
25
  this._parseCache = {};
26
26
  this._subscribers = new Set();
27
- this._loadLocale(this.defaultLocale);
27
+ // TODO: Bring this back as an option to pre-load the locale.
28
+ // this._loadLocale(this.defaultLocale);
28
29
  this.fallbackMessage = new message_1.InternalIntlMessage([], this.defaultLocale);
29
30
  // In cases where hot module replacement is available, set up cache clearing whenever the
30
31
  // targets change so that values are always replaced.
@@ -51,10 +52,18 @@ class MessageLoader {
51
52
  this._localeFileMap = localeFileMap;
52
53
  }
53
54
  get(key, locale) {
54
- var _a;
55
- const value = (_a = this.getMessageValue(key, locale)) !== null && _a !== void 0 ? _a : this.getMessageValue(key, this.defaultLocale);
56
- if (value != null)
57
- return value;
55
+ const expectedValue = this.getMessageValue(key, locale);
56
+ if (expectedValue != null)
57
+ return expectedValue;
58
+ // If the expected locale is still in progress with loading and the default locale _has not_
59
+ // started loading already, then return the fallback message instead of starting a load of the
60
+ // default locale when it may not be necessary.
61
+ if (this.isLocaleLoading(locale) && !this.isLocaleLoaded(this.defaultLocale)) {
62
+ return this.fallbackMessage;
63
+ }
64
+ const fallbackValue = this.getMessageValue(key, this.defaultLocale);
65
+ if (fallbackValue != null)
66
+ return fallbackValue;
58
67
  // If the message couldn't be found in either the requested nor the default locale, then
59
68
  // nothing can be done.
60
69
  const errorKey = this._debugKeyMap != null ? `"${this._debugKeyMap[key]}" (${key})` : undefined;
@@ -122,9 +131,13 @@ class MessageLoader {
122
131
  }
123
132
  _loadLocale(locale) {
124
133
  return __awaiter(this, void 0, void 0, function* () {
125
- var _a;
134
+ var _a, _b;
135
+ // If the locale is already set in `messages`, then it doesn't need to be loaded again.
136
+ if (this.messages[locale] != null)
137
+ return;
126
138
  // Don't re-load a locale that's already in progress.
127
139
  if (((_a = this._localeLoadingPromises[locale]) === null || _a === void 0 ? void 0 : _a.current) != null) {
140
+ yield ((_b = this._localeLoadingPromises[locale]) === null || _b === void 0 ? void 0 : _b.current);
128
141
  return;
129
142
  }
130
143
  // Safety check in case the locale map doesn't include a require for the
@@ -140,9 +153,6 @@ class MessageLoader {
140
153
  return;
141
154
  }
142
155
  }
143
- // If the locale is already set in `messages`, then it doesn't need to be loaded again.
144
- if (this.messages[locale] != null)
145
- return;
146
156
  const current = this.localeImportMap[locale]();
147
157
  this._localeLoadingPromises[locale] = { initialized: false, current };
148
158
  this.messages[locale] = (yield current).default;
@@ -166,6 +176,10 @@ class MessageLoader {
166
176
  this._subscribers.add(callback);
167
177
  return () => this._subscribers.delete(callback);
168
178
  }
179
+ isLocaleLoading(locale) {
180
+ var _a;
181
+ return ((_a = this._localeLoadingPromises[locale]) === null || _a === void 0 ? void 0 : _a.current) != null;
182
+ }
169
183
  isLocaleLoaded(locale, requireCurrent = false) {
170
184
  const ref = this._localeLoadingPromises[locale];
171
185
  // Ensure the locale at least exists and is initialized.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@discord/intl",
3
- "version": "0.10.2",
3
+ "version": "0.10.3-canary.1346695",
4
4
  "license": "MIT",
5
5
  "description": "Client runtime for managing messages and translations in a React project.",
6
6
  "main": "./dist/index.js",
@@ -14,12 +14,16 @@
14
14
  "dist",
15
15
  "src"
16
16
  ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/discord/discord-intl"
20
+ },
17
21
  "dependencies": {
18
22
  "@formatjs/icu-skeleton-parser": "1.8.2",
19
23
  "@formatjs/intl": "^2.10.1",
20
24
  "@intrnl/xxhash64": "^0.1.2",
21
25
  "intl-messageformat": "^10.5.11",
22
- "@discord/intl-ast": "0.10.2"
26
+ "@discord/intl-ast": "0.10.3"
23
27
  },
24
28
  "devDependencies": {
25
29
  "@swc/cli": "^0.3.12",
@@ -27,17 +31,7 @@
27
31
  "typescript": "*"
28
32
  },
29
33
  "peerDependencies": {
30
- "@rspack/core": "0.x || 1.x",
31
- "react": "> 16",
32
- "webpack": "^5.0.0"
33
- },
34
- "peerDependenciesMeta": {
35
- "@rspack/core": {
36
- "optional": true
37
- },
38
- "webpack": {
39
- "optional": true
40
- }
34
+ "react": "> 16"
41
35
  },
42
36
  "scripts": {
43
37
  "build": "tsc",
@@ -37,6 +37,24 @@ type ThisWithFormatters<
37
37
  [K in keyof T]: FormatFunction<T[K]>;
38
38
  };
39
39
 
40
+ export interface IntlManagerOptions {
41
+ /**
42
+ * The locale to initially have this manager use. Useful to set when information about the user's
43
+ * likely locale is available sooner than when that information is definitely known (at which
44
+ * point `setLocale` should be called instead).
45
+ *
46
+ * @default DEFAULT_LOCALE
47
+ */
48
+ initialLocale?: string;
49
+ /**
50
+ * The locale in which most messages are _defined_, used as an indication of where fallbacks
51
+ * should be loaded from when they can't be found in the requested `currentLocale`.
52
+ *
53
+ * @default DEFAULT_LOCALE
54
+ */
55
+ defaultLocale?: string;
56
+ }
57
+
40
58
  export class IntlManager {
41
59
  defaultLocale: string;
42
60
  currentLocale: string;
@@ -45,9 +63,12 @@ export class IntlManager {
45
63
 
46
64
  _localeSubscriptions: Set<(locale: string) => void>;
47
65
 
48
- constructor(defaultLocale: string = DEFAULT_LOCALE) {
66
+ constructor({
67
+ initialLocale = DEFAULT_LOCALE,
68
+ defaultLocale = DEFAULT_LOCALE,
69
+ }: IntlManagerOptions) {
70
+ this.currentLocale = initialLocale;
49
71
  this.defaultLocale = defaultLocale;
50
- this.currentLocale = defaultLocale;
51
72
  this.formatConfig = DEFAULT_FORMAT_CONFIG;
52
73
  this.intl = createIntl({
53
74
  formats: DEFAULT_FORMAT_CONFIG,
@@ -96,7 +96,8 @@ export class MessageLoader {
96
96
  this._parseCache = {};
97
97
  this._subscribers = new Set();
98
98
 
99
- this._loadLocale(this.defaultLocale);
99
+ // TODO: Bring this back as an option to pre-load the locale.
100
+ // this._loadLocale(this.defaultLocale);
100
101
  this.fallbackMessage = new InternalIntlMessage([], this.defaultLocale);
101
102
 
102
103
  // In cases where hot module replacement is available, set up cache clearing whenever the
@@ -126,9 +127,17 @@ export class MessageLoader {
126
127
  }
127
128
 
128
129
  get(key: string, locale: LocaleId): InternalIntlMessage {
129
- const value =
130
- this.getMessageValue(key, locale) ?? this.getMessageValue(key, this.defaultLocale);
131
- if (value != null) return value;
130
+ const expectedValue = this.getMessageValue(key, locale);
131
+ if (expectedValue != null) return expectedValue;
132
+ // If the expected locale is still in progress with loading and the default locale _has not_
133
+ // started loading already, then return the fallback message instead of starting a load of the
134
+ // default locale when it may not be necessary.
135
+ if (this.isLocaleLoading(locale) && !this.isLocaleLoaded(this.defaultLocale)) {
136
+ return this.fallbackMessage;
137
+ }
138
+
139
+ const fallbackValue = this.getMessageValue(key, this.defaultLocale);
140
+ if (fallbackValue != null) return fallbackValue;
132
141
 
133
142
  // If the message couldn't be found in either the requested nor the default locale, then
134
143
  // nothing can be done.
@@ -204,8 +213,12 @@ export class MessageLoader {
204
213
  }
205
214
 
206
215
  async _loadLocale(locale: LocaleId) {
216
+ // If the locale is already set in `messages`, then it doesn't need to be loaded again.
217
+ if (this.messages[locale] != null) return;
218
+
207
219
  // Don't re-load a locale that's already in progress.
208
220
  if (this._localeLoadingPromises[locale]?.current != null) {
221
+ await this._localeLoadingPromises[locale]?.current;
209
222
  return;
210
223
  }
211
224
 
@@ -224,9 +237,6 @@ export class MessageLoader {
224
237
  }
225
238
  }
226
239
 
227
- // If the locale is already set in `messages`, then it doesn't need to be loaded again.
228
- if (this.messages[locale] != null) return;
229
-
230
240
  const current = this.localeImportMap[locale]();
231
241
  this._localeLoadingPromises[locale] = { initialized: false, current };
232
242
  this.messages[locale] = (await current).default;
@@ -253,6 +263,10 @@ export class MessageLoader {
253
263
  return () => this._subscribers.delete(callback);
254
264
  }
255
265
 
266
+ isLocaleLoading(locale: LocaleId): boolean {
267
+ return this._localeLoadingPromises[locale]?.current != null;
268
+ }
269
+
256
270
  isLocaleLoaded(locale: LocaleId, requireCurrent: boolean = false): boolean {
257
271
  const ref = this._localeLoadingPromises[locale];
258
272
  // Ensure the locale at least exists and is initialized.