@vocab/react 0.0.0-tags-support-2023185232 → 0.0.0-tsdown-20250922064402
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 +21 -0
- package/dist/index.d.mts +73 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +92 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +66 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +21 -8
- package/dist/declarations/src/index.d.ts +0 -25
- package/dist/vocab-react.cjs.d.ts +0 -1
- package/dist/vocab-react.cjs.dev.js +0 -96
- package/dist/vocab-react.cjs.js +0 -7
- package/dist/vocab-react.cjs.prod.js +0 -96
- package/dist/vocab-react.esm.js +0 -86
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/dist/index.d.mts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React, { ReactNode } from "react";
|
|
2
|
+
import { LanguageName, ParsedFormatFn, ParsedFormatFnByKey, TranslationFile } from "@vocab/core";
|
|
3
|
+
|
|
4
|
+
//#region src/components.d.ts
|
|
5
|
+
type Locale = string;
|
|
6
|
+
interface TranslationsContextValue {
|
|
7
|
+
/**
|
|
8
|
+
* The `language` passed in to your `VocabProvider`
|
|
9
|
+
*/
|
|
10
|
+
language: LanguageName;
|
|
11
|
+
/**
|
|
12
|
+
* The `locale` passed in to your `VocabProvider`
|
|
13
|
+
*
|
|
14
|
+
* Please note that this value will be `undefined` if you have not passed a `locale` to your `VocabProvider`.
|
|
15
|
+
* If your languages are named with IETF language tags, you should just use `language` instead of
|
|
16
|
+
* this value, unless you specifically need to access your `locale` override.
|
|
17
|
+
*/
|
|
18
|
+
locale?: Locale;
|
|
19
|
+
}
|
|
20
|
+
interface VocabProviderProps {
|
|
21
|
+
/**
|
|
22
|
+
* The language to load translations for. Must be one of the language names defined in your `vocab.config.js`.
|
|
23
|
+
*/
|
|
24
|
+
language: TranslationsContextValue['language'];
|
|
25
|
+
/**
|
|
26
|
+
* A locale override. By default, Vocab will use the `language` as the locale when formatting messages if
|
|
27
|
+
* `locale` is not set. If your languages are named with IETF language tags, you probably don't need to
|
|
28
|
+
* set this value.
|
|
29
|
+
*
|
|
30
|
+
* You may want to override the locale for a specific language if the default formatting for that locale
|
|
31
|
+
* is not desired.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Override the locale for th-TH to use the Gregorian calendar instead of the default Buddhist calendar
|
|
35
|
+
* <VocabProvider language="th-TH" locale="th-TH-u-ca-gregory">
|
|
36
|
+
* </App>
|
|
37
|
+
* <VocabProvider />
|
|
38
|
+
*/
|
|
39
|
+
locale?: TranslationsContextValue['locale'];
|
|
40
|
+
children: ReactNode;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Provides a translation context for your application
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* import { VocabProvider } from '@vocab/react';
|
|
47
|
+
*
|
|
48
|
+
* <VocabProvider language="en">
|
|
49
|
+
* <App />
|
|
50
|
+
* <VocabProvider />
|
|
51
|
+
*/
|
|
52
|
+
declare const VocabProvider: ({
|
|
53
|
+
children,
|
|
54
|
+
language,
|
|
55
|
+
locale
|
|
56
|
+
}: VocabProviderProps) => React.JSX.Element;
|
|
57
|
+
/**
|
|
58
|
+
* @returns The `language` and `locale` values passed in to your `VocabProvider`
|
|
59
|
+
*/
|
|
60
|
+
declare const useLanguage: () => TranslationsContextValue;
|
|
61
|
+
type FormatXMLElementReactNodeFn = (parts: ReactNode[]) => ReactNode;
|
|
62
|
+
type MapToReactNodeFunction<Params extends Record<string, any>> = { [key in keyof Params]: Params[key] extends ParsedFormatFn ? FormatXMLElementReactNodeFn : Params[key] };
|
|
63
|
+
type TranslateFn<FormatFnByKey extends ParsedFormatFnByKey> = {
|
|
64
|
+
<TranslationKey extends keyof FormatFnByKey>(key: TranslationKey, params: MapToReactNodeFunction<Parameters<FormatFnByKey[TranslationKey]>[0]>): ReturnType<FormatFnByKey[TranslationKey]> extends string ? string : ReactNode | string | Array<ReactNode | string>;
|
|
65
|
+
<TranslationKey extends keyof FormatFnByKey>(key: Parameters<FormatFnByKey[TranslationKey]>[0] extends Record<string, any> ? never : TranslationKey): string;
|
|
66
|
+
};
|
|
67
|
+
declare function useTranslations<Language extends string, FormatFnByKey extends ParsedFormatFnByKey>(translations: TranslationFile<Language, FormatFnByKey>): {
|
|
68
|
+
ready: boolean;
|
|
69
|
+
t: TranslateFn<FormatFnByKey>;
|
|
70
|
+
};
|
|
71
|
+
//#endregion
|
|
72
|
+
export { VocabProvider, useLanguage, useTranslations };
|
|
73
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { LanguageName, ParsedFormatFn, ParsedFormatFnByKey, TranslationFile } from "@vocab/core";
|
|
2
|
+
import React, { ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/components.d.ts
|
|
5
|
+
type Locale = string;
|
|
6
|
+
interface TranslationsContextValue {
|
|
7
|
+
/**
|
|
8
|
+
* The `language` passed in to your `VocabProvider`
|
|
9
|
+
*/
|
|
10
|
+
language: LanguageName;
|
|
11
|
+
/**
|
|
12
|
+
* The `locale` passed in to your `VocabProvider`
|
|
13
|
+
*
|
|
14
|
+
* Please note that this value will be `undefined` if you have not passed a `locale` to your `VocabProvider`.
|
|
15
|
+
* If your languages are named with IETF language tags, you should just use `language` instead of
|
|
16
|
+
* this value, unless you specifically need to access your `locale` override.
|
|
17
|
+
*/
|
|
18
|
+
locale?: Locale;
|
|
19
|
+
}
|
|
20
|
+
interface VocabProviderProps {
|
|
21
|
+
/**
|
|
22
|
+
* The language to load translations for. Must be one of the language names defined in your `vocab.config.js`.
|
|
23
|
+
*/
|
|
24
|
+
language: TranslationsContextValue['language'];
|
|
25
|
+
/**
|
|
26
|
+
* A locale override. By default, Vocab will use the `language` as the locale when formatting messages if
|
|
27
|
+
* `locale` is not set. If your languages are named with IETF language tags, you probably don't need to
|
|
28
|
+
* set this value.
|
|
29
|
+
*
|
|
30
|
+
* You may want to override the locale for a specific language if the default formatting for that locale
|
|
31
|
+
* is not desired.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Override the locale for th-TH to use the Gregorian calendar instead of the default Buddhist calendar
|
|
35
|
+
* <VocabProvider language="th-TH" locale="th-TH-u-ca-gregory">
|
|
36
|
+
* </App>
|
|
37
|
+
* <VocabProvider />
|
|
38
|
+
*/
|
|
39
|
+
locale?: TranslationsContextValue['locale'];
|
|
40
|
+
children: ReactNode;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Provides a translation context for your application
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* import { VocabProvider } from '@vocab/react';
|
|
47
|
+
*
|
|
48
|
+
* <VocabProvider language="en">
|
|
49
|
+
* <App />
|
|
50
|
+
* <VocabProvider />
|
|
51
|
+
*/
|
|
52
|
+
declare const VocabProvider: ({
|
|
53
|
+
children,
|
|
54
|
+
language,
|
|
55
|
+
locale
|
|
56
|
+
}: VocabProviderProps) => React.JSX.Element;
|
|
57
|
+
/**
|
|
58
|
+
* @returns The `language` and `locale` values passed in to your `VocabProvider`
|
|
59
|
+
*/
|
|
60
|
+
declare const useLanguage: () => TranslationsContextValue;
|
|
61
|
+
type FormatXMLElementReactNodeFn = (parts: ReactNode[]) => ReactNode;
|
|
62
|
+
type MapToReactNodeFunction<Params extends Record<string, any>> = { [key in keyof Params]: Params[key] extends ParsedFormatFn ? FormatXMLElementReactNodeFn : Params[key] };
|
|
63
|
+
type TranslateFn<FormatFnByKey extends ParsedFormatFnByKey> = {
|
|
64
|
+
<TranslationKey extends keyof FormatFnByKey>(key: TranslationKey, params: MapToReactNodeFunction<Parameters<FormatFnByKey[TranslationKey]>[0]>): ReturnType<FormatFnByKey[TranslationKey]> extends string ? string : ReactNode | string | Array<ReactNode | string>;
|
|
65
|
+
<TranslationKey extends keyof FormatFnByKey>(key: Parameters<FormatFnByKey[TranslationKey]>[0] extends Record<string, any> ? never : TranslationKey): string;
|
|
66
|
+
};
|
|
67
|
+
declare function useTranslations<Language extends string, FormatFnByKey extends ParsedFormatFnByKey>(translations: TranslationFile<Language, FormatFnByKey>): {
|
|
68
|
+
ready: boolean;
|
|
69
|
+
t: TranslateFn<FormatFnByKey>;
|
|
70
|
+
};
|
|
71
|
+
//#endregion
|
|
72
|
+
export { VocabProvider, useLanguage, useTranslations };
|
|
73
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
let react = require("react");
|
|
25
|
+
react = __toESM(react);
|
|
26
|
+
|
|
27
|
+
//#region src/components.tsx
|
|
28
|
+
const TranslationsContext = react.default.createContext(void 0);
|
|
29
|
+
/**
|
|
30
|
+
* Provides a translation context for your application
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* import { VocabProvider } from '@vocab/react';
|
|
34
|
+
*
|
|
35
|
+
* <VocabProvider language="en">
|
|
36
|
+
* <App />
|
|
37
|
+
* <VocabProvider />
|
|
38
|
+
*/
|
|
39
|
+
const VocabProvider = ({ children, language, locale }) => {
|
|
40
|
+
const value = (0, react.useMemo)(() => ({
|
|
41
|
+
language,
|
|
42
|
+
locale
|
|
43
|
+
}), [language, locale]);
|
|
44
|
+
return /* @__PURE__ */ react.default.createElement(TranslationsContext.Provider, { value }, children);
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* @returns The `language` and `locale` values passed in to your `VocabProvider`
|
|
48
|
+
*/
|
|
49
|
+
const useLanguage = () => {
|
|
50
|
+
const context = (0, react.useContext)(TranslationsContext);
|
|
51
|
+
if (!context) throw new Error("Attempted to access translation without Vocab context set. Did you forget to render VocabProvider?");
|
|
52
|
+
if (!context.language) throw new Error("Attempted to access translation without language set. Did you forget to pass language to VocabProvider?");
|
|
53
|
+
return context;
|
|
54
|
+
};
|
|
55
|
+
const SERVER_RENDERING = typeof window === "undefined";
|
|
56
|
+
function useTranslations(translations) {
|
|
57
|
+
const { language, locale } = useLanguage();
|
|
58
|
+
const [, forceRender] = (0, react.useReducer)((s) => s + 1, 0);
|
|
59
|
+
const translationsObject = translations.getLoadedMessages(language, locale || language);
|
|
60
|
+
let ready = true;
|
|
61
|
+
if (!translationsObject) {
|
|
62
|
+
if (SERVER_RENDERING) throw new Error(`Translations not synchronously available on server render. Applying translations dynamically server-side is not supported.`);
|
|
63
|
+
translations.load(language).then(() => {
|
|
64
|
+
forceRender();
|
|
65
|
+
});
|
|
66
|
+
ready = false;
|
|
67
|
+
}
|
|
68
|
+
const t = (0, react.useCallback)((key, params) => {
|
|
69
|
+
if (!translationsObject) return " ";
|
|
70
|
+
const message = translationsObject?.[key];
|
|
71
|
+
if (!message) {
|
|
72
|
+
console.error(`Unable to find translation for key "${key}". Possible keys are ${Object.keys(translationsObject).map((v) => `"${v}"`).join(", ")}`);
|
|
73
|
+
return "";
|
|
74
|
+
}
|
|
75
|
+
const result = message.format(params);
|
|
76
|
+
if (Array.isArray(result)) for (let i = 0; i < result.length; i++) {
|
|
77
|
+
const item = result[i];
|
|
78
|
+
if (typeof item === "object" && item && !item.key && (0, react.isValidElement)(item)) result[i] = (0, react.cloneElement)(item, { key: `_vocab-${i}` });
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}, [translationsObject]);
|
|
82
|
+
return {
|
|
83
|
+
ready,
|
|
84
|
+
t
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//#endregion
|
|
89
|
+
exports.VocabProvider = VocabProvider;
|
|
90
|
+
exports.useLanguage = useLanguage;
|
|
91
|
+
exports.useTranslations = useTranslations;
|
|
92
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["React"],"sources":["../src/components.tsx"],"sourcesContent":["import type {\n TranslationFile,\n LanguageName,\n ParsedFormatFnByKey,\n ParsedFormatFn,\n} from '@vocab/core';\n\nimport React, {\n type ReactNode,\n useContext,\n useMemo,\n useReducer,\n isValidElement,\n cloneElement,\n useCallback,\n} from 'react';\n\ntype Locale = string;\n\ninterface TranslationsContextValue {\n /**\n * The `language` passed in to your `VocabProvider`\n */\n language: LanguageName;\n /**\n * The `locale` passed in to your `VocabProvider`\n *\n * Please note that this value will be `undefined` if you have not passed a `locale` to your `VocabProvider`.\n * If your languages are named with IETF language tags, you should just use `language` instead of\n * this value, unless you specifically need to access your `locale` override.\n */\n locale?: Locale;\n}\n\nconst TranslationsContext = React.createContext<\n TranslationsContextValue | undefined\n>(undefined);\n\n// Not extending TranslationsContextValue so we can tailor the docs for each prop to be better\n// suited to the provider, rather than for the useLanguage hook\ninterface VocabProviderProps {\n /**\n * The language to load translations for. Must be one of the language names defined in your `vocab.config.js`.\n */\n language: TranslationsContextValue['language'];\n /**\n * A locale override. By default, Vocab will use the `language` as the locale when formatting messages if\n * `locale` is not set. If your languages are named with IETF language tags, you probably don't need to\n * set this value.\n *\n * You may want to override the locale for a specific language if the default formatting for that locale\n * is not desired.\n *\n * @example\n * // Override the locale for th-TH to use the Gregorian calendar instead of the default Buddhist calendar\n * <VocabProvider language=\"th-TH\" locale=\"th-TH-u-ca-gregory\">\n * </App>\n * <VocabProvider />\n */\n locale?: TranslationsContextValue['locale'];\n children: ReactNode;\n}\n\n/**\n * Provides a translation context for your application\n *\n * @example\n * import { VocabProvider } from '@vocab/react';\n *\n * <VocabProvider language=\"en\">\n * <App />\n * <VocabProvider />\n */\nexport const VocabProvider = ({\n children,\n language,\n locale,\n}: VocabProviderProps) => {\n const value = useMemo(() => ({ language, locale }), [language, locale]);\n\n return (\n <TranslationsContext.Provider value={value}>\n {children}\n </TranslationsContext.Provider>\n );\n};\n\n/**\n * @returns The `language` and `locale` values passed in to your `VocabProvider`\n */\nexport const useLanguage = (): TranslationsContextValue => {\n const context = useContext(TranslationsContext);\n if (!context) {\n throw new Error(\n 'Attempted to access translation without Vocab context set. Did you forget to render VocabProvider?',\n );\n }\n if (!context.language) {\n throw new Error(\n 'Attempted to access translation without language set. Did you forget to pass language to VocabProvider?',\n );\n }\n\n return context;\n};\n\nconst SERVER_RENDERING = typeof window === 'undefined';\n\ntype FormatXMLElementReactNodeFn = (parts: ReactNode[]) => ReactNode;\n\ntype MapToReactNodeFunction<Params extends Record<string, any>> = {\n [key in keyof Params]: Params[key] extends ParsedFormatFn\n ? FormatXMLElementReactNodeFn\n : Params[key];\n};\n\ntype TranslateFn<FormatFnByKey extends ParsedFormatFnByKey> = {\n <TranslationKey extends keyof FormatFnByKey>(\n key: TranslationKey,\n params: MapToReactNodeFunction<\n Parameters<FormatFnByKey[TranslationKey]>[0]\n >,\n ): ReturnType<FormatFnByKey[TranslationKey]> extends string\n ? string\n : ReactNode | string | Array<ReactNode | string>;\n <TranslationKey extends keyof FormatFnByKey>(\n key: Parameters<FormatFnByKey[TranslationKey]>[0] extends Record<\n string,\n any\n >\n ? never\n : TranslationKey,\n ): string;\n};\n\nexport function useTranslations<\n Language extends string,\n FormatFnByKey extends ParsedFormatFnByKey,\n>(\n translations: TranslationFile<Language, FormatFnByKey>,\n): {\n ready: boolean;\n t: TranslateFn<FormatFnByKey>;\n} {\n const { language, locale } = useLanguage();\n const [, forceRender] = useReducer((s: number) => s + 1, 0);\n\n const translationsObject = translations.getLoadedMessages(\n language as any,\n locale || language,\n );\n\n let ready = true;\n\n if (!translationsObject) {\n if (SERVER_RENDERING) {\n throw new Error(\n `Translations not synchronously available on server render. Applying translations dynamically server-side is not supported.`,\n );\n }\n\n translations.load(language as any).then(() => {\n forceRender();\n });\n ready = false;\n }\n\n const t = useCallback(\n (key: string, params?: any) => {\n if (!translationsObject) {\n return ' ';\n }\n\n const message = translationsObject?.[key];\n\n if (!message) {\n // eslint-disable-next-line no-console\n console.error(\n `Unable to find translation for key \"${key}\". Possible keys are ${Object.keys(\n translationsObject,\n )\n .map((v) => `\"${v}\"`)\n .join(', ')}`,\n );\n return '';\n }\n\n const result = message.format(params);\n\n if (Array.isArray(result)) {\n for (let i = 0; i < result.length; i++) {\n const item = result[i];\n if (\n typeof item === 'object' &&\n item &&\n !item.key &&\n isValidElement(item)\n ) {\n result[i] = cloneElement(item, { key: `_vocab-${i}` });\n }\n }\n }\n\n return result;\n },\n [translationsObject],\n );\n\n return {\n ready,\n t,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,MAAM,sBAAsBA,cAAM,cAEhC,OAAU;;;;;;;;;;;AAqCZ,MAAa,iBAAiB,EAC5B,UACA,UACA,aACwB;CACxB,MAAM,kCAAuB;EAAE;EAAU;EAAQ,GAAG,CAAC,UAAU,OAAO,CAAC;AAEvE,QACE,4CAAC,oBAAoB,YAAgB,SAClC,SAC4B;;;;;AAOnC,MAAa,oBAA8C;CACzD,MAAM,gCAAqB,oBAAoB;AAC/C,KAAI,CAAC,QACH,OAAM,IAAI,MACR,qGACD;AAEH,KAAI,CAAC,QAAQ,SACX,OAAM,IAAI,MACR,0GACD;AAGH,QAAO;;AAGT,MAAM,mBAAmB,OAAO,WAAW;AA6B3C,SAAgB,gBAId,cAIA;CACA,MAAM,EAAE,UAAU,WAAW,aAAa;CAC1C,MAAM,GAAG,sCAA2B,MAAc,IAAI,GAAG,EAAE;CAE3D,MAAM,qBAAqB,aAAa,kBACtC,UACA,UAAU,SACX;CAED,IAAI,QAAQ;AAEZ,KAAI,CAAC,oBAAoB;AACvB,MAAI,iBACF,OAAM,IAAI,MACR,6HACD;AAGH,eAAa,KAAK,SAAgB,CAAC,WAAW;AAC5C,gBAAa;IACb;AACF,UAAQ;;CAGV,MAAM,4BACH,KAAa,WAAiB;AAC7B,MAAI,CAAC,mBACH,QAAO;EAGT,MAAM,UAAU,qBAAqB;AAErC,MAAI,CAAC,SAAS;AAEZ,WAAQ,MACN,uCAAuC,IAAI,uBAAuB,OAAO,KACvE,mBACD,CACE,KAAK,MAAM,IAAI,EAAE,GAAG,CACpB,KAAK,KAAK,GACd;AACD,UAAO;;EAGT,MAAM,SAAS,QAAQ,OAAO,OAAO;AAErC,MAAI,MAAM,QAAQ,OAAO,CACvB,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;GACtC,MAAM,OAAO,OAAO;AACpB,OACE,OAAO,SAAS,YAChB,QACA,CAAC,KAAK,iCACS,KAAK,CAEpB,QAAO,6BAAkB,MAAM,EAAE,KAAK,UAAU,KAAK,CAAC;;AAK5D,SAAO;IAET,CAAC,mBAAmB,CACrB;AAED,QAAO;EACL;EACA;EACD"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React, { cloneElement, isValidElement, useCallback, useContext, useMemo, useReducer } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/components.tsx
|
|
4
|
+
const TranslationsContext = React.createContext(void 0);
|
|
5
|
+
/**
|
|
6
|
+
* Provides a translation context for your application
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import { VocabProvider } from '@vocab/react';
|
|
10
|
+
*
|
|
11
|
+
* <VocabProvider language="en">
|
|
12
|
+
* <App />
|
|
13
|
+
* <VocabProvider />
|
|
14
|
+
*/
|
|
15
|
+
const VocabProvider = ({ children, language, locale }) => {
|
|
16
|
+
const value = useMemo(() => ({
|
|
17
|
+
language,
|
|
18
|
+
locale
|
|
19
|
+
}), [language, locale]);
|
|
20
|
+
return /* @__PURE__ */ React.createElement(TranslationsContext.Provider, { value }, children);
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* @returns The `language` and `locale` values passed in to your `VocabProvider`
|
|
24
|
+
*/
|
|
25
|
+
const useLanguage = () => {
|
|
26
|
+
const context = useContext(TranslationsContext);
|
|
27
|
+
if (!context) throw new Error("Attempted to access translation without Vocab context set. Did you forget to render VocabProvider?");
|
|
28
|
+
if (!context.language) throw new Error("Attempted to access translation without language set. Did you forget to pass language to VocabProvider?");
|
|
29
|
+
return context;
|
|
30
|
+
};
|
|
31
|
+
const SERVER_RENDERING = typeof window === "undefined";
|
|
32
|
+
function useTranslations(translations) {
|
|
33
|
+
const { language, locale } = useLanguage();
|
|
34
|
+
const [, forceRender] = useReducer((s) => s + 1, 0);
|
|
35
|
+
const translationsObject = translations.getLoadedMessages(language, locale || language);
|
|
36
|
+
let ready = true;
|
|
37
|
+
if (!translationsObject) {
|
|
38
|
+
if (SERVER_RENDERING) throw new Error(`Translations not synchronously available on server render. Applying translations dynamically server-side is not supported.`);
|
|
39
|
+
translations.load(language).then(() => {
|
|
40
|
+
forceRender();
|
|
41
|
+
});
|
|
42
|
+
ready = false;
|
|
43
|
+
}
|
|
44
|
+
const t = useCallback((key, params) => {
|
|
45
|
+
if (!translationsObject) return " ";
|
|
46
|
+
const message = translationsObject?.[key];
|
|
47
|
+
if (!message) {
|
|
48
|
+
console.error(`Unable to find translation for key "${key}". Possible keys are ${Object.keys(translationsObject).map((v) => `"${v}"`).join(", ")}`);
|
|
49
|
+
return "";
|
|
50
|
+
}
|
|
51
|
+
const result = message.format(params);
|
|
52
|
+
if (Array.isArray(result)) for (let i = 0; i < result.length; i++) {
|
|
53
|
+
const item = result[i];
|
|
54
|
+
if (typeof item === "object" && item && !item.key && isValidElement(item)) result[i] = cloneElement(item, { key: `_vocab-${i}` });
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}, [translationsObject]);
|
|
58
|
+
return {
|
|
59
|
+
ready,
|
|
60
|
+
t
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//#endregion
|
|
65
|
+
export { VocabProvider, useLanguage, useTranslations };
|
|
66
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/components.tsx"],"sourcesContent":["import type {\n TranslationFile,\n LanguageName,\n ParsedFormatFnByKey,\n ParsedFormatFn,\n} from '@vocab/core';\n\nimport React, {\n type ReactNode,\n useContext,\n useMemo,\n useReducer,\n isValidElement,\n cloneElement,\n useCallback,\n} from 'react';\n\ntype Locale = string;\n\ninterface TranslationsContextValue {\n /**\n * The `language` passed in to your `VocabProvider`\n */\n language: LanguageName;\n /**\n * The `locale` passed in to your `VocabProvider`\n *\n * Please note that this value will be `undefined` if you have not passed a `locale` to your `VocabProvider`.\n * If your languages are named with IETF language tags, you should just use `language` instead of\n * this value, unless you specifically need to access your `locale` override.\n */\n locale?: Locale;\n}\n\nconst TranslationsContext = React.createContext<\n TranslationsContextValue | undefined\n>(undefined);\n\n// Not extending TranslationsContextValue so we can tailor the docs for each prop to be better\n// suited to the provider, rather than for the useLanguage hook\ninterface VocabProviderProps {\n /**\n * The language to load translations for. Must be one of the language names defined in your `vocab.config.js`.\n */\n language: TranslationsContextValue['language'];\n /**\n * A locale override. By default, Vocab will use the `language` as the locale when formatting messages if\n * `locale` is not set. If your languages are named with IETF language tags, you probably don't need to\n * set this value.\n *\n * You may want to override the locale for a specific language if the default formatting for that locale\n * is not desired.\n *\n * @example\n * // Override the locale for th-TH to use the Gregorian calendar instead of the default Buddhist calendar\n * <VocabProvider language=\"th-TH\" locale=\"th-TH-u-ca-gregory\">\n * </App>\n * <VocabProvider />\n */\n locale?: TranslationsContextValue['locale'];\n children: ReactNode;\n}\n\n/**\n * Provides a translation context for your application\n *\n * @example\n * import { VocabProvider } from '@vocab/react';\n *\n * <VocabProvider language=\"en\">\n * <App />\n * <VocabProvider />\n */\nexport const VocabProvider = ({\n children,\n language,\n locale,\n}: VocabProviderProps) => {\n const value = useMemo(() => ({ language, locale }), [language, locale]);\n\n return (\n <TranslationsContext.Provider value={value}>\n {children}\n </TranslationsContext.Provider>\n );\n};\n\n/**\n * @returns The `language` and `locale` values passed in to your `VocabProvider`\n */\nexport const useLanguage = (): TranslationsContextValue => {\n const context = useContext(TranslationsContext);\n if (!context) {\n throw new Error(\n 'Attempted to access translation without Vocab context set. Did you forget to render VocabProvider?',\n );\n }\n if (!context.language) {\n throw new Error(\n 'Attempted to access translation without language set. Did you forget to pass language to VocabProvider?',\n );\n }\n\n return context;\n};\n\nconst SERVER_RENDERING = typeof window === 'undefined';\n\ntype FormatXMLElementReactNodeFn = (parts: ReactNode[]) => ReactNode;\n\ntype MapToReactNodeFunction<Params extends Record<string, any>> = {\n [key in keyof Params]: Params[key] extends ParsedFormatFn\n ? FormatXMLElementReactNodeFn\n : Params[key];\n};\n\ntype TranslateFn<FormatFnByKey extends ParsedFormatFnByKey> = {\n <TranslationKey extends keyof FormatFnByKey>(\n key: TranslationKey,\n params: MapToReactNodeFunction<\n Parameters<FormatFnByKey[TranslationKey]>[0]\n >,\n ): ReturnType<FormatFnByKey[TranslationKey]> extends string\n ? string\n : ReactNode | string | Array<ReactNode | string>;\n <TranslationKey extends keyof FormatFnByKey>(\n key: Parameters<FormatFnByKey[TranslationKey]>[0] extends Record<\n string,\n any\n >\n ? never\n : TranslationKey,\n ): string;\n};\n\nexport function useTranslations<\n Language extends string,\n FormatFnByKey extends ParsedFormatFnByKey,\n>(\n translations: TranslationFile<Language, FormatFnByKey>,\n): {\n ready: boolean;\n t: TranslateFn<FormatFnByKey>;\n} {\n const { language, locale } = useLanguage();\n const [, forceRender] = useReducer((s: number) => s + 1, 0);\n\n const translationsObject = translations.getLoadedMessages(\n language as any,\n locale || language,\n );\n\n let ready = true;\n\n if (!translationsObject) {\n if (SERVER_RENDERING) {\n throw new Error(\n `Translations not synchronously available on server render. Applying translations dynamically server-side is not supported.`,\n );\n }\n\n translations.load(language as any).then(() => {\n forceRender();\n });\n ready = false;\n }\n\n const t = useCallback(\n (key: string, params?: any) => {\n if (!translationsObject) {\n return ' ';\n }\n\n const message = translationsObject?.[key];\n\n if (!message) {\n // eslint-disable-next-line no-console\n console.error(\n `Unable to find translation for key \"${key}\". Possible keys are ${Object.keys(\n translationsObject,\n )\n .map((v) => `\"${v}\"`)\n .join(', ')}`,\n );\n return '';\n }\n\n const result = message.format(params);\n\n if (Array.isArray(result)) {\n for (let i = 0; i < result.length; i++) {\n const item = result[i];\n if (\n typeof item === 'object' &&\n item &&\n !item.key &&\n isValidElement(item)\n ) {\n result[i] = cloneElement(item, { key: `_vocab-${i}` });\n }\n }\n }\n\n return result;\n },\n [translationsObject],\n );\n\n return {\n ready,\n t,\n };\n}\n"],"mappings":";;;AAkCA,MAAM,sBAAsB,MAAM,cAEhC,OAAU;;;;;;;;;;;AAqCZ,MAAa,iBAAiB,EAC5B,UACA,UACA,aACwB;CACxB,MAAM,QAAQ,eAAe;EAAE;EAAU;EAAQ,GAAG,CAAC,UAAU,OAAO,CAAC;AAEvE,QACE,oCAAC,oBAAoB,YAAgB,SAClC,SAC4B;;;;;AAOnC,MAAa,oBAA8C;CACzD,MAAM,UAAU,WAAW,oBAAoB;AAC/C,KAAI,CAAC,QACH,OAAM,IAAI,MACR,qGACD;AAEH,KAAI,CAAC,QAAQ,SACX,OAAM,IAAI,MACR,0GACD;AAGH,QAAO;;AAGT,MAAM,mBAAmB,OAAO,WAAW;AA6B3C,SAAgB,gBAId,cAIA;CACA,MAAM,EAAE,UAAU,WAAW,aAAa;CAC1C,MAAM,GAAG,eAAe,YAAY,MAAc,IAAI,GAAG,EAAE;CAE3D,MAAM,qBAAqB,aAAa,kBACtC,UACA,UAAU,SACX;CAED,IAAI,QAAQ;AAEZ,KAAI,CAAC,oBAAoB;AACvB,MAAI,iBACF,OAAM,IAAI,MACR,6HACD;AAGH,eAAa,KAAK,SAAgB,CAAC,WAAW;AAC5C,gBAAa;IACb;AACF,UAAQ;;CAGV,MAAM,IAAI,aACP,KAAa,WAAiB;AAC7B,MAAI,CAAC,mBACH,QAAO;EAGT,MAAM,UAAU,qBAAqB;AAErC,MAAI,CAAC,SAAS;AAEZ,WAAQ,MACN,uCAAuC,IAAI,uBAAuB,OAAO,KACvE,mBACD,CACE,KAAK,MAAM,IAAI,EAAE,GAAG,CACpB,KAAK,KAAK,GACd;AACD,UAAO;;EAGT,MAAM,SAAS,QAAQ,OAAO,OAAO;AAErC,MAAI,MAAM,QAAQ,OAAO,CACvB,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;GACtC,MAAM,OAAO,OAAO;AACpB,OACE,OAAO,SAAS,YAChB,QACA,CAAC,KAAK,OACN,eAAe,KAAK,CAEpB,QAAO,KAAK,aAAa,MAAM,EAAE,KAAK,UAAU,KAAK,CAAC;;AAK5D,SAAO;IAET,CAAC,mBAAmB,CACrB;AAED,QAAO;EACL;EACA;EACD"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vocab/react",
|
|
3
|
-
"version": "0.0.0-
|
|
4
|
-
"
|
|
5
|
-
|
|
3
|
+
"version": "0.0.0-tsdown-20250922064402",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/seek-oss/vocab.git",
|
|
7
|
+
"directory": "packages/react"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"module": "./dist/index.mjs",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/index.mjs",
|
|
15
|
+
"require": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./package.json": "./package.json"
|
|
18
|
+
},
|
|
6
19
|
"author": "SEEK",
|
|
7
20
|
"license": "MIT",
|
|
8
21
|
"peerDependencies": {
|
|
@@ -12,11 +25,11 @@
|
|
|
12
25
|
"dist"
|
|
13
26
|
],
|
|
14
27
|
"dependencies": {
|
|
15
|
-
"
|
|
16
|
-
"
|
|
28
|
+
"intl-messageformat": "^10.0.0",
|
|
29
|
+
"@vocab/core": "^0.0.0-tsdown-20250922064402"
|
|
17
30
|
},
|
|
18
31
|
"devDependencies": {
|
|
19
|
-
"@types/react": "^
|
|
20
|
-
"react": "^
|
|
32
|
+
"@types/react": "^19.1.8",
|
|
33
|
+
"react": "^19.1.0"
|
|
21
34
|
}
|
|
22
|
-
}
|
|
35
|
+
}
|
|
@@ -1,25 +0,0 @@
|
|
|
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 +0,0 @@
|
|
|
1
|
-
export * from "./declarations/src/index";
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
|
-
var React = require('react');
|
|
6
|
-
|
|
7
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
8
|
-
|
|
9
|
-
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
10
|
-
|
|
11
|
-
const TranslationsContext = /*#__PURE__*/React__default['default'].createContext(undefined);
|
|
12
|
-
const VocabProvider = ({
|
|
13
|
-
children,
|
|
14
|
-
language,
|
|
15
|
-
locale
|
|
16
|
-
}) => {
|
|
17
|
-
const value = React.useMemo(() => ({
|
|
18
|
-
language,
|
|
19
|
-
locale
|
|
20
|
-
}), [language, locale]);
|
|
21
|
-
return /*#__PURE__*/React__default['default'].createElement(TranslationsContext.Provider, {
|
|
22
|
-
value: value
|
|
23
|
-
}, children);
|
|
24
|
-
};
|
|
25
|
-
const useLanguage = () => {
|
|
26
|
-
const context = React.useContext(TranslationsContext);
|
|
27
|
-
|
|
28
|
-
if (!context) {
|
|
29
|
-
throw new Error('Attempted to access translation without Vocab context set. Did you forget to render VocabProvider?');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (!context.language) {
|
|
33
|
-
throw new Error('Attempted to access translation without language set. Did you forget to pass language to VocabProvider?');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return context;
|
|
37
|
-
};
|
|
38
|
-
const SERVER_RENDERING = typeof window === 'undefined';
|
|
39
|
-
function useTranslations(translations) {
|
|
40
|
-
const {
|
|
41
|
-
language,
|
|
42
|
-
locale
|
|
43
|
-
} = useLanguage();
|
|
44
|
-
const [, forceRender] = React.useReducer(s => s + 1, 0);
|
|
45
|
-
const translationsObject = translations.getLoadedMessages(language, locale || language);
|
|
46
|
-
let ready = true;
|
|
47
|
-
|
|
48
|
-
if (!translationsObject) {
|
|
49
|
-
if (SERVER_RENDERING) {
|
|
50
|
-
throw new Error(`Translations not synchronously available on server render. Applying translations dynamically server-side is not supported.`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
translations.load(language).then(() => {
|
|
54
|
-
forceRender();
|
|
55
|
-
});
|
|
56
|
-
ready = false;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const t = React.useCallback((key, params) => {
|
|
60
|
-
if (!translationsObject) {
|
|
61
|
-
return ' ';
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const message = translationsObject === null || translationsObject === void 0 ? void 0 : translationsObject[key];
|
|
65
|
-
|
|
66
|
-
if (!message) {
|
|
67
|
-
// eslint-disable-next-line no-console
|
|
68
|
-
console.error(`Unable to find translation for key "${key}". Possible keys are ${Object.keys(translationsObject).map(v => `"${v}"`).join(', ')}`);
|
|
69
|
-
return '';
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const result = message.format(params);
|
|
73
|
-
|
|
74
|
-
if (Array.isArray(result)) {
|
|
75
|
-
for (let i = 0; i < result.length; i++) {
|
|
76
|
-
const item = result[i];
|
|
77
|
-
|
|
78
|
-
if (typeof item === 'object' && item && !item.key && /*#__PURE__*/React.isValidElement(item)) {
|
|
79
|
-
result[i] = /*#__PURE__*/React.cloneElement(item, {
|
|
80
|
-
key: `_vocab-${i}`
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return result;
|
|
87
|
-
}, [translationsObject]);
|
|
88
|
-
return {
|
|
89
|
-
ready,
|
|
90
|
-
t
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
exports.VocabProvider = VocabProvider;
|
|
95
|
-
exports.useLanguage = useLanguage;
|
|
96
|
-
exports.useTranslations = useTranslations;
|
package/dist/vocab-react.cjs.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
|
-
var React = require('react');
|
|
6
|
-
|
|
7
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
8
|
-
|
|
9
|
-
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
10
|
-
|
|
11
|
-
const TranslationsContext = /*#__PURE__*/React__default['default'].createContext(undefined);
|
|
12
|
-
const VocabProvider = ({
|
|
13
|
-
children,
|
|
14
|
-
language,
|
|
15
|
-
locale
|
|
16
|
-
}) => {
|
|
17
|
-
const value = React.useMemo(() => ({
|
|
18
|
-
language,
|
|
19
|
-
locale
|
|
20
|
-
}), [language, locale]);
|
|
21
|
-
return /*#__PURE__*/React__default['default'].createElement(TranslationsContext.Provider, {
|
|
22
|
-
value: value
|
|
23
|
-
}, children);
|
|
24
|
-
};
|
|
25
|
-
const useLanguage = () => {
|
|
26
|
-
const context = React.useContext(TranslationsContext);
|
|
27
|
-
|
|
28
|
-
if (!context) {
|
|
29
|
-
throw new Error('Attempted to access translation without Vocab context set. Did you forget to render VocabProvider?');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (!context.language) {
|
|
33
|
-
throw new Error('Attempted to access translation without language set. Did you forget to pass language to VocabProvider?');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return context;
|
|
37
|
-
};
|
|
38
|
-
const SERVER_RENDERING = typeof window === 'undefined';
|
|
39
|
-
function useTranslations(translations) {
|
|
40
|
-
const {
|
|
41
|
-
language,
|
|
42
|
-
locale
|
|
43
|
-
} = useLanguage();
|
|
44
|
-
const [, forceRender] = React.useReducer(s => s + 1, 0);
|
|
45
|
-
const translationsObject = translations.getLoadedMessages(language, locale || language);
|
|
46
|
-
let ready = true;
|
|
47
|
-
|
|
48
|
-
if (!translationsObject) {
|
|
49
|
-
if (SERVER_RENDERING) {
|
|
50
|
-
throw new Error(`Translations not synchronously available on server render. Applying translations dynamically server-side is not supported.`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
translations.load(language).then(() => {
|
|
54
|
-
forceRender();
|
|
55
|
-
});
|
|
56
|
-
ready = false;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const t = React.useCallback((key, params) => {
|
|
60
|
-
if (!translationsObject) {
|
|
61
|
-
return ' ';
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const message = translationsObject === null || translationsObject === void 0 ? void 0 : translationsObject[key];
|
|
65
|
-
|
|
66
|
-
if (!message) {
|
|
67
|
-
// eslint-disable-next-line no-console
|
|
68
|
-
console.error(`Unable to find translation for key "${key}". Possible keys are ${Object.keys(translationsObject).map(v => `"${v}"`).join(', ')}`);
|
|
69
|
-
return '';
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const result = message.format(params);
|
|
73
|
-
|
|
74
|
-
if (Array.isArray(result)) {
|
|
75
|
-
for (let i = 0; i < result.length; i++) {
|
|
76
|
-
const item = result[i];
|
|
77
|
-
|
|
78
|
-
if (typeof item === 'object' && item && !item.key && /*#__PURE__*/React.isValidElement(item)) {
|
|
79
|
-
result[i] = /*#__PURE__*/React.cloneElement(item, {
|
|
80
|
-
key: `_vocab-${i}`
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return result;
|
|
87
|
-
}, [translationsObject]);
|
|
88
|
-
return {
|
|
89
|
-
ready,
|
|
90
|
-
t
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
exports.VocabProvider = VocabProvider;
|
|
95
|
-
exports.useLanguage = useLanguage;
|
|
96
|
-
exports.useTranslations = useTranslations;
|
package/dist/vocab-react.esm.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import React, { useMemo, useContext, useReducer, useCallback, isValidElement, cloneElement } from 'react';
|
|
2
|
-
|
|
3
|
-
const TranslationsContext = /*#__PURE__*/React.createContext(undefined);
|
|
4
|
-
const VocabProvider = ({
|
|
5
|
-
children,
|
|
6
|
-
language,
|
|
7
|
-
locale
|
|
8
|
-
}) => {
|
|
9
|
-
const value = useMemo(() => ({
|
|
10
|
-
language,
|
|
11
|
-
locale
|
|
12
|
-
}), [language, locale]);
|
|
13
|
-
return /*#__PURE__*/React.createElement(TranslationsContext.Provider, {
|
|
14
|
-
value: value
|
|
15
|
-
}, children);
|
|
16
|
-
};
|
|
17
|
-
const useLanguage = () => {
|
|
18
|
-
const context = useContext(TranslationsContext);
|
|
19
|
-
|
|
20
|
-
if (!context) {
|
|
21
|
-
throw new Error('Attempted to access translation without Vocab context set. Did you forget to render VocabProvider?');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (!context.language) {
|
|
25
|
-
throw new Error('Attempted to access translation without language set. Did you forget to pass language to VocabProvider?');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return context;
|
|
29
|
-
};
|
|
30
|
-
const SERVER_RENDERING = typeof window === 'undefined';
|
|
31
|
-
function useTranslations(translations) {
|
|
32
|
-
const {
|
|
33
|
-
language,
|
|
34
|
-
locale
|
|
35
|
-
} = useLanguage();
|
|
36
|
-
const [, forceRender] = useReducer(s => s + 1, 0);
|
|
37
|
-
const translationsObject = translations.getLoadedMessages(language, locale || language);
|
|
38
|
-
let ready = true;
|
|
39
|
-
|
|
40
|
-
if (!translationsObject) {
|
|
41
|
-
if (SERVER_RENDERING) {
|
|
42
|
-
throw new Error(`Translations not synchronously available on server render. Applying translations dynamically server-side is not supported.`);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
translations.load(language).then(() => {
|
|
46
|
-
forceRender();
|
|
47
|
-
});
|
|
48
|
-
ready = false;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const t = useCallback((key, params) => {
|
|
52
|
-
if (!translationsObject) {
|
|
53
|
-
return ' ';
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const message = translationsObject === null || translationsObject === void 0 ? void 0 : translationsObject[key];
|
|
57
|
-
|
|
58
|
-
if (!message) {
|
|
59
|
-
// eslint-disable-next-line no-console
|
|
60
|
-
console.error(`Unable to find translation for key "${key}". Possible keys are ${Object.keys(translationsObject).map(v => `"${v}"`).join(', ')}`);
|
|
61
|
-
return '';
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const result = message.format(params);
|
|
65
|
-
|
|
66
|
-
if (Array.isArray(result)) {
|
|
67
|
-
for (let i = 0; i < result.length; i++) {
|
|
68
|
-
const item = result[i];
|
|
69
|
-
|
|
70
|
-
if (typeof item === 'object' && item && !item.key && /*#__PURE__*/isValidElement(item)) {
|
|
71
|
-
result[i] = /*#__PURE__*/cloneElement(item, {
|
|
72
|
-
key: `_vocab-${i}`
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return result;
|
|
79
|
-
}, [translationsObject]);
|
|
80
|
-
return {
|
|
81
|
-
ready,
|
|
82
|
-
t
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export { VocabProvider, useLanguage, useTranslations };
|