@vocab/phrase 1.3.1 → 1.3.3

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
@@ -4,73 +4,114 @@ Vocab is a strongly typed internationalization framework for React.
4
4
 
5
5
  Vocab helps you ship multiple languages without compromising the reliability of your site or slowing down delivery.
6
6
 
7
- - Shareable translations
8
-
7
+ - **Shareable translations**\
9
8
  Translations are co-located with the components that use them. Vocab uses the module graph allowing shared components to be installed with package managers like npm, just like any other module.
10
9
 
11
- - Loading translations dynamically
12
-
10
+ - **Loading translations dynamically**\
13
11
  Vocab only loads the current user's language. If the language changes Vocab can load the new language behind the scenes without reloading the page.
14
12
 
15
- - Strongly typed with TypeScript
16
-
13
+ - **Strongly typed with TypeScript**\
17
14
  When using translations TypeScript will ensure code only accesses valid translations and translations are passed all required dynamic values.
18
15
 
19
16
  ## Getting started
20
17
 
21
18
  ### Step 1: Install Dependencies
22
19
 
23
- Vocab is a monorepo with different packages you can install depending on your usage, the below list will get you started using the CLI and React integration.
20
+ Vocab is a monorepo containing different packages you can install depending on your usage.
21
+ The below list will get you started using the CLI and React integration.
24
22
 
25
- ```bash
26
- $ npm i --save-dev @vocab/cli
27
- $ npm i --save @vocab/core @vocab/react
23
+ ```sh
24
+ npm install --save-dev @vocab/cli
25
+ npm install --save @vocab/core @vocab/react
28
26
  ```
29
27
 
30
28
  ### Step 2: Configure Vocab
31
29
 
32
- You can configure Vocab directly when calling the API or via a `vocab.config.js` or `vocab.config.cjs` file.
30
+ You can configure Vocab directly when calling the API, or via a `vocab.config.js` or `vocab.config.cjs` file.
33
31
 
34
- In this example we've configured two languages, English and French, where our initial `translation.json` files will use English.
32
+ > [!TIP]
33
+ > It's a good idea to name your languages using [IETF language tags], however this is not a requirement.
35
34
 
36
- **vocab.config.js**
35
+ In this example we've configured two languages named `en` (English) and `fr` (French).
36
+ We've also configured a `devLanguage` of `en`.
37
+ This is the language Vocab will assume when it sees a `translation.json` file without a language prefix.
37
38
 
38
39
  ```js
40
+ // vocab.config.js
39
41
  module.exports = {
40
- devLanguage: 'en',
41
42
  languages: [{ name: 'en' }, { name: 'fr' }]
43
+ devLanguage: 'en',
42
44
  };
43
45
  ```
44
46
 
47
+ See the [configuration] section for more configuration options.
48
+
49
+ [IETF language tags]: https://en.wikipedia.org/wiki/IETF_language_tag
50
+ [configuration]: #configuration
51
+
45
52
  ### Step 3: Set the language using the React Provider
46
53
 
47
- Vocab doesn't tell you how to select or change your language. You just need to tell Vocab what language to use.
54
+ Vocab uses React's context API to provide information for your translation lookups.
55
+ To tell Vocab which language to use, wrap your app in a `VocabProvider` component and pass in a `language` prop corresponding to one of the language names configured in your `vocab.config.js` file.
56
+
57
+ > [!NOTE]
58
+ > Using methods discussed later we'll make sure the first language is loaded on page load.
59
+ > However, after this, changing languages may lead to a period of no translations as Vocab downloads the new language's translations.
48
60
 
49
- **Note:** Using methods discussed later we'll make sure the first language is loaded on page load. However, after this, changing languages may then lead to a period of no translations as Vocab downloads the new language's translations.
61
+ ```tsx
62
+ // src/App.tsx
50
63
 
51
- **src/App.tsx**
64
+ import { VocabProvider } from '@vocab/react';
65
+
66
+ const App = ({ children }) => {
67
+ return (
68
+ <VocabProvider language="en">{children}</VocabProvider>
69
+ );
70
+ };
71
+ ```
72
+
73
+ If you need to customize the locale for your language, you can pass a `locale` prop to the `VocabProvider` component.
74
+ This tells Vocab which locale to use when formatting your translations.
52
75
 
53
76
  ```tsx
77
+ // src/App.tsx
78
+
54
79
  import { VocabProvider } from '@vocab/react';
55
80
 
56
81
  function App({ children }) {
57
82
  return (
58
- <VocabProvider language={language}>
83
+ <VocabProvider language="myCustomLanguage" locale="en">
59
84
  {children}
60
85
  </VocabProvider>
61
86
  );
62
87
  }
63
88
  ```
64
89
 
65
- ### Step 4: Create initial values and use them
90
+ See [here][overriding the locale] for more information on how and when to use the `locale` prop.
66
91
 
67
- A translation file is a JSON file consisting of a flat structure of keys, each with a message and an optional description.
92
+ [overriding the locale]: #overriding-the-locale
68
93
 
69
- **Note:** Currently, to create a new translation it must be placed inside a folder ending in **`.vocab`**, this folder suffix can be configured with the `translationsDirectorySuffix` configuration value.
94
+ ### Step 4: Create translations
70
95
 
71
- **`./example.vocab/translations.json`**
96
+ A translation file is a JSON file consisting of a flat structure of keys.
97
+ Each key must contain a `message` property, and optionally a `description` property.
98
+
99
+ Rather than creating one giant file for each language's translations, Vocab enables you to co-locate the translations alongside their consuming components.
100
+ To facilitate this, Vocab lets you group translations inside folders ending in `.vocab`.
101
+ You may have as many of these folders as you like in your project.
102
+
103
+ > [!TIP]
104
+ > Your folders can be named anything, as long as it ends in `.vocab`.
105
+ > It's recommened to just name your folders `.vocab` so you have one less name to think of/rename in the future.
106
+
107
+ Translation files must follow the naming pattern of `{languageName}.translations.json`.
108
+ The exception to this is translations for your `devLanguage` which must be placed in a file named `translations.json`.
109
+
110
+ In the following examples, we're defining translations for our `devLanguage`, and a language named `fr`.
111
+
112
+ ```jsonc
113
+ // src/MyComponent/.vocab/translations.json
72
114
 
73
- ```json
74
115
  {
75
116
  "my key": {
76
117
  "message": "Hello from Vocab",
@@ -79,57 +120,65 @@ A translation file is a JSON file consisting of a flat structure of keys, each w
79
120
  }
80
121
  ```
81
122
 
82
- Then run `vocab compile`. Or `vocab compile --watch`.
83
- This will create a new `index.ts` file for each folder ending in **`.vocab`**.
123
+ ```jsonc
124
+ // src/MyComponent/.vocab/fr.translations.json
125
+
126
+ {
127
+ "my key": {
128
+ "message": "Bonjour de Vocab",
129
+ "description": "An optional description to help when translating"
130
+ }
131
+ }
132
+ ```
133
+
134
+ > [!NOTE]
135
+ > You can create your translation files manually.
136
+ > However, Vocab also offers integrations with remote translation platforms to push and pull translations automatically.
137
+ > See [External translation tooling] for more information.
84
138
 
85
- You can then import these translations into your React components. Translations can be used by calling the `t` function returned by `useTranslations`.
139
+ [External translation tooling]: #external-translation-tooling
86
140
 
87
- **./MyComponent.tsx**
141
+ ### Step 5: Compile and consume translations
142
+
143
+ Once you have created some translations, run `vocab compile`.
144
+ This command creates an `index.ts` file inside each folder ending in `.vocab`.
145
+ Importing this file provides type-safe translations for your React components.
146
+ Accessing translation messages is done by passing these imported translations to the `useTranslations` hook and using the returned `t` function.
88
147
 
89
148
  ```tsx
149
+ // src/MyComponent.tsx
150
+
90
151
  import { useTranslations } from '@vocab/react';
91
- import translations from './example.vocab';
152
+ import translations from './.vocab';
92
153
 
93
154
  function MyComponent({ children }) {
94
155
  const { t } = useTranslations(translations);
95
- return <div>{t('my key')}</div>;
96
- }
97
- ```
98
-
99
- ### Step 5: Create translations
100
-
101
- So far, your app will run, but you're missing any translations other than the initial language. The below file can be created manually; however, you can also integrate with a remote translation platform to push and pull translations automatically. See [External translation tooling](#external-translation-tooling) for more information.
102
-
103
- **./example.vocab/fr-FR.translations.json**
104
156
 
