@vocab/core 1.6.2 → 1.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,6 +13,17 @@ Vocab helps you ship multiple languages without compromising the reliability of
13
13
  - **Strongly typed with TypeScript**\
14
14
  When using translations TypeScript will ensure code only accesses valid translations and translations are passed all required dynamic values.
15
15
 
16
+ ## Table of contents
17
+
18
+ - [Getting started](#getting-started)
19
+ - [Step 1: Install Dependencies](#step-1-install-dependencies)
20
+ - [Step 2: Configure Vocab](#step-2-configure-vocab)
21
+ - [Step 3: Set the language using the React Provider](#step-3-set-the-language-using-the-react-provider)
22
+ - [Step 4: Create translations](#step-4-create-translations)
23
+ - [Step 5: Compile and consume translations](#step-5-compile-and-consume-translations)
24
+ - [Step 6: [Optional] Set up plugin](#step-6-optional-set-up-plugin)
25
+ - [Step 7: [Optional] Optimize for fast page loading](#step-7-optional-optimize-for-fast-page-loading)
26
+
16
27
  ## Getting started
17
28
 
18
29
  ### Step 1: Install Dependencies
@@ -39,8 +50,8 @@ This is the language Vocab will assume when it sees a `translation.json` file wi
39
50
  ```js
40
51
  // vocab.config.js
41
52
  module.exports = {
42
- languages: [{ name: 'en' }, { name: 'fr' }]
43
- devLanguage: 'en',
53
+ languages: [{ name: 'en' }, { name: 'fr' }],
54
+ devLanguage: 'en'
44
55
  };
45
56
  ```
46
57
 
@@ -159,7 +170,9 @@ function MyComponent({ children }) {
159
170
  }
160
171
  ```
161
172
 
162
- ### Step 6: [Optional] Set up Webpack plugin
173
+ ### Step 6: [Optional] Set up plugin
174
+
175
+ #### Webpack Plugin
163
176
 
164
177
  With the default setup, every language is loaded into your web application all the time, potentially leading to a large bundle size.
165
178
  Ideally you will want to switch out the Node.js/default runtime for the web runtime, which only loads the active language.
@@ -181,6 +194,85 @@ module.exports = {
181
194
  };
182
195
  ```
183
196
 
197
+ #### Vite Plugin _(this plugin is experimental)_
198
+
199
+ > [!NOTE]
200
+ > This plugin is still experimental and may not work in all cases. If you encounter any issues, please open an issue on the Vocab GitHub repository.
201
+
202
+ Vocab also provides a Vite plugin to handle the same functionality as the Webpack plugin.
203
+
204
+ ```shell
205
+ npm i --save-dev @vocab/vite
206
+ ```
207
+
208
+ default usage
209
+
210
+ ```js
211
+ // vite.config.js
212
+ import { defineConfig } from 'vite';
213
+ import { vocabPluginVite } from '@vocab/vite';
214
+ import vocabConfig from './vocab.config.cjs';
215
+
216
+ export default defineConfig({
217
+ plugins: [
218
+ vocabPluginVite({
219
+ vocabConfig
220
+ })
221
+ ]
222
+ });
223
+ ```
224
+
225
+ #### createVocabChunks
226
+
227
+ If you want to combine all language files into a single chunk, you can use the `createVocabChunks` function.
228
+ Simply use the function in your `manualChunks` configuration.
229
+
230
+ ```js
231
+ // vite.config.js
232
+ import { defineConfig } from 'vite';
233
+ import { vocabPluginVite } from '@vocab/vite';
234
+ import { createVocabChunks } from '@vocab/vite/create-vocab-chunks';
235
+ import vocabConfig from './vocab.config.cjs';
236
+
237
+ export default defineConfig({
238
+ plugins: [
239
+ vocabPluginVite({
240
+ vocabConfig
241
+ })
242
+ ],
243
+ build: {
244
+ rollupOptions: {
245
+ output: {
246
+ manualChunks: (id, ctx) => {
247
+ // handle your own manual chunks before or after the vocab chunks.
248
+ const languageChunkName = createVocabChunks(
249
+ id,
250
+ ctx
251
+ );
252
+ if (languageChunkName) {
253
+ // vocab has found a language chunk. Either return it or handle it in your own way.
254
+ return languageChunkName;
255
+ }
256
+ }
257
+ }
258
+ }
259
+ }
260
+ });
261
+ ```
262
+
263
+ #### VocabPluginOptions
264
+
265
+ ```ts
266
+ type VocabPluginOptions = {
267
+ /**
268
+ * The Vocab configuration file.
269
+ * The type can be found in the `@vocab/core/types`.
270
+ * This value is required
271
+ */
272
+ vocabConfig: UserConfig;
273
+ };
274
+ ```
275
+
184
276
  ### Step 7: [Optional] Optimize for fast page loading
185
277
 
186
278
  Using the above method without optimizing what chunks webpack uses you may find the page needing to do an extra round trip to load languages on a page.
@@ -207,7 +299,7 @@ extractor.addChunk(chunkName);
207
299
 
208
300
  Translation messages can sometimes contain dynamic values, such as dates/times, links, usernames, etc.
209
301
  These values often exist somewhere in the middle of a message, and could change location depending on the translation.
210
- To support this, Vocab uses [Format.js's `intl-messageformat` library], which enables you to use [ICU Message syntax](https://formatjs.io/docs/core-concepts/icu-syntax/) in your messages.
302
+ To support this, Vocab uses [Format.js's `intl-messageformat` library], which enables you to use [ICU Message syntax](https://formatjs.github.io/docs/core-concepts/icu-syntax/) in your messages.
211
303
 
212
304
  In the below example we are defining two messages: one that accepts a single parameter, and one that accepts a component.
213
305
 
@@ -231,7 +323,7 @@ t('my key with component', {
231
323
  });
232
324
  ```
233
325
 
234
- [Format.js's `intl-messageformat` library]: https://formatjs.io/docs/intl-messageformat/
326
+ [Format.js's `intl-messageformat` library]: https://formatjs.github.io/docs/intl-messageformat/
235
327
 
236
328
  ## Overriding the Locale
237
329
 
@@ -254,7 +346,7 @@ This can be useful in certain situations:
254
346
  For example: `th-u-ca-gregory`.
255
347
  See the [MDN Intl docs] for more information on BCP 47 extension sequences.
256
348
 
257
- [`intl-messageformat`]: https://formatjs.io/docs/intl-messageformat/
349
+ [`intl-messageformat`]: https://formatjs.github.io/docs/intl-messageformat/
258
350
  [IETF language tag]: https://en.wikipedia.org/wiki/IETF_language_tag
259
351
  [mdn intl docs]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locales_argument
260
352
 
@@ -311,8 +403,8 @@ const Currency = ({ value, currency }) => {
311
403
  };
312
404
  ```
313
405
 
314
- [numbers]: https://formatjs.io/docs/core-concepts/icu-syntax/#number-type
315
- [dates, and times]: https://formatjs.io/docs/core-concepts/icu-syntax/#supported-datetime-skeleton
406
+ [numbers]: https://formatjs.github.io/docs/core-concepts/icu-syntax/#number-type
407
+ [dates, and times]: https://formatjs.github.io/docs/core-concepts/icu-syntax/#supported-datetime-skeleton
316
408
 
317
409
  ## Configuration
318
410
 
@@ -452,7 +544,7 @@ const App = () => (
452
544
  );
453
545
  ```
454
546
 
455
- [icu message syntax]: https://formatjs.io/docs/intl-messageformat/#message-syntax
547
+ [icu message syntax]: https://formatjs.github.io/docs/intl-messageformat/#message-syntax
456
548
  [diacritics]: https://en.wikipedia.org/wiki/Diacritic
457
549
 
458
550
  ## Pseudo-localization
@@ -629,6 +721,17 @@ referenced in the upload. These keys can be deleted from Phrase by providing the
629
721
  vocab push --branch my-branch --delete-unused-keys
630
722
  ```
631
723
 
724
+ #### Ignoring Files
725
+
726
+ The `ignore` key in your [Vocab config](#configuration) allows you to ignore certain files from being validated, compiled and uploaded.
727
+ However, in some cases you may only want certain files to be compiled and validated, but not uploaded, such as those present in a build output directory.
728
+ This can be accomplished by providing the `--ignore` flag to `vocab push`.
729
+ This flag accepts an array of glob patterns to ignore.
730
+
731
+ ```sh
732
+ vocab push --branch my-branch --ignore "**/dist/**" "**/another_ignored_directory/**"
733
+ ```
734
+
632
735
  [phrase]: https://developers.phrase.com/api/
633
736
 
634
737
  #### [Tags]
@@ -3,4 +3,4 @@ export { validate } from "./validate/index.js";
3
3
  export { resolveConfig, resolveConfigSync, validateConfig } from "./config.js";
4
4
  export { getAltLanguages, getAltLanguageFilePath, getDevLanguageFileFromTsFile, } from "./utils.js";
5
5
  export { getUniqueKey, loadAllTranslations, loadTranslation, } from "./load-translations.js";
6
- export * from "./types.js";
6
+ export type * from "./types.js";
@@ -4,7 +4,7 @@ export declare function getUniqueKey(key: string, namespace: string): string;
4
4
  export declare function mergeWithDevLanguageTranslation({ translation, devTranslation, }: {
5
5
  translation: TranslationsByKey;
6
6
  devTranslation: TranslationsByKey;
7
- }): TranslationsByKey<string>;
7
+ }): TranslationsByKey;
8
8
  export declare function getLanguageHierarchy({ languages, }: {
9
9
  languages: LanguageTarget[];
10
10
  }): Map<string, string[]>;
@@ -1,2 +1,2 @@
1
- export * from "./declarations/src/index";
1
+ export * from "./declarations/src/index.js";
2
2
  //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidm9jYWItY29yZS5janMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4vZGVjbGFyYXRpb25zL3NyYy9pbmRleC5kLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBIn0=
@@ -324,6 +324,8 @@ function loadAltLanguageFile({
324
324
  try {
325
325
  const altFilePath = getAltLanguageFilePath(filePath, fallbackLanguage);
326
326
  delete require.cache[altFilePath];
327
+
328
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
327
329
  const translationFile = require(altFilePath);
328
330
  const {
329
331
  keys: fallbackLanguageTranslation
@@ -335,7 +337,7 @@ function loadAltLanguageFile({
335
337
  translation: fallbackLanguageTranslation,
336
338
  devTranslation
337
339
  }));
338
- } catch (e) {
340
+ } catch {
339
341
  trace(`Missing alt language file ${getAltLanguageFilePath(filePath, fallbackLanguage)}
340
342
  `);
341
343
  }
@@ -359,6 +361,7 @@ function loadTranslation({
359
361
  trace(`Loading translation file in "${fallbacks}" fallback mode: "${filePath}"`);
360
362
  const languageSet = {};
361
363
  delete require.cache[filePath];
364
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
362
365
  const translationContent = require(filePath);
363
366
  const relativePath = path__default["default"].relative(userConfig.projectRoot || process.cwd(), filePath);
364
367
  const {
@@ -419,13 +422,15 @@ async function loadAllTranslations({
419
422
  cwd: projectRoot
420
423
  });
421
424
  trace(`Found ${translationFiles.length} translation files`);
422
- const result = await Promise.all(translationFiles.map(filePath => loadTranslation({
423
- filePath,
424
- fallbacks,
425
- withTags
426
- }, config)));
425
+ const loadedTranslations = [];
427
426
  const keys = new Set();
428
- for (const loadedTranslation of result) {
427
+ for (const translationFile of translationFiles) {
428
+ const loadedTranslation = loadTranslation({
429
+ filePath: translationFile,
430
+ fallbacks,
431
+ withTags
432
+ }, config);
433
+ loadedTranslations.push(loadedTranslation);
429
434
  for (const key of loadedTranslation.keys) {
430
435
  const uniqueKey = getUniqueKey(key, loadedTranslation.namespace);
431
436
  if (keys.has(uniqueKey)) {
@@ -442,7 +447,7 @@ async function loadAllTranslations({
442
447
  }
443
448
  }
444
449
  }
445
- return result;
450
+ return loadedTranslations;
446
451
  }
447
452
 
448
453
  function extractHasTags(ast) {
@@ -581,7 +586,7 @@ async function generateRuntime(loadedTranslation) {
581
586
  }
582
587
  const prettierConfig = await prettier__default["default"].resolveConfig(filePath);
583
588
  const serializedTranslationType = serialiseTranslationRuntime(translationTypes, imports, loadedTranslation);
584
- const declaration = prettier__default["default"].format(serializedTranslationType, {
589
+ const declaration = await prettier__default["default"].format(serializedTranslationType, {
585
590
  ...prettierConfig,
586
591
  parser: 'typescript'
587
592
  });
@@ -659,7 +664,7 @@ async function writeIfChanged(filepath, contents) {
659
664
  encoding: 'utf-8'
660
665
  });
661
666
  hasChanged = existingContents !== contents;
662
- } catch (e) {
667
+ } catch {
663
668
  // ignore error, likely a file doesn't exist error so we want to write anyway
664
669
  }
665
670
  if (hasChanged) {
@@ -851,6 +856,7 @@ function createConfig(configFilePath) {
851
856
  const cwd = path__default["default"].dirname(configFilePath);
852
857
  return {
853
858
  projectRoot: cwd,
859
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
854
860
  ...require(configFilePath)
855
861
  };
856
862
  }
@@ -324,6 +324,8 @@ function loadAltLanguageFile({
324
324
  try {
325
325
  const altFilePath = getAltLanguageFilePath(filePath, fallbackLanguage);
326
326
  delete require.cache[altFilePath];
327
+
328
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
327
329
  const translationFile = require(altFilePath);
328
330
  const {
329
331
  keys: fallbackLanguageTranslation
@@ -335,7 +337,7 @@ function loadAltLanguageFile({
335
337
  translation: fallbackLanguageTranslation,
336
338
  devTranslation
337
339
  }));
338
- } catch (e) {
340
+ } catch {
339
341
  trace(`Missing alt language file ${getAltLanguageFilePath(filePath, fallbackLanguage)}
340
342
  `);
341
343
  }
@@ -359,6 +361,7 @@ function loadTranslation({
359
361
  trace(`Loading translation file in "${fallbacks}" fallback mode: "${filePath}"`);
360
362
  const languageSet = {};
361
363
  delete require.cache[filePath];
364
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
362
365
  const translationContent = require(filePath);
363
366
  const relativePath = path__default["default"].relative(userConfig.projectRoot || process.cwd(), filePath);
364
367
  const {
@@ -419,13 +422,15 @@ async function loadAllTranslations({
419
422
  cwd: projectRoot
420
423
  });
421
424
  trace(`Found ${translationFiles.length} translation files`);
422
- const result = await Promise.all(translationFiles.map(filePath => loadTranslation({
423
- filePath,
424
- fallbacks,
425
- withTags
426
- }, config)));
425
+ const loadedTranslations = [];
427
426
  const keys = new Set();
428
- for (const loadedTranslation of result) {
427
+ for (const translationFile of translationFiles) {
428
+ const loadedTranslation = loadTranslation({
429
+ filePath: translationFile,
430
+ fallbacks,
431
+ withTags
432
+ }, config);
433
+ loadedTranslations.push(loadedTranslation);
429
434
  for (const key of loadedTranslation.keys) {
430
435
  const uniqueKey = getUniqueKey(key, loadedTranslation.namespace);
431
436
  if (keys.has(uniqueKey)) {
@@ -442,7 +447,7 @@ async function loadAllTranslations({
442
447
  }
443
448
  }
444
449
  }
445
- return result;
450
+ return loadedTranslations;
446
451
  }
447
452
 
448
453
  function extractHasTags(ast) {
@@ -581,7 +586,7 @@ async function generateRuntime(loadedTranslation) {
581
586
  }
582
587
  const prettierConfig = await prettier__default["default"].resolveConfig(filePath);
583
588
  const serializedTranslationType = serialiseTranslationRuntime(translationTypes, imports, loadedTranslation);
584
- const declaration = prettier__default["default"].format(serializedTranslationType, {
589
+ const declaration = await prettier__default["default"].format(serializedTranslationType, {
585
590
  ...prettierConfig,
586
591
  parser: 'typescript'
587
592
  });
@@ -659,7 +664,7 @@ async function writeIfChanged(filepath, contents) {
659
664
  encoding: 'utf-8'
660
665
  });
661
666
  hasChanged = existingContents !== contents;
662
- } catch (e) {
667
+ } catch {
663
668
  // ignore error, likely a file doesn't exist error so we want to write anyway
664
669
  }
665
670
  if (hasChanged) {
@@ -851,6 +856,7 @@ function createConfig(configFilePath) {
851
856
  const cwd = path__default["default"].dirname(configFilePath);
852
857
  return {
853
858
  projectRoot: cwd,
859
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
854
860
  ...require(configFilePath)
855
861
  };
856
862
  }
@@ -308,6 +308,8 @@ function loadAltLanguageFile({
308
308
  try {
309
309
  const altFilePath = getAltLanguageFilePath(filePath, fallbackLanguage);
310
310
  delete require.cache[altFilePath];
311
+
312
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
311
313
  const translationFile = require(altFilePath);
312
314
  const {
313
315
  keys: fallbackLanguageTranslation
@@ -319,7 +321,7 @@ function loadAltLanguageFile({
319
321
  translation: fallbackLanguageTranslation,
320
322
  devTranslation
321
323
  }));
322
- } catch (e) {
324
+ } catch {
323
325
  trace(`Missing alt language file ${getAltLanguageFilePath(filePath, fallbackLanguage)}
324
326
  `);
325
327
  }
@@ -343,6 +345,7 @@ function loadTranslation({
343
345
  trace(`Loading translation file in "${fallbacks}" fallback mode: "${filePath}"`);
344
346
  const languageSet = {};
345
347
  delete require.cache[filePath];
348
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
346
349
  const translationContent = require(filePath);
347
350
  const relativePath = path.relative(userConfig.projectRoot || process.cwd(), filePath);
348
351
  const {
@@ -403,13 +406,15 @@ async function loadAllTranslations({
403
406
  cwd: projectRoot
404
407
  });
405
408
  trace(`Found ${translationFiles.length} translation files`);
406
- const result = await Promise.all(translationFiles.map(filePath => loadTranslation({
407
- filePath,
408
- fallbacks,
409
- withTags
410
- }, config)));
409
+ const loadedTranslations = [];
411
410
  const keys = new Set();
412
- for (const loadedTranslation of result) {
411
+ for (const translationFile of translationFiles) {
412
+ const loadedTranslation = loadTranslation({
413
+ filePath: translationFile,
414
+ fallbacks,
415
+ withTags
416
+ }, config);
417
+ loadedTranslations.push(loadedTranslation);
413
418
  for (const key of loadedTranslation.keys) {
414
419
  const uniqueKey = getUniqueKey(key, loadedTranslation.namespace);
415
420
  if (keys.has(uniqueKey)) {
@@ -426,7 +431,7 @@ async function loadAllTranslations({
426
431
  }
427
432
  }
428
433
  }
429
- return result;
434
+ return loadedTranslations;
430
435
  }
431
436
 
432
437
  function extractHasTags(ast) {
@@ -565,7 +570,7 @@ async function generateRuntime(loadedTranslation) {
565
570
  }
566
571
  const prettierConfig = await prettier.resolveConfig(filePath);
567
572
  const serializedTranslationType = serialiseTranslationRuntime(translationTypes, imports, loadedTranslation);
568
- const declaration = prettier.format(serializedTranslationType, {
573
+ const declaration = await prettier.format(serializedTranslationType, {
569
574
  ...prettierConfig,
570
575
  parser: 'typescript'
571
576
  });
@@ -643,7 +648,7 @@ async function writeIfChanged(filepath, contents) {
643
648
  encoding: 'utf-8'
644
649
  });
645
650
  hasChanged = existingContents !== contents;
646
- } catch (e) {
651
+ } catch {
647
652
  // ignore error, likely a file doesn't exist error so we want to write anyway
648
653
  }
649
654
  if (hasChanged) {
@@ -835,6 +840,7 @@ function createConfig(configFilePath) {
835
840
  const cwd = path.dirname(configFilePath);
836
841
  return {
837
842
  projectRoot: cwd,
843
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
838
844
  ...require(configFilePath)
839
845
  };
840
846
  }
@@ -1,2 +1,2 @@
1
- export * from "../../dist/declarations/src/icu-handler";
1
+ export * from "../../dist/declarations/src/icu-handler.js";
2
2
  //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidm9jYWItY29yZS1pY3UtaGFuZGxlci5janMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL2Rpc3QvZGVjbGFyYXRpb25zL3NyYy9pY3UtaGFuZGxlci5kLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBIn0=
package/package.json CHANGED
@@ -1,6 +1,11 @@
1
1
  {
2
2
  "name": "@vocab/core",
3
- "version": "1.6.2",
3
+ "version": "1.6.4",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/seek-oss/vocab.git",
7
+ "directory": "packages/core"
8
+ },
4
9
  "main": "dist/vocab-core.cjs.js",
5
10
  "module": "dist/vocab-core.esm.js",
6
11
  "exports": {
@@ -47,10 +52,9 @@
47
52
  "find-up": "^5.0.0",
48
53
  "intl-messageformat": "^10.0.0",
49
54
  "picocolors": "^1.0.0",
50
- "prettier": "^2.1.2"
55
+ "prettier": "^3.5.3"
51
56
  },
52
57
  "devDependencies": {
53
- "@types/debug": "^4.1.5",
54
- "@types/prettier": "^2.1.5"
58
+ "@types/debug": "^4.1.5"
55
59
  }
56
60
  }
@@ -1,2 +1,2 @@
1
- export * from "../../dist/declarations/src/runtime";
1
+ export * from "../../dist/declarations/src/runtime.js";
2
2
  //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidm9jYWItY29yZS1ydW50aW1lLmNqcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vZGlzdC9kZWNsYXJhdGlvbnMvc3JjL3J1bnRpbWUuZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSJ9
@@ -1,2 +1,2 @@
1
- export * from "../../dist/declarations/src/translation-file";
1
+ export * from "../../dist/declarations/src/translation-file.js";
2
2
  //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidm9jYWItY29yZS10cmFuc2xhdGlvbi1maWxlLmNqcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vZGlzdC9kZWNsYXJhdGlvbnMvc3JjL3RyYW5zbGF0aW9uLWZpbGUuZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSJ9