@discord/intl 0.18.0-canary.fa54f84 → 0.18.0-rc.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.
@@ -73,7 +73,7 @@ export declare class MessageLoader {
73
73
  * @private
74
74
  */
75
75
  _localeFileMap?: Record<string, string>;
76
- constructor(localeImportMap: LocaleImportMap, defaultLocale: LocaleId);
76
+ constructor(messageKeys: string[], localeImportMap: LocaleImportMap, defaultLocale: LocaleId);
77
77
  /**
78
78
  * Provide additional debug information to use during development, providing additional context
79
79
  * for console error messages.
@@ -93,6 +93,20 @@ export declare class MessageLoader {
93
93
  * returning.
94
94
  */
95
95
  getMessageValue(key: string, locale: LocaleId): InternalIntlMessage | undefined;
96
+ /**
97
+ * Returns a record mapping the keys this object manages to bound functions
98
+ * for `get` with the that key as the first argument, allowing consumers to
99
+ * just call the function with a locale to retrieve the translated message
100
+ * for that key.
101
+ *
102
+ * This method is provided as a way to generate binds _at runtime_, but for
103
+ * very-large messages files (e.g., thousands of messages), this can be a
104
+ * non-negligible cost. Where feasible, consider generating these binds
105
+ * at build/bundle time, especially in cases where they can be substantially
106
+ * minified (i.e., Hermes bytecode). This is provided automatically as an
107
+ * option when using one of `@discord/intl`'s transformers.
108
+ */
109
+ getBinds(): Record<string, IntlMessageGetter>;
96
110
  _loadLocale(locale: LocaleId): Promise<void>;
97
111
  /**
98
112
  * Inform subscribers that the loader state has changed and they should
@@ -131,12 +145,9 @@ export declare function loadAllMessagesInLocale(locale: LocaleId): Promise<void>
131
145
  */
132
146
  export declare function waitForAllDefaultIntlMessagesLoaded(): Promise<void>;
133
147
  /**
134
- * Create a new MessageLoader, which handles lazily loading messages for different locales and
135
- * sanity checks as needed to provide accessors for each message contained by the import map.
136
- *
137
- * Notably, this does _not_ verify whether the locale objects managed by this loader actually
138
- * contain a given key. It is the responsibility of the caller to verify this (easily enforced with
139
- * typescript, eslint rules, and others).
148
+ * Create a new MessageLoader, which handles lazily loading messages for
149
+ * different locales and sanity checks as needed to provide accessors for each
150
+ * message defined in `messageKeys`.
140
151
  */
141
- export declare function createLoader(localeImportMap: LocaleImportMap, defaultLocale: LocaleId): MessageLoader;
152
+ export declare function createLoader(messageKeys: string[], localeImportMap: LocaleImportMap, defaultLocale: LocaleId): MessageLoader;
142
153
  export {};
@@ -15,7 +15,8 @@ exports.waitForAllDefaultIntlMessagesLoaded = waitForAllDefaultIntlMessagesLoade
15
15
  exports.createLoader = createLoader;
16
16
  const message_1 = require("./message");
17
17
  class MessageLoader {
18
- constructor(localeImportMap, defaultLocale) {
18
+ constructor(messageKeys, localeImportMap, defaultLocale) {
19
+ this.messageKeys = messageKeys;
19
20
  this.messages = {};
20
21
  this.localeImportMap = localeImportMap;
21
22
  this.supportedLocales = Object.keys(localeImportMap);
@@ -98,16 +99,9 @@ class MessageLoader {
98
99
  }
99
100
  return undefined;
100
101
  }
101
- // Then try to return the loaded message. Previously, this used a `key in ...` check to quickly
102
- // verify whether the locale object contains the requested message, but in the case where the
103
- // target is a Proxy or uses some other internalized method for providing gettable values, `in`
104
- // queries aren't guaranteed to work. Instead, since this is realistically amortized to just be
105
- // a property access on every call, we can just the returned value as the determining factor. If
106
- // the locale object returns `undefined`, then it "does not contain" the message, whether it's
107
- // still loading or otherwise. Future calls will then be able to pick up any changed value,
108
- // since it won't be cached in the `_parseCache`.
109
- const content = this.messages[locale][key];
110
- if (content != null) {
102
+ // Then try to return the loaded message.
103
+ if (key in this.messages[locale]) {
104
+ const content = this.messages[locale][key];
111
105
  const message = new message_1.InternalIntlMessage(content, locale);
112
106
  ((_b = (_c = this._parseCache)[locale]) !== null && _b !== void 0 ? _b : (_c[locale] = {}))[key] = message;
113
107
  return message;
@@ -115,6 +109,26 @@ class MessageLoader {
115
109
  // Otherwise just assume it doesn't exist.
116
110
  return undefined;
117
111
  }
112
+ /**
113
+ * Returns a record mapping the keys this object manages to bound functions
114
+ * for `get` with the that key as the first argument, allowing consumers to
115
+ * just call the function with a locale to retrieve the translated message
116
+ * for that key.
117
+ *
118
+ * This method is provided as a way to generate binds _at runtime_, but for
119
+ * very-large messages files (e.g., thousands of messages), this can be a
120
+ * non-negligible cost. Where feasible, consider generating these binds
121
+ * at build/bundle time, especially in cases where they can be substantially
122
+ * minified (i.e., Hermes bytecode). This is provided automatically as an
123
+ * option when using one of `@discord/intl`'s transformers.
124
+ */
125
+ getBinds() {
126
+ const result = {};
127
+ for (const key of this.messageKeys) {
128
+ result[key] = this.get.bind(this, key);
129
+ }
130
+ return result;
131
+ }
118
132
  _loadLocale(locale) {
119
133
  return __awaiter(this, void 0, void 0, function* () {
120
134
  var _a, _b, _c, _d;
@@ -234,15 +248,12 @@ function waitForAllDefaultIntlMessagesLoaded() {
234
248
  });
235
249
  }
236
250
  /**
237
- * Create a new MessageLoader, which handles lazily loading messages for different locales and
238
- * sanity checks as needed to provide accessors for each message contained by the import map.
239
- *
240
- * Notably, this does _not_ verify whether the locale objects managed by this loader actually
241
- * contain a given key. It is the responsibility of the caller to verify this (easily enforced with
242
- * typescript, eslint rules, and others).
251
+ * Create a new MessageLoader, which handles lazily loading messages for
252
+ * different locales and sanity checks as needed to provide accessors for each
253
+ * message defined in `messageKeys`.
243
254
  */
244
- function createLoader(localeImportMap, defaultLocale) {
245
- const loader = new MessageLoader(localeImportMap, defaultLocale);
255
+ function createLoader(messageKeys, localeImportMap, defaultLocale) {
256
+ const loader = new MessageLoader(messageKeys, localeImportMap, defaultLocale);
246
257
  LOADER_REGISTRY.push(loader);
247
258
  return loader;
248
259
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@discord/intl",
3
- "version": "0.18.0-canary.fa54f84",
3
+ "version": "0.18.0-rc.0",
4
4
  "license": "MIT",
5
5
  "description": "Client runtime for managing messages and translations in a React project.",
6
6
  "main": "./dist/index.js",
@@ -23,7 +23,7 @@
23
23
  "@formatjs/intl": "^2.10.1",
24
24
  "@intrnl/xxhash64": "^0.1.2",
25
25
  "intl-messageformat": "^10.5.11",
26
- "@discord/intl-ast": "0.18.0"
26
+ "@discord/intl-ast": "0.18.0-rc.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@formatjs/intl-durationformat": "^0.7.3",
@@ -85,7 +85,8 @@ export class MessageLoader {
85
85
  */
86
86
  _localeFileMap?: Record<string, string>;
87
87
 
88
- constructor(localeImportMap: LocaleImportMap, defaultLocale: LocaleId) {
88
+ constructor(messageKeys: string[], localeImportMap: LocaleImportMap, defaultLocale: LocaleId) {
89
+ this.messageKeys = messageKeys;
89
90
  this.messages = {};
90
91
  this.localeImportMap = localeImportMap;
91
92
  this.supportedLocales = Object.keys(localeImportMap);
@@ -177,16 +178,9 @@ export class MessageLoader {
177
178
  return undefined;
178
179
  }
179
180
 
180
- // Then try to return the loaded message. Previously, this used a `key in ...` check to quickly
181
- // verify whether the locale object contains the requested message, but in the case where the
182
- // target is a Proxy or uses some other internalized method for providing gettable values, `in`
183
- // queries aren't guaranteed to work. Instead, since this is realistically amortized to just be
184
- // a property access on every call, we can just the returned value as the determining factor. If
185
- // the locale object returns `undefined`, then it "does not contain" the message, whether it's
186
- // still loading or otherwise. Future calls will then be able to pick up any changed value,
187
- // since it won't be cached in the `_parseCache`.
188
- const content = this.messages[locale][key];
189
- if (content != null) {
181
+ // Then try to return the loaded message.
182
+ if (key in this.messages[locale]) {
183
+ const content = this.messages[locale][key];
190
184
  const message = new InternalIntlMessage(content, locale);
191
185
  (this._parseCache[locale] ??= {})[key] = message;
192
186
  return message;
@@ -196,6 +190,28 @@ export class MessageLoader {
196
190
  return undefined;
197
191
  }
198
192
 
193
+ /**
194
+ * Returns a record mapping the keys this object manages to bound functions
195
+ * for `get` with the that key as the first argument, allowing consumers to
196
+ * just call the function with a locale to retrieve the translated message
197
+ * for that key.
198
+ *
199
+ * This method is provided as a way to generate binds _at runtime_, but for
200
+ * very-large messages files (e.g., thousands of messages), this can be a
201
+ * non-negligible cost. Where feasible, consider generating these binds
202
+ * at build/bundle time, especially in cases where they can be substantially
203
+ * minified (i.e., Hermes bytecode). This is provided automatically as an
204
+ * option when using one of `@discord/intl`'s transformers.
205
+ */
206
+ getBinds(): Record<string, IntlMessageGetter> {
207
+ const result: Record<string, IntlMessageGetter> = {};
208
+ for (const key of this.messageKeys) {
209
+ result[key] = this.get.bind(this, key);
210
+ }
211
+
212
+ return result;
213
+ }
214
+
199
215
  async _loadLocale(locale: LocaleId) {
200
216
  // If the locale is already set in `messages`, then it doesn't need to be loaded again.
201
217
  if (this.messages[locale] != null) return;
@@ -312,15 +328,16 @@ export async function waitForAllDefaultIntlMessagesLoaded(): Promise<void> {
312
328
  }
313
329
 
314
330
  /**
315
- * Create a new MessageLoader, which handles lazily loading messages for different locales and
316
- * sanity checks as needed to provide accessors for each message contained by the import map.
317
- *
318
- * Notably, this does _not_ verify whether the locale objects managed by this loader actually
319
- * contain a given key. It is the responsibility of the caller to verify this (easily enforced with
320
- * typescript, eslint rules, and others).
331
+ * Create a new MessageLoader, which handles lazily loading messages for
332
+ * different locales and sanity checks as needed to provide accessors for each
333
+ * message defined in `messageKeys`.
321
334
  */
322
- export function createLoader(localeImportMap: LocaleImportMap, defaultLocale: LocaleId) {
323
- const loader = new MessageLoader(localeImportMap, defaultLocale);
335
+ export function createLoader(
336
+ messageKeys: string[],
337
+ localeImportMap: LocaleImportMap,
338
+ defaultLocale: LocaleId,
339
+ ) {
340
+ const loader = new MessageLoader(messageKeys, localeImportMap, defaultLocale);
324
341
  LOADER_REGISTRY.push(loader);
325
342
  return loader;
326
343
  }