105
- ```json
106
- {
107
- "my key": {
108
- "message": "Bonjour de Vocab",
109
- "description": "An optional description to help when translating"
110
- }
157
+ // t('my key') will return the appropriate translation based on the language set in your app's VocabProvider
158
+ return <div>{t('my key')}</div>;
111
159
  }
112
160
  ```
113
161
 
114
162
  ### Step 6: [Optional] Set up Webpack plugin
115
163
 
116
- Right now every language is loaded into your web application all the time, which could lead to a large bundle size. Ideally you will want to switch out the Node/default runtime for web runtime that will load only the active language.
164
+ With the default setup, every language is loaded into your web application all the time, potentially leading to a large bundle size.
165
+ Ideally you will want to switch out the Node.js/default runtime for the web runtime, which only loads the active language.
117
166
 
118
- This is done using the **VocabWebpackPlugin**. Applying this plugin to your client webpack configuration will replace all vocab files with a dynamic asynchronous chunks designed for the web.
167
+ This is done using the `VocabWebpackPlugin`.
168
+ Applying this plugin to your client webpack configuration will replace all vocab files with dynamic asynchronous chunks designed for the web.
119
169
 
120
- ```bash
121
- $ npm i --save-dev @vocab/webpack
170
+ ```sh
171
+ npm i --save-dev @vocab/webpack
122
172
  ```
123
173
 
124
- **webpack.config.js**
125
-
126
174
  ```js
175
+ // webpack.config.js
176
+
127
177
  const { VocabWebpackPlugin } = require('@vocab/webpack');
128
178
 
129
179
  module.exports = {
130
- ...,
131
180
  plugins: [new VocabWebpackPlugin()]
132
- }
181
+ };
133
182
  ```
134
183
 
135
184
  ### Step 7: [Optional] Optimize for fast page loading
@@ -138,11 +187,11 @@ Using the above method without optimizing what chunks webpack uses you may find
138
187
 
139
188
  This is where `getChunkName` can be used to retrieve the Webpack chunk used for a specific language.
140
189
 
141
- For example, here is a Server Render function that would add the current language chunk to [Loadable component's ChunkExtractor](https://loadable-components.com/docs/api-loadable-server/#chunkextractor).
142
-
143
- **src/render.tsx**
190
+ For example, here is a server render function that would add the current language chunk to [Loadable component's ChunkExtractor](https://loadable-components.com/docs/api-loadable-server/#chunkextractor).
144
191
 
145
192
  ```tsx
193
+ // src/render.tsx
194
+
146
195
  import { getChunkName } from '@vocab/webpack/chunk-name';
147
196
 
148
197
  // ...
@@ -154,13 +203,13 @@ const extractor = new ChunkExtractor();
154
203
  extractor.addChunk(chunkName);
155
204
  ```
156
205
 
157
- ## ICU Message format
158
-
159
- Translation messages can sometimes contain dynamic values, such as dates/times, links or usernames. These values can often exist somewhere in the middle of a message and change location based on translation.
206
+ ## Dynamic Values in Translations
160
207
 
161
- To support this Vocab uses [Format.js's intl-messageformat] allowing you to use [ICU Message syntax](https://formatjs.io/docs/core-concepts/icu-syntax/) in your messages.
208
+ Translation messages can sometimes contain dynamic values, such as dates/times, links, usernames, etc.
209
+ 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.
162
211
 
163
- In the below example we use two messages, one that passes in a single parameter and one uses a component.
212
+ In the below example we are defining two messages: one that accepts a single parameter, and one that accepts a component.
164
213
 
165
214
  ```json
166
215
  {
@@ -173,7 +222,7 @@ In the below example we use two messages, one that passes in a single parameter
173
222
  }
174
223
  ```
175
224
 
176
- Vocab will automatically parse these strings as ICU messages, identify the required parameters and ensure TypeScript knows the values must be passed in.
225
+ Vocab will automatically parse these strings as ICU messages and generate strict types for any parameters it finds.
177
226
 
178
227
  ```tsx
179
228
  t('my key with param', { name: 'Vocab' });
