@vocab/react 1.1.3 → 1.1.5

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ ### MIT License
2
+
3
+ Copyright (c) 2020 SEEK
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -422,20 +422,81 @@ Or to re-run the compiler when files change use:
422
422
  $ vocab compile --watch
423
423
  ```
424
424
 
425
- ## External translation tooling
425
+ ## External Translation Tooling
426
426
 
427
427
  Vocab can be used to synchronize your translations with translations from a remote translation platform.
428
428
 
429
- | Platform | Environment Variables |
430
- | -------------------------------------------- | ----------------------------------- |
431
- | [Phrase](https://developers.phrase.com/api/) | PHRASE_PROJECT_ID, PHRASE_API_TOKEN |
429
+ | Platform | Environment Variables |
430
+ | -------- | ----------------------------------- |
431
+ | [Phrase] | PHRASE_PROJECT_ID, PHRASE_API_TOKEN |
432
432
 
433
433
  ```bash
434
434
  $ vocab push --branch my-branch
435
- $ vocab push --branch my-branch --delete-unused-keys
436
435
  $ vocab pull --branch my-branch
437
436
  ```
438
437
 
438
+ ### [Phrase] Platform Features
439
+
440
+ #### Delete Unused keys
441
+
442
+ When uploading translations, Phrase identifies keys that exist in the Phrase project, but were not
443
+ referenced in the upload. These keys can be deleted from Phrase by providing the
444
+ `---delete-unused-keys` flag to `vocab push`. E.g.
445
+
446
+ ```sh
447
+ $ vocab push --branch my-branch --delete-unused-keys
448
+ ```
449
+
450
+ [phrase]: https://developers.phrase.com/api/
451
+
452
+ #### [Tags]
453
+
454
+ `vocab push` supports uploading [tags] to Phrase.
455
+
456
+ Tags can be added to an individual key via the `tags` property:
457
+
458
+ ```jsonc
459
+ // translations.json
460
+ {
461
+ "Hello": {
462
+ "message": "Hello",
463
+ "tags": ["greeting", "home_page"]
464
+ },
465
+ "Goodbye": {
466
+ "message": "Goodbye",
467
+ "tags": ["home_page"]
468
+ }
469
+ }
470
+ ```
471
+
472
+ Tags can also be added under a top-level `_meta` field. This will result in the tags applying to all
473
+ keys specified in the file:
474
+
475
+ ```jsonc
476
+ // translations.json
477
+ {
478
+ "_meta": {
479
+ "tags": ["home_page"]
480
+ },
481
+ "Hello": {
482
+ "message": "Hello",
483
+ "tags": ["greeting"]
484
+ },
485
+ "Goodbye": {
486
+ "message": "Goodbye"
487
+ }
488
+ }
489
+ ```
490
+
491
+ In the above example, both the `Hello` and `Goodbye` keys would have the `home_page` tag attached to
492
+ them, but only the `Hello` key would have the `usage_greeting` tag attached to it.
493
+
494
+ **NOTE**: Only tags specified on keys in your [`devLanguage`][configuration] will be uploaded.
495
+ Tags on keys in other languages will be ignored.
496
+
497
+ [tags]: https://support.phrase.com/hc/en-us/articles/5822598372252-Tags-Strings-
498
+ [configuration]: #Configuration
499
+
439
500
  ## Troubleshooting
440
501
 
441
502
  ### Problem: Passed locale is being ignored or using en-US instead
@@ -1,25 +1,25 @@
1
- import { TranslationFile, LanguageName, ParsedFormatFnByKey, ParsedFormatFn } from '@vocab/types';
2
- import { ReactNode } from 'react';
3
- declare type Locale = string;
4
- interface TranslationsValue {
5
- language: LanguageName;
6
- locale?: Locale;
7
- }
8
- interface VocabProviderProps extends TranslationsValue {
9
- children: ReactNode;
10
- }
11
- export declare const VocabProvider: ({ children, language, locale, }: VocabProviderProps) => JSX.Element;
12
- export declare const useLanguage: () => TranslationsValue;
13
- declare type FormatXMLElementReactNodeFn = (parts: ReactNode[]) => ReactNode;
14
- declare type MapToReactNodeFunction<Params extends Record<string, any>> = {
15
- [key in keyof Params]: Params[key] extends ParsedFormatFn ? FormatXMLElementReactNodeFn : Params[key];
16
- };
17
- declare type TranslateFn<FormatFnByKey extends ParsedFormatFnByKey> = {
18
- <TranslationKey extends keyof FormatFnByKey>(key: TranslationKey, params: MapToReactNodeFunction<Parameters<FormatFnByKey[TranslationKey]>[0]>): ReturnType<FormatFnByKey[TranslationKey]> extends string ? string : ReactNode | string | Array<ReactNode | string>;
19
- <TranslationKey extends keyof FormatFnByKey>(key: Parameters<FormatFnByKey[TranslationKey]>[0] extends Record<string, any> ? never : TranslationKey): string;
20
- };
21
- export declare function useTranslations<Language extends string, FormatFnByKey extends ParsedFormatFnByKey>(translations: TranslationFile<Language, FormatFnByKey>): {
22
- ready: boolean;
23
- t: TranslateFn<FormatFnByKey>;
24
- };
25
- export {};
1
+ import type { TranslationFile, LanguageName, ParsedFormatFnByKey, ParsedFormatFn } from '@vocab/core';
2
+ import { ReactNode } from 'react';
3
+ type Locale = string;
4
+ interface TranslationsValue {
5
+ language: LanguageName;
6
+ locale?: Locale;
7
+ }
8
+ interface VocabProviderProps extends TranslationsValue {
9
+ children: ReactNode;
10
+ }
11
+ export declare const VocabProvider: ({ children, language, locale, }: VocabProviderProps) => JSX.Element;
12
+ export declare const useLanguage: () => TranslationsValue;
13
+ type FormatXMLElementReactNodeFn = (parts: ReactNode[]) => ReactNode;
14
+ type MapToReactNodeFunction<Params extends Record<string, any>> = {
15
+ [key in keyof Params]: Params[key] extends ParsedFormatFn ? FormatXMLElementReactNodeFn : Params[key];
16
+ };
17
+ type TranslateFn<FormatFnByKey extends ParsedFormatFnByKey> = {
18
+ <TranslationKey extends keyof FormatFnByKey>(key: TranslationKey, params: MapToReactNodeFunction<Parameters<FormatFnByKey[TranslationKey]>[0]>): ReturnType<FormatFnByKey[TranslationKey]> extends string ? string : ReactNode | string | Array<ReactNode | string>;
19
+ <TranslationKey extends keyof FormatFnByKey>(key: Parameters<FormatFnByKey[TranslationKey]>[0] extends Record<string, any> ? never : TranslationKey): string;
20
+ };
21
+ export declare function useTranslations<Language extends string, FormatFnByKey extends ParsedFormatFnByKey>(translations: TranslationFile<Language, FormatFnByKey>): {
22
+ ready: boolean;
23
+ t: TranslateFn<FormatFnByKey>;
24
+ };
25
+ export {};
@@ -8,7 +8,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e };
8
8
 
9
9
  var React__default = /*#__PURE__*/_interopDefault(React);
10
10
 
11
- const TranslationsContext = /*#__PURE__*/React__default['default'].createContext(undefined);
11
+ const TranslationsContext = /*#__PURE__*/React__default["default"].createContext(undefined);
12
12
  const VocabProvider = ({
13
13
  children,
14
14
  language,
@@ -18,21 +18,18 @@ const VocabProvider = ({
18
18
  language,
19
19
  locale
20
20
  }), [language, locale]);
21
- return /*#__PURE__*/React__default['default'].createElement(TranslationsContext.Provider, {
21
+ return /*#__PURE__*/React__default["default"].createElement(TranslationsContext.Provider, {
22
22
  value: value
23
23
  }, children);
24
24
  };
25
25
  const useLanguage = () => {
26
26
  const context = React.useContext(TranslationsContext);
27
-
28
27
  if (!context) {
29
28
  throw new Error('Attempted to access translation without Vocab context set. Did you forget to render VocabProvider?');
30
29
  }
31
-
32
30
  if (!context.language) {
33
31
  throw new Error('Attempted to access translation without language set. Did you forget to pass language to VocabProvider?');
34
32
  }
35
-
36
33
  return context;
37
34
  };
38
35
  const SERVER_RENDERING = typeof window === 'undefined';
@@ -44,37 +41,29 @@ function useTranslations(translations) {
44
41
  const [, forceRender] = React.useReducer(s => s + 1, 0);
45
42
  const translationsObject = translations.getLoadedMessages(language, locale || language);
46
43
  let ready = true;
47
-
48
44
  if (!translationsObject) {
49
45
  if (SERVER_RENDERING) {
50
46
  throw new Error(`Translations not synchronously available on server render. Applying translations dynamically server-side is not supported.`);
51
47
  }
52
-
53
48
  translations.load(language).then(() => {
54
49
  forceRender();
55
50
  });
56
51
  ready = false;
57
52
  }
58
-
59
53
  const t = React.useCallback((key, params) => {
60
54
  if (!translationsObject) {
61
55
  return ' ';
62
56
  }
63
-
64
57
  const message = translationsObject === null || translationsObject === void 0 ? void 0 : translationsObject[key];
65
-
66
58
  if (!message) {
67
59
  // eslint-disable-next-line no-console
68
60
  console.error(`Unable to find translation for key "${key}". Possible keys are ${Object.keys(translationsObject).map(v => `"${v}"`).join(', ')}`);
69
61
  return '';
70
62
  }
71
-
72
63
  const result = message.format(params);
73
-
74
64
  if (Array.isArray(result)) {
75
65
  for (let i = 0; i < result.length; i++) {
76
66
  const item = result[i];
77
-
78
67
  if (typeof item === 'object' && item && !item.key && /*#__PURE__*/React.isValidElement(item)) {
79
68
  result[i] = /*#__PURE__*/React.cloneElement(item, {
80
69
  key: `_vocab-${i}`
@@ -82,7 +71,6 @@ function useTranslations(translations) {
82
71
  }
83
72
  }
84
73
  }
85
-
86
74
  return result;
87
75
  }, [translationsObject]);
88
76
  return {
@@ -8,7 +8,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e };
8
8
 
9
9
  var React__default = /*#__PURE__*/_interopDefault(React);
10
10
 
11
- const TranslationsContext = /*#__PURE__*/React__default['default'].createContext(undefined);
11
+ const TranslationsContext = /*#__PURE__*/React__default["default"].createContext(undefined);
12
12
  const VocabProvider = ({
13
13
  children,
14
14
  language,
@@ -18,21 +18,18 @@ const VocabProvider = ({
18
18
  language,
19
19
  locale
20
20
  }), [language, locale]);
21
- return /*#__PURE__*/React__default['default'].createElement(TranslationsContext.Provider, {
21
+ return /*#__PURE__*/React__default["default"].createElement(TranslationsContext.Provider, {
22
22
  value: value
23
23
  }, children);
24
24
  };
25
25
  const useLanguage = () => {
26
26
  const context = React.useContext(TranslationsContext);
27
-
28
27
  if (!context) {
29
28
  throw new Error('Attempted to access translation without Vocab context set. Did you forget to render VocabProvider?');
30
29
  }
31
-
32
30
  if (!context.language) {
33
31
  throw new Error('Attempted to access translation without language set. Did you forget to pass language to VocabProvider?');
34
32
  }
35
-
36
33
  return context;
37
34
  };
38
35
  const SERVER_RENDERING = typeof window === 'undefined';
@@ -44,37 +41,29 @@ function useTranslations(translations) {
44
41
  const [, forceRender] = React.useReducer(s => s + 1, 0);
45
42
  const translationsObject = translations.getLoadedMessages(language, locale || language);
46
43
  let ready = true;
47
-
48
44
  if (!translationsObject) {
49
45
  if (SERVER_RENDERING) {
50
46
  throw new Error(`Translations not synchronously available on server render. Applying translations dynamically server-side is not supported.`);
51
47
  }
52
-
53
48
  translations.load(language).then(() => {
54
49
  forceRender();
55
50
  });
56
51
  ready = false;
57
52
  }
58
-
59
53
  const t = React.useCallback((key, params) => {
60
54
  if (!translationsObject) {
61
55
  return ' ';
62
56
  }
63
-
64
57
  const message = translationsObject === null || translationsObject === void 0 ? void 0 : translationsObject[key];
65
-
66
58
  if (!message) {
67
59
  // eslint-disable-next-line no-console
68
60
  console.error(`Unable to find translation for key "${key}". Possible keys are ${Object.keys(translationsObject).map(v => `"${v}"`).join(', ')}`);
69
61
  return '';
70
62
  }
71
-
72
63
  const result = message.format(params);
73
-
74
64
  if (Array.isArray(result)) {
75
65
  for (let i = 0; i < result.length; i++) {
76
66
  const item = result[i];
77
-
78
67
  if (typeof item === 'object' && item && !item.key && /*#__PURE__*/React.isValidElement(item)) {
79
68
  result[i] = /*#__PURE__*/React.cloneElement(item, {
80
69
  key: `_vocab-${i}`
@@ -82,7 +71,6 @@ function useTranslations(translations) {
82
71
  }
83
72
  }
84
73
  }
85
-
86
74
  return result;
87
75
  }, [translationsObject]);
88
76
  return {
@@ -16,15 +16,12 @@ const VocabProvider = ({
16
16
  };
17
17
  const useLanguage = () => {
18
18
  const context = useContext(TranslationsContext);
19
-
20
19
  if (!context) {
21
20
  throw new Error('Attempted to access translation without Vocab context set. Did you forget to render VocabProvider?');
22
21
  }
23
-
24
22
  if (!context.language) {
25
23
  throw new Error('Attempted to access translation without language set. Did you forget to pass language to VocabProvider?');
26
24
  }
27
-
28
25
  return context;
29
26
  };
30
27
  const SERVER_RENDERING = typeof window === 'undefined';
@@ -36,37 +33,29 @@ function useTranslations(translations) {
36
33
  const [, forceRender] = useReducer(s => s + 1, 0);
37
34
  const translationsObject = translations.getLoadedMessages(language, locale || language);
38
35
  let ready = true;
39
-
40
36
  if (!translationsObject) {
41
37
  if (SERVER_RENDERING) {
42
38
  throw new Error(`Translations not synchronously available on server render. Applying translations dynamically server-side is not supported.`);
43
39
  }
44
-
45
40
  translations.load(language).then(() => {
46
41
  forceRender();
47
42
  });
48
43
  ready = false;
49
44
  }
50
-
51
45
  const t = useCallback((key, params) => {
52
46
  if (!translationsObject) {
53
47
  return ' ';
54
48
  }
55
-
56
49
  const message = translationsObject === null || translationsObject === void 0 ? void 0 : translationsObject[key];
57
-
58
50
  if (!message) {
59
51
  // eslint-disable-next-line no-console
60
52
  console.error(`Unable to find translation for key "${key}". Possible keys are ${Object.keys(translationsObject).map(v => `"${v}"`).join(', ')}`);
61
53
  return '';
62
54
  }
63
-
64
55
  const result = message.format(params);
65
-
66
56
  if (Array.isArray(result)) {
67
57
  for (let i = 0; i < result.length; i++) {
68
58
  const item = result[i];
69
-
70
59
  if (typeof item === 'object' && item && !item.key && /*#__PURE__*/isValidElement(item)) {
71
60
  result[i] = /*#__PURE__*/cloneElement(item, {
72
61
  key: `_vocab-${i}`
@@ -74,7 +63,6 @@ function useTranslations(translations) {
74
63
  }
75
64
  }
76
65
  }
77
-
78
66
  return result;
79
67
  }, [translationsObject]);
80
68
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vocab/react",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "main": "dist/vocab-react.cjs.js",
5
5
  "module": "dist/vocab-react.esm.js",
6
6
  "author": "SEEK",
@@ -8,12 +8,15 @@
8
8
  "peerDependencies": {
9
9
  "react": ">=16.3.0"
10
10
  },
11
+ "files": [
12
+ "dist"
13
+ ],
11
14
  "dependencies": {
12
- "@vocab/types": "^1.1.1",
15
+ "@vocab/core": "^1.3.0",
13
16
  "intl-messageformat": "^10.0.0"
14
17
  },
15
18
  "devDependencies": {
16
19
  "@types/react": "^18.0.9",
17
20
  "react": "^18.1.0"
18
21
  }
19
- }
22
+ }
package/CHANGELOG.md DELETED
@@ -1,176 +0,0 @@
1
- # @vocab/react
2
-
3
- ## 1.1.3
4
-
5
- ### Patch Changes
6
-
7
- - [`e5a066c`](https://github.com/seek-oss/vocab/commit/e5a066c8a7539a62a9c1c4d813aa87461ba43cdc) [#96](https://github.com/seek-oss/vocab/pull/96) Thanks [@askoufis](https://github.com/askoufis)! - Update `intl-messageformat` dependencies
8
-
9
- - Updated dependencies [[`e5a066c`](https://github.com/seek-oss/vocab/commit/e5a066c8a7539a62a9c1c4d813aa87461ba43cdc)]:
10
- - @vocab/types@1.1.1
11
-
12
- ## 1.1.2
13
-
14
- ### Patch Changes
15
-
16
- - [`240d6ad`](https://github.com/seek-oss/vocab/commit/240d6ad7e0cf43fed92655a2f95fb463bd7b6644) [#85](https://github.com/seek-oss/vocab/pull/85) Thanks [@askoufis](https://github.com/askoufis)! - The `t` function returned from `useTranslations` is now memoized. `t` should now only change after the initial loading of translations, and when the language changes, making it more useful inside a hook's dependency array.
17
-
18
- ## 1.1.1
19
-
20
- ### Patch Changes
21
-
22
- - [`e9c7067`](https://github.com/seek-oss/vocab/commit/e9c7067b31215a176e70ac1e73f2c878107f328f) [#83](https://github.com/seek-oss/vocab/pull/83) Thanks [@michaeltaranto](https://github.com/michaeltaranto)! - Add React 18 support
23
-
24
- ## 1.1.0
25
-
26
- ### Minor Changes
27
-
28
- - [`6de02b3`](https://github.com/seek-oss/vocab/commit/6de02b35839e8ecdd9016fec49a95e17d3696f87) [#69](https://github.com/seek-oss/vocab/pull/69) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Automatically assign keys to React elements
29
-
30
- Previously, when using React elements within translation templates, React would warn about missing keys as the return type is an array. This meant you needed to supply a key manually. Vocab can now automatically assign a key to React elements. Keys that are passed explicitly will remain untouched.
31
-
32
- ## 1.0.2
33
-
34
- ### Patch Changes
35
-
36
- - [`3ec6dba`](https://github.com/seek-oss/vocab/commit/3ec6dbaad590299cc33e2d9d4a877576eb05853a) [#63](https://github.com/seek-oss/vocab/pull/63) Thanks [@jahredhope](https://github.com/jahredhope)! - Migrate to new @formatjs/icu-messageformat-parser as intl-messageformat-parser has been deprecated
37
-
38
- - Updated dependencies [[`3ec6dba`](https://github.com/seek-oss/vocab/commit/3ec6dbaad590299cc33e2d9d4a877576eb05853a)]:
39
- - @vocab/types@1.0.1
40
-
41
- ## 1.0.1
42
-
43
- ### Patch Changes
44
-
45
- - [`c9a38dd`](https://github.com/seek-oss/vocab/commit/c9a38dd15e2c2a47fc4d5eb2348fdd08a6982768) [#54](https://github.com/seek-oss/vocab/pull/54) Thanks [@jahredhope](https://github.com/jahredhope)! - Allow special characters within translation keys and messages
46
-
47
- * [`c9a38dd`](https://github.com/seek-oss/vocab/commit/c9a38dd15e2c2a47fc4d5eb2348fdd08a6982768) [#54](https://github.com/seek-oss/vocab/pull/54) Thanks [@jahredhope](https://github.com/jahredhope)! - Add a warning when accessing a key that doesn't exist
48
-
49
- ## 1.0.0
50
-
51
- ### Major Changes
52
-
53
- - [`3031054`](https://github.com/seek-oss/vocab/commit/303105440851db6126f0606e1607745b27dd981c) [#51](https://github.com/seek-oss/vocab/pull/51) Thanks [@jahredhope](https://github.com/jahredhope)! - Release v1.0.0
54
-
55
- Release Vocab as v1.0.0 to signify a stable API and support future [semver versioning](https://semver.org/) releases.
56
-
57
- Vocab has seen a lot of iteration and changes since it was first published on 20 November 2020. We are now confident with the API and believe Vocab is ready for common use.
58
-
59
- ### Patch Changes
60
-
61
- - [`0074382`](https://github.com/seek-oss/vocab/commit/007438273ef70f5d5ded45777933651ad8df36f6) [#52](https://github.com/seek-oss/vocab/pull/52) Thanks [@jahredhope](https://github.com/jahredhope)! - Remove React dependency on core types.
62
-
63
- Direct use of tags in Translations now have stricter type definitions.
64
-
65
- - Updated dependencies [[`0074382`](https://github.com/seek-oss/vocab/commit/007438273ef70f5d5ded45777933651ad8df36f6), [`3031054`](https://github.com/seek-oss/vocab/commit/303105440851db6126f0606e1607745b27dd981c)]:
66
- - @vocab/types@1.0.0
67
-
68
- ## 0.0.12
69
-
70
- ### Patch Changes
71
-
72
- - [`5b1fdc0`](https://github.com/seek-oss/vocab/commit/5b1fdc019522b12e7ef94b2fec57b54a9310d41c) [#46](https://github.com/seek-oss/vocab/pull/46) Thanks [@jahredhope](https://github.com/jahredhope)! - Enable the use of translation files directly with 3 new documented methods for working with translations.
73
-
74
- ```typescript
75
- /**
76
- * Retrieve messages. If not available, will attempt to load messages and resolve once complete.
77
- */
78
- translations.getMessages(language);
79
- /**
80
- * Retrieve already loaded messages. Will return null if messages haven't been loaded.
81
- */
82
- translations.getLoadedMessages(language);
83
- /**
84
- * Load messages for the given language. Resolving once complete.
85
- */
86
- translations.load(language);
87
- ```
88
-
89
- - Updated dependencies [[`5b1fdc0`](https://github.com/seek-oss/vocab/commit/5b1fdc019522b12e7ef94b2fec57b54a9310d41c)]:
90
- - @vocab/types@0.0.9
91
-
92
- ## 0.0.11
93
-
94
- ### Patch Changes
95
-
96
- - [`f2fca67`](https://github.com/seek-oss/vocab/commit/f2fca679c66ae65405a0aa24f0a0e472026aad0d) [#36](https://github.com/seek-oss/vocab/pull/36) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Support custom locales for ICU message parsing
97
-
98
- * [`6c725f4`](https://github.com/seek-oss/vocab/commit/6c725f43c5eaed9b248c8452ff6f83cef1b2f61c) [#35](https://github.com/seek-oss/vocab/pull/35) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Rename `useTranslation` to `useTranslations`
99
-
100
- * Updated dependencies [[`f2fca67`](https://github.com/seek-oss/vocab/commit/f2fca679c66ae65405a0aa24f0a0e472026aad0d)]:
101
- - @vocab/types@0.0.8
102
-
103
- ## 0.0.10
104
-
105
- ### Patch Changes
106
-
107
- - Updated dependencies [[`283bcad`](https://github.com/seek-oss/vocab/commit/283bcada06e622ab14ed891743ed3f55cf09e245), [`f3992ef`](https://github.com/seek-oss/vocab/commit/f3992efbf08939ebf853fac650a49cc46dc51dfb)]:
108
- - @vocab/types@0.0.7
109
-
110
- ## 0.0.9
111
-
112
- ### Patch Changes
113
-
114
- - Updated dependencies [[`80a46c0`](https://github.com/seek-oss/vocab/commit/80a46c01a55408675f5822c3618519f80136c3ab)]:
115
- - @vocab/types@0.0.6
116
-
117
- ## 0.0.8
118
-
119
- ### Patch Changes
120
-
121
- - [`b51db12`](https://github.com/seek-oss/vocab/commit/b51db125b6d5e29feb77eac20a45b410e79be9b2) [#21](https://github.com/seek-oss/vocab/pull/21) Thanks [@jahredhope](https://github.com/jahredhope)! - Rename TranslationsProvider to VocabProvider
122
-
123
- ## 0.0.7
124
-
125
- ### Patch Changes
126
-
127
- - [`5f5c581`](https://github.com/seek-oss/vocab/commit/5f5c581a65bff28729ee19e1ec0bdea488a9d6c2) [#19](https://github.com/seek-oss/vocab/pull/19) Thanks [@jahredhope](https://github.com/jahredhope)! - Compile useable TypeScript importable files with `vocab compile`.
128
-
129
- The new `vocab compile` step replaces `vocab generate-types` in creating a fully functional **translations.ts** file.
130
-
131
- This allows vocab to be used **without the Webpack Plugin**, however use of the plugin is still heavily advised to ensure optimal loading of translation content on the web.
132
-
133
- Support for unit testing is now better than ever! The newly created **translations.ts** means your unit test code will see the same code as available while rendering.
134
-
135
- See the [documentation](https://github.com/seek-oss/vocab) for further usage details.
136
-
137
- - Updated dependencies [[`5f5c581`](https://github.com/seek-oss/vocab/commit/5f5c581a65bff28729ee19e1ec0bdea488a9d6c2)]:
138
- - @vocab/types@0.0.5
139
-
140
- ## 0.0.6
141
-
142
- ### Patch Changes
143
-
144
- - [`26b52f4`](https://github.com/seek-oss/vocab/commit/26b52f4878ded440841e08c858bdc9e685500c2a) [#16](https://github.com/seek-oss/vocab/pull/16) Thanks [@jahredhope](https://github.com/jahredhope)! - Enable debugging with DEBUG environment variable
145
-
146
- - Updated dependencies [[`08de30d`](https://github.com/seek-oss/vocab/commit/08de30d338c2a5ebdcf14da7c736dddf22e7ca9e)]:
147
- - @vocab/types@0.0.4
148
-
149
- ## 0.0.5
150
-
151
- ### Patch Changes
152
-
153
- - [`4710f34`](https://github.com/seek-oss/vocab/commit/4710f341f2827643e3eff69ef7e26d44ec6e8a2b) [#8](https://github.com/seek-oss/vocab/pull/8) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Infer `t` return type more intelligently
154
-
155
- The translate key function (`t`) will now infer the return type as ReactNode only when the tag syntax is used.
156
-
157
- - Updated dependencies [[`4710f34`](https://github.com/seek-oss/vocab/commit/4710f341f2827643e3eff69ef7e26d44ec6e8a2b)]:
158
- - @vocab/types@0.0.3
159
-
160
- ## 0.0.4
161
-
162
- ### Patch Changes
163
-
164
- - [`45c4fe2`](https://github.com/seek-oss/vocab/commit/45c4fe273c5157475cb03ca57db662956ad5cbc9) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Improved type definitions for `t` function
165
-
166
- ## 0.0.3
167
-
168
- ### Patch Changes
169
-
170
- - [`f79c85e`](https://github.com/seek-oss/vocab/commit/f79c85e37c5b927306866961cf6cb3c541d0d6cf) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Add @vocab/types dep
171
-
172
- ## 0.0.2
173
-
174
- ### Patch Changes
175
-
176
- - [`9f99ea7`](https://github.com/seek-oss/vocab/commit/9f99ea7c827ec4d7c21a485e17e3adbbd1c49319) Thanks [@jahredhope](https://github.com/jahredhope)! - Remove React as dependency and target node
package/src/index.tsx DELETED
@@ -1,167 +0,0 @@
1
- import {
2
- TranslationFile,
3
- LanguageName,
4
- ParsedFormatFnByKey,
5
- ParsedFormatFn,
6
- } from '@vocab/types';
7
- import React, {
8
- ReactNode,
9
- useContext,
10
- useMemo,
11
- useReducer,
12
- isValidElement,
13
- cloneElement,
14
- useCallback,
15
- } from 'react';
16
-
17
- type Locale = string;
18
-
19
- interface TranslationsValue {
20
- language: LanguageName;
21
- locale?: Locale;
22
- }
23
-
24
- const TranslationsContext = React.createContext<TranslationsValue | undefined>(
25
- undefined,
26
- );
27
-
28
- interface VocabProviderProps extends TranslationsValue {
29
- children: ReactNode;
30
- }
31
- export const VocabProvider = ({
32
- children,
33
- language,
34
- locale,
35
- }: VocabProviderProps) => {
36
- const value = useMemo(() => ({ language, locale }), [language, locale]);
37
-
38
- return (
39
- <TranslationsContext.Provider value={value}>
40
- {children}
41
- </TranslationsContext.Provider>
42
- );
43
- };
44
-
45
- export const useLanguage = (): TranslationsValue => {
46
- const context = useContext(TranslationsContext);
47
- if (!context) {
48
- throw new Error(
49
- 'Attempted to access translation without Vocab context set. Did you forget to render VocabProvider?',
50
- );
51
- }
52
- if (!context.language) {
53
- throw new Error(
54
- 'Attempted to access translation without language set. Did you forget to pass language to VocabProvider?',
55
- );
56
- }
57
-
58
- return context;
59
- };
60
-
61
- const SERVER_RENDERING = typeof window === 'undefined';
62
-
63
- type FormatXMLElementReactNodeFn = (parts: ReactNode[]) => ReactNode;
64
-
65
- type MapToReactNodeFunction<Params extends Record<string, any>> = {
66
- [key in keyof Params]: Params[key] extends ParsedFormatFn
67
- ? FormatXMLElementReactNodeFn
68
- : Params[key];
69
- };
70
-
71
- type TranslateFn<FormatFnByKey extends ParsedFormatFnByKey> = {
72
- <TranslationKey extends keyof FormatFnByKey>(
73
- key: TranslationKey,
74
- params: MapToReactNodeFunction<
75
- Parameters<FormatFnByKey[TranslationKey]>[0]
76
- >,
77
- ): ReturnType<FormatFnByKey[TranslationKey]> extends string
78
- ? string
79
- : ReactNode | string | Array<ReactNode | string>;
80
- <TranslationKey extends keyof FormatFnByKey>(
81
- key: Parameters<FormatFnByKey[TranslationKey]>[0] extends Record<
82
- string,
83
- any
84
- >
85
- ? never
86
- : TranslationKey,
87
- ): string;
88
- };
89
-
90
- export function useTranslations<
91
- Language extends string,
92
- FormatFnByKey extends ParsedFormatFnByKey,
93
- >(
94
- translations: TranslationFile<Language, FormatFnByKey>,
95
- ): {
96
- ready: boolean;
97
- t: TranslateFn<FormatFnByKey>;
98
- } {
99
- const { language, locale } = useLanguage();
100
- const [, forceRender] = useReducer((s: number) => s + 1, 0);
101
-
102
- const translationsObject = translations.getLoadedMessages(
103
- language as any,
104
- locale || language,
105
- );
106
-
107
- let ready = true;
108
-
109
- if (!translationsObject) {
110
- if (SERVER_RENDERING) {
111
- throw new Error(
112
- `Translations not synchronously available on server render. Applying translations dynamically server-side is not supported.`,
113
- );
114
- }
115
-
116
- translations.load(language as any).then(() => {
117
- forceRender();
118
- });
119
- ready = false;
120
- }
121
-
122
- const t = useCallback(
123
- (key: string, params?: any) => {
124
- if (!translationsObject) {
125
- return ' ';
126
- }
127
-
128
- const message = translationsObject?.[key];
129
-
130
- if (!message) {
131
- // eslint-disable-next-line no-console
132
- console.error(
133
- `Unable to find translation for key "${key}". Possible keys are ${Object.keys(
134
- translationsObject,
135
- )
136
- .map((v) => `"${v}"`)
137
- .join(', ')}`,
138
- );
139
- return '';
140
- }
141
-
142
- const result = message.format(params);
143
-
144
- if (Array.isArray(result)) {
145
- for (let i = 0; i < result.length; i++) {
146
- const item = result[i];
147
- if (
148
- typeof item === 'object' &&
149
- item &&
150
- !item.key &&
151
- isValidElement(item)
152
- ) {
153
- result[i] = cloneElement(item, { key: `_vocab-${i}` });
154
- }
155
- }
156
- }
157
-
158
- return result;
159
- },
160
- [translationsObject],
161
- );
162
-
163
- return {
164
- ready,
165
- t,
166
- };
167
- }