@@ -182,13 +231,96 @@ t('my key with component', {
182
231
  });
183
232
  ```
184
233
 
185
- ## Configuration
234
+ [Format.js's `intl-messageformat` library]: https://formatjs.io/docs/intl-messageformat/
186
235
 
187
- Configuration can either be passed into the Node API directly or be gathered from the nearest _vocab.config.js_ or _vocab.config.cjs_ file.
236
+ ## Overriding the Locale
188
237
 
189
- **vocab.config.js**
238
+ By default, your language name is passed as the `locale` to the formatting API provided by [`intl-messageformat`].
239
+ The `locale` is used to determine how to format dates, numbers, and other locale-sensitive values.
240
+ If you wish to customize this behaviour, you can pass a `locale` prop to the `VocabProvider` component.
241
+
242
+ ```tsx
243
+ <VocabProvider language="myCustomLanguage" locale="th-TH">
244
+ {children}
245
+ </VocabProvider>
246
+ ```
247
+
248
+ This can be useful in certain situations:
249
+
250
+ - You have chosen to name your language something other than an [IETF language tag], but still want to use a specific locale for formatting
251
+ - You want to use a different locale for formatting a specific language.
252
+ E.g. when formatting values for `th` (Thai) locales, the default calendar is Buddhist, but you may want to use the Gregorian calendar.
253
+ This can be achieved by specifying a `locale` value with a BCP 47 extension sequence suffix such as `-u-ca-gregory`.
254
+ For example: `th-u-ca-gregory`.
255
+ See the [MDN Intl docs] for more information on BCP 47 extension sequences.
256
+
257
+ [`intl-messageformat`]: https://formatjs.io/docs/intl-messageformat/
258
+ [IETF language tag]: https://en.wikipedia.org/wiki/IETF_language_tag
259
+ [mdn intl docs]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locales_argument
260
+
261
+ ## Accessing the Current `language` or `locale`
262
+
263
+ If you need to access either the `language` or `locale` that you passed to your `VocabProvider`, you can use the `useLanguage` hook:
264
+
265
+ ```tsx
266
+ import { useLanguage } from '@vocab/react';
267
+
268
+ const MyComponent = () => {
269
+ const { language, locale } = useLanguage();
270
+ return (
271
+ <div>
272
+ {language} - {locale}
273
+ </div>
274
+ );
275
+ };
276
+ ```
277
+
278
+ > [!CAUTION]\
279
+ > `locale` is only available when you pass a `locale` prop to your `VocabProvider`.
280
+ > If you don't pass a `locale` prop, `locale` will be `undefined`.
281
+ > It's generally advised to name your languages using [IETF language tags] and let Vocab handle the locale for you.
282
+ > This gives you the added benefit that you can use the `language` from `useLanguage` if necessary, and it will always be defined.
283
+
284
+ Typically you won't need to access these values since the ICU message syntax supports locale-aware formatting of [numbers], [dates, and times].
285
+ However, one use case where you might need to access these values is when formatting a currency value.
286
+ This is because there is currently no way to specify the currency for an ICU message programmatically, so it must be hardcoded within the messsage.
287
+ This poses a problem when you don't want to couple your translations to a specific currency.
288
+
289
+ ```json
290
+ {
291
+ "my key with currency": {
292
+ "message": "You have {value, number, ::compact-short currency/GBP}"
293
+ }
294
+ }
295
+ ```
296
+
297
+ When given a `value` of `123`, the above message would render as `You have GBP 123`.
298
+
299
+ To format a value with a dynamic currency, you could use the `useLanguage` hook to access the current `language` and format the currency value using the `Intl.NumberFormat` API:
300
+
301
+ ```tsx
302
+ const Currency = ({ value, currency }) => {
303
+ const { language } = useLanguage();
304
+
305
+ const formattedValue = new Intl.NumberFormat(locale, {
306
+ style: 'currency',
307
+ currency
308
+ }).format(value);
309
+
310
+ return <div>{formattedValue}</div>;
311
+ };
312
+ ```
313
+
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
316
+
317
+ ## Configuration
318
+
319
+ Configuration can either be passed into the Node API directly or be gathered from the nearest `vocab.config.js` or `vocab.config.cjs` file.
190
320
 
191
321
  ```js
322
+ // vocab.config.js
323
+
192
324
  function capitalize(element) {
193
325
  return element.toUpperCase();
194
326
  }
@@ -236,6 +368,32 @@ module.exports = {
236
368
  };
237
369
  ```
238
370
 
371
+ ## Translation Key Types
372
+
373
+ If you need to access the keys of your translations as a TypeScript type, you can use the `TranslationKeys` type from `@vocab/core`:
374
+
375
+ ```jsonc
376
+ // translations.json
377
+ {
378
+ "Hello": {
379
+ "message": "Hello"
380
+ },
381
+ "Goodbye": {
382
+ "message": "Goodbye"
383
+ }
384
+ }
385
+ ```
386
+
387
+ ```ts
388
+ import type { TranslationKeys } from '@vocab/core';
389
+ import translations from './.vocab';
390
+
391
+ // "Hello" | "Goodbye"
392
+ type MyTranslationKeys = TranslationKeys<
393
+ typeof translations
394
+ >;
395
+ ```
396
+
239
397
  ## Generated languages
240
398
 
241
399
  Vocab supports the creation of generated languages via the `generatedLanguages` config.
@@ -254,9 +412,9 @@ An example of a use case for this function would be adding padding text to the s
254
412
 
255
413
  By default, a generated language's messages will be based off the `devLanguage`'s messages, but this can be overridden by providing an `extends` value that references another language.
256
414
 
257
- **vocab.config.js**
258
-
259
415
  ```js
416
+ // vocab.config.js
417
+
260
418
  function capitalize(message) {
261
419
  return message.toUpperCase();
262
420
  }
@@ -284,12 +442,12 @@ module.exports = {
284
442
  Generated languages are consumed the same way as regular languages.
285
443
  Any Vocab API that accepts a `language` parameter will work with a generated language as well as a regular language.
286
444
 
287
- **App.tsx**
288
-
289
445
  ```tsx
446
+ // App.tsx
447
+
290
448
  const App = () => (
291
449
  <VocabProvider language="generatedLanguage">
292
- ...
450
+ <div>Hello, world!</div>
293
451
  </VocabProvider>
294
452
  );
295
453
  ```
@@ -301,8 +459,8 @@ const App = () => (
301
459
 
302
460
  The `@vocab/pseudo-localize` package exports low-level functions that can be used for pseudo-localization of translation messages.
303
461
 
304
- ```bash
305
- $ npm i --save-dev @vocab/pseudo-localize
462
+ ```sh
463
+ $ npm install --save-dev @vocab/pseudo-localize
306
464
  ```
307
465
 
308
466
  ```ts
@@ -332,21 +490,28 @@ const pseudoLocalizedMessage = pseudoLocalize(message);
332
490
  Pseudo-localization is a transformation that can be applied to a translation message.
333
491
  Vocab's implementation of this transformation contains the following elements:
334
492
 
335
- - _Start and end markers (`padString`):_ All strings are encapsulated in `[` and `]`. If a developer doesn’t see these characters they know the string has been clipped by an inflexible UI element.
493
+ - _Start and end markers (`padString`):_ All strings are encapsulated in `[` and `]`.
494
+
495
+ If a developer doesn’t see these characters they know the string has been clipped by an inflexible UI element.
496
+
336
497
  - _Transformation of ASCII characters to extended character equivalents (`substituteCharacters`):_ Stresses the UI from a vertical line-height perspective, tests font and encoding support, and weeds out strings that haven’t been externalized correctly (they will not have the pseudo-localization applied to them).
337
- - _Padding text (`extendVowels`):_ Simulates translation-induced expansion. Vocab's implementation of this involves repeating vowels (and `y`) to simulate a 40% expansion in the message's length.
338
498
 
339
- This Netflix technology [blog post][blog post] inspired Vocab's implementation of this
340
- functionality.
499
+ - _Padding text (`extendVowels`):_ Simulates translation-induced expansion.
500
+
501
+ Vocab's implementation of this involves repeating vowels (and `y`) to simulate a 40% expansion in the message's length.
502
+
503
+ This [Netflix technology blog post] inspired Vocab's implementation of this functionality.
504
+
505
+ [netflix technology blog post]: https://netflixtechblog.com/pseudo-localization-netflix-12fff76fbcbe
341
506
 
342
507
  ### Generating a pseudo-localized language using Vocab
343
508
 
344
509
  Vocab can generate a pseudo-localized language via the [`generatedLanguages` config][generated languages config], either via the webpack plugin or your `vocab.config.js` or `vocab.config.cjs` file.
345
510
  `@vocab/pseudo-localize` exports a `generator` that can be used directly in your config.
346
511
 
347
- **vocab.config.js**
348
-
349
512
  ```js
513
+ // vocab.config.js
514
+
350
515
  const { generator } = require('@vocab/pseudo-localize');
351
516
 
352
517
  module.exports = {
@@ -362,27 +527,35 @@ module.exports = {
362
527
  };
363
528
  ```
364
529
 
365
- [blog post]: https://netflixtechblog.com/pseudo-localization-netflix-12fff76fbcbe
366
530
  [generated languages config]: #generated-languages
367
531
 
368
- ## Use without React
532
+ ## Use Without React
369
533
 
370
- If you need to use Vocab outside of React, you can access the returned Vocab file directly. You'll then be responsible for when to load translations and how to update on translation load.
534
+ If you need to use Vocab outside of React, you can access the translations directly.
535
+ You'll then be responsible for when to load translations and how to update on translation load.
371
536
 
372
537
  #### Async access
373
538
 
374
- - `getMessages(language: string) => Promise<Messages>` returns messages for the given language formatted according to the correct locale. If the language has not been loaded it will load the language before resolving.
539
+ - `getMessages(language: string) => Promise<Messages>` returns messages for the given language formatted according to the correct locale.
540
+ If the language has not been loaded it will load the language before resolving.
541
+
542
+ > [!NOTE]
543
+ > To optimize loading time you may want to call [`load`] ahead of use.
375
544
 
376
- **Note:** To optimize loading time you may want to call `load` (see below) ahead of use.
545
+ [`load`]: #sync-access
377
546
 
378
547
  #### Sync access
379
548
 
380
- - `load(language: string) => Promise<void>` attempts to pre-load messages for the given language. Resolving once complete. Note this only ensures the language is available and does not return any translations.
381
- - `getLoadedMessages(language: string) => Messages | null` returns messages for the given language formatted according to the correct locale. If the language has not been loaded it will return `null`. Note that this will not load the language if it's not available. Useful when a synchronous (non-promise) return is required.
549
+ - `load(language: string) => Promise<void>` attempts to pre-load messages for the given language, resolving once loaded.
550
+ This function only ensures the language is available and does not return any translations.
551
+ - `getLoadedMessages(language: string) => Messages | null` returns messages for the given language formatted according to the correct locale.
552
+ If the language has not been loaded it will return `null`.
553
+ This will not load a language that is not available.
554
+ Useful when a synchronous (non-promise) return is required.
382
555
 
383
556
  **Example: Promise based formatting of messages**
384
557
 
385
- ```typescript
558
+ ```ts
386
559
  import translations from './.vocab';
387
560
 
388
561
  async function getFooMessage(language) {
@@ -395,7 +568,7 @@ getFooMessage().then((m) => console.log(m));
395
568
 
396
569
  **Example: Synchronously returning a message**
397
570
 
398
- ```typescript
571
+ ```ts
399
572
  import translations from './.vocab';
400
573
 
401
574
  function getFooMessageSync(language) {
@@ -421,14 +594,14 @@ Vocab generates custom `index.ts` files that give your React components strongly
421
594
 
422
595
  To generate these files run:
423
596
 
424
- ```bash
425
- $ vocab compile
597
+ ```sh
598
+ vocab compile
426
599
  ```
427
600
 
428
- Or to re-run the compiler when files change use:
601
+ Or to re-run the compiler when files change:
429
602
 
430
- ```bash
431
- $ vocab compile --watch
603
+ ```sh
604
+ vocab compile --watch
432
605
  ```
433
606
 
434
607
  ## External Translation Tooling
@@ -439,9 +612,9 @@ Vocab can be used to synchronize your translations with translations from a remo
439
612
  | -------- | ----------------------------------- |
440
613
  | [Phrase] | PHRASE_PROJECT_ID, PHRASE_API_TOKEN |
441
614
 
442
- ```bash
443
- $ vocab push --branch my-branch
444
- $ vocab pull --branch my-branch
615
+ ```sh
616
+ vocab push --branch my-branch
617
+ vocab pull --branch my-branch
445
618
  ```
446
619
 
447
620
  ### [Phrase] Platform Features
@@ -453,7 +626,7 @@ referenced in the upload. These keys can be deleted from Phrase by providing the
453
626
  `--delete-unused-keys` flag to `vocab push`. E.g.
454
627
 
455
628
  ```sh
456
- $ vocab push --branch my-branch --delete-unused-keys
629
+ vocab push --branch my-branch --delete-unused-keys
457
630
  ```
458
631
 
459
632
  [phrase]: https://developers.phrase.com/api/
@@ -466,6 +639,7 @@ Tags can be added to an individual key via the `tags` property:
466
639
 
467
640
  ```jsonc
468
641
  // translations.json
642
+
469
643
  {
470
644
  "Hello": {
471
645
  "message": "Hello",
@@ -483,6 +657,7 @@ keys specified in the file:
483
657
 
484
658
  ```jsonc
485
659
  // translations.json
660
+
486
661
  {
487
662
  "_meta": {
488
663
  "tags": ["home_page"]
@@ -500,11 +675,12 @@ keys specified in the file:
500
675
  In the above example, both the `Hello` and `Goodbye` keys would have the `home_page` tag attached to
501
676
  them, but only the `Hello` key would have the `usage_greeting` tag attached to it.
502
677
 
503
- **NOTE**: Only tags specified on keys in your [`devLanguage`][configuration] will be uploaded.
504
- Tags on keys in other languages will be ignored.
678
+ > [!NOTE]
679
+ > Only tags specified on keys in your [`devLanguage`][configuration] will be uploaded.
680
+ > Tags on keys in other languages will be ignored.
505
681
 
506
682
  [tags]: https://support.phrase.com/hc/en-us/articles/5822598372252-Tags-Strings-
507
- [configuration]: #Configuration
683
+ [configuration]: #configuration
508
684
 
509
685
  #### Global key
510
686
 
@@ -512,6 +688,7 @@ Tags on keys in other languages will be ignored.
512
688
 
513
689
  ```jsonc
514
690
  // translations.json
691
+
515
692
  {
516
693
  "Hello": {
517
694
  "message": "Hello",
@@ -542,9 +719,6 @@ vocab pull --error-on-no-global-key-translation
542
719
 
543
720
  ### Problem: Passed locale is being ignored or using en-US instead
544
721
 
545
- When running in Node.js the locale formatting is supported by [Node.js's Internationalization support](https://nodejs.org/api/intl.html#intl_internationalization_support). Node.js will silently switch to the closest locale it can find if the passed locale is not available.
722
+ When running in Node.js, the locale formatting is supported by [Node.js's Internationalization support](https://nodejs.org/api/intl.html#intl_internationalization_support).
723
+ Node.js will silently switch to the closest locale it can find if the passed locale is not available.
546
724
  See Node's documentation on [Options for building Node.js](https://nodejs.org/api/intl.html#intl_options_for_building_node_js) for information on ensuring Node has the locales you need.
547
-
548
- ### License
549
-
550
- MIT.
@@ -1,2 +1,2 @@
1
1
  export * from "./declarations/src/index";
2
- //# sourceMappingURL=vocab-phrase.cjs.d.ts.map
2
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidm9jYWItcGhyYXNlLmNqcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi9kZWNsYXJhdGlvbnMvc3JjL2luZGV4LmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEifQ==
@@ -7,7 +7,7 @@ var path = require('path');
7
7
  var core = require('@vocab/core');
8
8
  var FormData = require('form-data');
9
9
  var fetch = require('node-fetch');
10
- var chalk = require('chalk');
10
+ var pc = require('picocolors');
11
11
  var debug = require('debug');
12
12
  var sync = require('csv-stringify/sync');
13
13
 
@@ -16,7 +16,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e };
16
16
  var path__default = /*#__PURE__*/_interopDefault(path);
17
17
  var FormData__default = /*#__PURE__*/_interopDefault(FormData);
18
18
  var fetch__default = /*#__PURE__*/_interopDefault(fetch);
19
- var chalk__default = /*#__PURE__*/_interopDefault(chalk);
19
+ var pc__default = /*#__PURE__*/_interopDefault(pc);
20
20
  var debug__default = /*#__PURE__*/_interopDefault(debug);
21
21
 
22
22
  const mkdir = fs.promises.mkdir;
@@ -25,7 +25,7 @@ const writeFile = fs.promises.writeFile;
25
25
  const trace = debug__default["default"](`vocab:phrase`);
26
26
  const log = (...params) => {
27
27
  // eslint-disable-next-line no-console
28
- console.log(chalk__default["default"].yellow('Vocab'), ...params);
28
+ console.log(pc__default["default"].yellow('Vocab'), ...params);
29
29
  };
30
30
 
31
31
  function translationsToCsv(translations, devLanguage) {
@@ -7,7 +7,7 @@ var path = require('path');
7
7
  var core = require('@vocab/core');
8
8
  var FormData = require('form-data');
9
9
  var fetch = require('node-fetch');
10
- var chalk = require('chalk');
10
+ var pc = require('picocolors');
11
11
  var debug = require('debug');
12
12
  var sync = require('csv-stringify/sync');
13
13
 
@@ -16,7 +16,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e };
16
16
  var path__default = /*#__PURE__*/_interopDefault(path);
17
17
  var FormData__default = /*#__PURE__*/_interopDefault(FormData);
18
18
  var fetch__default = /*#__PURE__*/_interopDefault(fetch);
19
- var chalk__default = /*#__PURE__*/_interopDefault(chalk);
19
+ var pc__default = /*#__PURE__*/_interopDefault(pc);
20
20
  var debug__default = /*#__PURE__*/_interopDefault(debug);
21
21
 
22
22
  const mkdir = fs.promises.mkdir;
@@ -25,7 +25,7 @@ const writeFile = fs.promises.writeFile;
25
25
  const trace = debug__default["default"](`vocab:phrase`);
26
26
  const log = (...params) => {
27
27
  // eslint-disable-next-line no-console
28
- console.log(chalk__default["default"].yellow('Vocab'), ...params);
28
+ console.log(pc__default["default"].yellow('Vocab'), ...params);
29
29
  };
30
30
 
31
31
  function translationsToCsv(translations, devLanguage) {
@@ -3,7 +3,7 @@ import path from 'path';
3
3
  import { getAltLanguages, loadAllTranslations, getUniqueKey, getAltLanguageFilePath } from '@vocab/core';
4
4
  import FormData from 'form-data';
5
5
  import fetch from 'node-fetch';
6
- import chalk from 'chalk';
6
+ import pc from 'picocolors';
7
7
  import debug from 'debug';
8
8
  import { stringify } from 'csv-stringify/sync';
9
9
 
@@ -13,7 +13,7 @@ const writeFile = promises.writeFile;
13
13
  const trace = debug(`vocab:phrase`);
14
14
  const log = (...params) => {
15
15
  // eslint-disable-next-line no-console
16
- console.log(chalk.yellow('Vocab'), ...params);
16
+ console.log(pc.yellow('Vocab'), ...params);
17
17
  };
18
18
 
19
19
  function translationsToCsv(translations, devLanguage) {
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@vocab/phrase",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "main": "dist/vocab-phrase.cjs.js",
5
5
  "module": "dist/vocab-phrase.esm.js",
6
6
  "author": "SEEK",
7
7
  "license": "MIT",
8
8
  "dependencies": {
9
- "@vocab/core": "^1.6.0",
10
- "chalk": "^4.1.0",
9
+ "@vocab/core": "^1.6.2",
11
10
  "csv-stringify": "^6.2.3",
12
11
  "debug": "^4.3.1",
13
12
  "form-data": "^3.0.0",
14
- "node-fetch": "^2.6.1"
13
+ "node-fetch": "^2.6.1",
14
+ "picocolors": "^1.0.0"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@types/debug": "^4.1.5",
@@ -1 +0,0 @@
1
- {"version":3,"file":"vocab-phrase.cjs.d.ts","sourceRoot":"","sources":["./declarations/src/index.d.ts"],"names":[],"mappings":"AAAA"}