@snack-uikit/locale 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +1 -1
- package/dist/components/LocaleProvider/LocaleProvider.d.ts +2 -1
- package/dist/components/LocaleProvider/LocaleProvider.js +11 -2
- package/dist/components/LocaleProvider/hooks.d.ts +10 -3
- package/dist/components/LocaleProvider/hooks.js +25 -12
- package/dist/locales/ru_RU.d.ts +2 -27
- package/dist/typeUtils.d.ts +4 -0
- package/dist/types.d.ts +3 -2
- package/package.json +2 -2
- package/src/components/LocaleProvider/LocaleProvider.tsx +19 -3
- package/src/components/LocaleProvider/hooks.ts +42 -19
- package/src/locales/ru_RU.ts +3 -1
- package/src/typeUtils.ts +16 -0
- package/src/types.ts +8 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 0.4.0 (2024-02-12)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **FF-4205:** add typing to ru locale to match texts ([fd4a435](https://github.com/cloud-ru-tech/snack-uikit/commit/fd4a43532bb8a349d8e1f765285491ae65c00882))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **FF-4205:** changed api of useLocale hook ([5c19647](https://github.com/cloud-ru-tech/snack-uikit/commit/5c19647f21d072e92c48c4b9588ed9df86c0ae86))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
# 0.3.0 (2024-02-09)
|
|
7
23
|
|
|
8
24
|
|
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ const lang = 'en_GB'; // or 'ru_RU' or 'custom_LANG'
|
|
|
54
54
|
| name | type | default value | description |
|
|
55
55
|
|------|------|---------------|-------------|
|
|
56
56
|
| lang* | `string` | - | |
|
|
57
|
-
| locales | `
|
|
57
|
+
| locales | `PartialObjectDeep<Record<string, { firstLevelTrans: string; Table: { searchPlaceholder: string; noData: { title: string; }; noResults: { title: string; description: string; }; errorData: { title: string; description: string; }; rowsOptionsLabel: string; export: string; }; Chips: { ...; }; Fields: { ...; }; }>>` | - | |
|
|
58
58
|
## useLocale
|
|
59
59
|
`helper`
|
|
60
60
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { LocaleLang, OverrideLocales } from '../../types';
|
|
2
|
+
import { LocaleDictionary, LocaleLang, OverrideLocales } from '../../types';
|
|
3
3
|
export declare const DEFAULT_LANG = "en_GB";
|
|
4
4
|
export type LocaleContextType = {
|
|
5
5
|
lang: LocaleLang;
|
|
6
6
|
locales: OverrideLocales;
|
|
7
|
+
localesByLang: LocaleDictionary;
|
|
7
8
|
};
|
|
8
9
|
export declare const LocaleContext: import("react").Context<LocaleContextType>;
|
|
9
10
|
export type LocaleProviderProps = {
|
|
@@ -6,8 +6,9 @@ export const DEFAULT_LANG = 'en_GB';
|
|
|
6
6
|
export const LocaleContext = createContext({
|
|
7
7
|
lang: DEFAULT_LANG,
|
|
8
8
|
locales: LOCALES,
|
|
9
|
+
localesByLang: LOCALES.en_GB,
|
|
9
10
|
});
|
|
10
|
-
export function LocaleProvider({ lang: langProp
|
|
11
|
+
export function LocaleProvider({ lang: langProp, locales: localesProp, children }) {
|
|
11
12
|
const locales = useMemo(() => {
|
|
12
13
|
if (localesProp) {
|
|
13
14
|
return merge({}, LOCALES, localesProp);
|
|
@@ -15,5 +16,13 @@ export function LocaleProvider({ lang: langProp = DEFAULT_LANG, locales: locales
|
|
|
15
16
|
return LOCALES;
|
|
16
17
|
}, [localesProp]);
|
|
17
18
|
const lang = useMemo(() => langProp.replace('-', '_'), [langProp]);
|
|
18
|
-
|
|
19
|
+
const localesByLang = useMemo(() => {
|
|
20
|
+
let localesObj = locales[lang];
|
|
21
|
+
if (!localesObj) {
|
|
22
|
+
console.warn(`Snack-uikit: localization for lang ${lang} was not found. Make sure you are using correct lang or passed proper locales to LocaleProvider. For now default language (${DEFAULT_LANG}) will be used`);
|
|
23
|
+
localesObj = locales[DEFAULT_LANG];
|
|
24
|
+
}
|
|
25
|
+
return localesObj;
|
|
26
|
+
}, [lang, locales]);
|
|
27
|
+
return _jsx(LocaleContext.Provider, { value: { lang, locales, localesByLang }, children: children });
|
|
19
28
|
}
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import { LocaleDictionary, LocaleLang } from '../../types';
|
|
1
|
+
import { DottedTranslationKey, LocaleDictionary, LocaleLang } from '../../types';
|
|
2
2
|
type LocaleComponentName = keyof LocaleDictionary;
|
|
3
|
+
type GetLocaleText<T extends keyof LocaleDictionary | undefined = undefined> = (key: DottedTranslationKey<T>) => string;
|
|
3
4
|
/**
|
|
4
5
|
* Inner hook to use translations
|
|
5
6
|
* @function helper
|
|
6
7
|
*/
|
|
7
|
-
export declare function useLocale():
|
|
8
|
-
|
|
8
|
+
export declare function useLocale(): {
|
|
9
|
+
t: GetLocaleText;
|
|
10
|
+
lang: LocaleLang;
|
|
11
|
+
};
|
|
12
|
+
export declare function useLocale<C extends LocaleComponentName = LocaleComponentName>(componentName: C): {
|
|
13
|
+
t: GetLocaleText<C>;
|
|
14
|
+
lang: LocaleLang;
|
|
15
|
+
};
|
|
9
16
|
export {};
|
|
@@ -1,17 +1,30 @@
|
|
|
1
|
-
import { useContext, useMemo } from 'react';
|
|
2
|
-
import {
|
|
1
|
+
import { useCallback, useContext, useMemo } from 'react';
|
|
2
|
+
import { LocaleContext } from './LocaleProvider';
|
|
3
3
|
export function useLocale(componentName) {
|
|
4
|
-
const {
|
|
4
|
+
const { localesByLang, lang } = useContext(LocaleContext);
|
|
5
5
|
const locales = useMemo(() => {
|
|
6
|
-
let localesObj = ctxLocales[lang];
|
|
7
|
-
if (!localesObj) {
|
|
8
|
-
console.warn(`Snack-uikit: localization for lang ${lang} was not found. Make sure you are using correct lang or passed proper locales to LocaleProvider. For now default language (${DEFAULT_LANG}) will be used`);
|
|
9
|
-
localesObj = ctxLocales[DEFAULT_LANG];
|
|
10
|
-
}
|
|
11
6
|
if (!componentName) {
|
|
12
|
-
return
|
|
7
|
+
return localesByLang;
|
|
8
|
+
}
|
|
9
|
+
return (localesByLang[componentName] || {});
|
|
10
|
+
}, [componentName, localesByLang]);
|
|
11
|
+
const getLocaleText = useCallback(key => {
|
|
12
|
+
let translation = '';
|
|
13
|
+
const complexKey = key.split('.');
|
|
14
|
+
if (complexKey.length === 1) {
|
|
15
|
+
translation = locales[key];
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
translation = complexKey.reduce((acc, cur) => acc[cur], locales);
|
|
19
|
+
}
|
|
20
|
+
if (!(translation === null || translation === void 0 ? void 0 : translation.length)) {
|
|
21
|
+
console.warn(`Snack-uikit: the '${key}' key is not found in the current locale '${lang}'.`);
|
|
22
|
+
return key;
|
|
13
23
|
}
|
|
14
|
-
return
|
|
15
|
-
}, [
|
|
16
|
-
return
|
|
24
|
+
return translation;
|
|
25
|
+
}, [lang, locales]);
|
|
26
|
+
return {
|
|
27
|
+
t: getLocaleText,
|
|
28
|
+
lang,
|
|
29
|
+
};
|
|
17
30
|
}
|
package/dist/locales/ru_RU.d.ts
CHANGED
|
@@ -1,27 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
searchPlaceholder: string;
|
|
4
|
-
noData: {
|
|
5
|
-
title: string;
|
|
6
|
-
};
|
|
7
|
-
noResults: {
|
|
8
|
-
title: string;
|
|
9
|
-
description: string;
|
|
10
|
-
};
|
|
11
|
-
errorData: {
|
|
12
|
-
title: string;
|
|
13
|
-
description: string;
|
|
14
|
-
};
|
|
15
|
-
rowsOptionsLabel: string;
|
|
16
|
-
export: string;
|
|
17
|
-
};
|
|
18
|
-
Chips: {
|
|
19
|
-
clearAllButton: string;
|
|
20
|
-
};
|
|
21
|
-
Fields: {
|
|
22
|
-
limitTooltip: {
|
|
23
|
-
max: string;
|
|
24
|
-
min: string;
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
};
|
|
1
|
+
import { en_GB } from './en_GB';
|
|
2
|
+
export declare const ru_RU: typeof en_GB;
|
package/dist/typeUtils.d.ts
CHANGED
|
@@ -23,4 +23,8 @@ type PartialReadonlySetDeep<T> = unknown & ReadonlySet<PartialDeep<T>>;
|
|
|
23
23
|
type PartialObjectDeep<ObjectType extends object> = {
|
|
24
24
|
[KeyType in keyof ObjectType]?: PartialDeep<ObjectType[KeyType]>;
|
|
25
25
|
};
|
|
26
|
+
export type PathsToStringProps<T> = T extends string ? [] : {
|
|
27
|
+
[K in Extract<keyof T, string>]: [K, ...PathsToStringProps<T[K]>];
|
|
28
|
+
}[Extract<keyof T, string>];
|
|
29
|
+
export type Join<T extends string[], D extends string> = T extends [] ? never : T extends [infer F] ? F : T extends [infer F, ...infer R] ? F extends string ? `${F}${D}${Join<Extract<R, string[]>, D>}` : never : string;
|
|
26
30
|
export {};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LOCALES } from './locales';
|
|
2
|
-
import { PartialDeep } from './typeUtils';
|
|
2
|
+
import { Join, PartialDeep, PathsToStringProps } from './typeUtils';
|
|
3
3
|
export type KnownLocaleLang = keyof typeof LOCALES;
|
|
4
4
|
export type LocaleLang = KnownLocaleLang | string;
|
|
5
5
|
export type LocaleDictionary = typeof LOCALES.en_GB;
|
|
6
|
-
export type OverrideLocales = PartialDeep<Record<
|
|
6
|
+
export type OverrideLocales = PartialDeep<Record<LocaleLang, LocaleDictionary>>;
|
|
7
|
+
export type DottedTranslationKey<C extends keyof LocaleDictionary | undefined = undefined> = C extends string ? Join<PathsToStringProps<LocaleDictionary[C]>, '.'> : Join<PathsToStringProps<LocaleDictionary>, '.'>;
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Locale",
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.4.0",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/lodash.merge": "4.6.9"
|
|
39
39
|
},
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "5e7b0b6d34f40c4266070bf918e9cdf127ac882c"
|
|
41
41
|
}
|
|
@@ -2,18 +2,20 @@ import merge from 'lodash.merge';
|
|
|
2
2
|
import { createContext, ReactNode, useMemo } from 'react';
|
|
3
3
|
|
|
4
4
|
import { LOCALES } from '../../locales';
|
|
5
|
-
import { LocaleLang, OverrideLocales } from '../../types';
|
|
5
|
+
import { KnownLocaleLang, LocaleDictionary, LocaleLang, OverrideLocales } from '../../types';
|
|
6
6
|
|
|
7
7
|
export const DEFAULT_LANG = 'en_GB';
|
|
8
8
|
|
|
9
9
|
export type LocaleContextType = {
|
|
10
10
|
lang: LocaleLang;
|
|
11
11
|
locales: OverrideLocales;
|
|
12
|
+
localesByLang: LocaleDictionary;
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
export const LocaleContext = createContext<LocaleContextType>({
|
|
15
16
|
lang: DEFAULT_LANG,
|
|
16
17
|
locales: LOCALES,
|
|
18
|
+
localesByLang: LOCALES.en_GB,
|
|
17
19
|
});
|
|
18
20
|
|
|
19
21
|
export type LocaleProviderProps = {
|
|
@@ -22,7 +24,7 @@ export type LocaleProviderProps = {
|
|
|
22
24
|
children: ReactNode;
|
|
23
25
|
};
|
|
24
26
|
|
|
25
|
-
export function LocaleProvider({ lang: langProp
|
|
27
|
+
export function LocaleProvider({ lang: langProp, locales: localesProp, children }: LocaleProviderProps) {
|
|
26
28
|
const locales = useMemo(() => {
|
|
27
29
|
if (localesProp) {
|
|
28
30
|
return merge({}, LOCALES, localesProp);
|
|
@@ -33,5 +35,19 @@ export function LocaleProvider({ lang: langProp = DEFAULT_LANG, locales: locales
|
|
|
33
35
|
|
|
34
36
|
const lang = useMemo(() => langProp.replace('-', '_') as LocaleLang, [langProp]);
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
const localesByLang = useMemo(() => {
|
|
39
|
+
let localesObj = locales[lang as KnownLocaleLang];
|
|
40
|
+
|
|
41
|
+
if (!localesObj) {
|
|
42
|
+
console.warn(
|
|
43
|
+
`Snack-uikit: localization for lang ${lang} was not found. Make sure you are using correct lang or passed proper locales to LocaleProvider. For now default language (${DEFAULT_LANG}) will be used`,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
localesObj = locales[DEFAULT_LANG] as LocaleDictionary;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return localesObj;
|
|
50
|
+
}, [lang, locales]);
|
|
51
|
+
|
|
52
|
+
return <LocaleContext.Provider value={{ lang, locales, localesByLang }}>{children}</LocaleContext.Provider>;
|
|
37
53
|
}
|
|
@@ -1,39 +1,62 @@
|
|
|
1
|
-
import { useContext, useMemo } from 'react';
|
|
1
|
+
import { useCallback, useContext, useMemo } from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { DottedTranslationKey, LocaleDictionary, LocaleLang } from '../../types';
|
|
4
|
+
import { LocaleContext, LocaleContextType } from './LocaleProvider';
|
|
5
|
+
|
|
6
|
+
type ValueOf<T> = T[keyof T];
|
|
5
7
|
|
|
6
8
|
type LocaleComponentName = keyof LocaleDictionary;
|
|
7
9
|
|
|
10
|
+
type GetLocaleText<T extends keyof LocaleDictionary | undefined = undefined> = (key: DottedTranslationKey<T>) => string;
|
|
11
|
+
|
|
8
12
|
/**
|
|
9
13
|
* Inner hook to use translations
|
|
10
14
|
* @function helper
|
|
11
15
|
*/
|
|
12
|
-
export function useLocale():
|
|
16
|
+
export function useLocale(): { t: GetLocaleText; lang: LocaleLang };
|
|
13
17
|
export function useLocale<C extends LocaleComponentName = LocaleComponentName>(
|
|
14
18
|
componentName: C,
|
|
15
|
-
):
|
|
19
|
+
): { t: GetLocaleText<C>; lang: LocaleLang };
|
|
16
20
|
|
|
17
21
|
export function useLocale<C extends LocaleComponentName = LocaleComponentName>(componentName?: C) {
|
|
18
|
-
const {
|
|
22
|
+
const { localesByLang, lang } = useContext<LocaleContextType>(LocaleContext);
|
|
19
23
|
|
|
20
24
|
const locales = useMemo(() => {
|
|
21
|
-
|
|
25
|
+
if (!componentName) {
|
|
26
|
+
return localesByLang;
|
|
27
|
+
}
|
|
22
28
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
`Snack-uikit: localization for lang ${lang} was not found. Make sure you are using correct lang or passed proper locales to LocaleProvider. For now default language (${DEFAULT_LANG}) will be used`,
|
|
26
|
-
);
|
|
29
|
+
return (localesByLang[componentName] || {}) as LocaleDictionary[C];
|
|
30
|
+
}, [componentName, localesByLang]);
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
const getLocaleText: GetLocaleText<C> = useCallback(
|
|
33
|
+
key => {
|
|
34
|
+
let translation = '';
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
const complexKey = key.split('.');
|
|
37
|
+
|
|
38
|
+
if (complexKey.length === 1) {
|
|
39
|
+
translation = locales[key as keyof typeof locales] as unknown as string;
|
|
40
|
+
} else {
|
|
41
|
+
translation = complexKey.reduce<LocaleDictionary | ValueOf<LocaleDictionary> | string>(
|
|
42
|
+
(acc, cur) => acc[cur as keyof typeof acc],
|
|
43
|
+
locales,
|
|
44
|
+
) as string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!translation?.length) {
|
|
48
|
+
console.warn(`Snack-uikit: the '${key}' key is not found in the current locale '${lang}'.`);
|
|
49
|
+
|
|
50
|
+
return key;
|
|
51
|
+
}
|
|
34
52
|
|
|
35
|
-
|
|
36
|
-
|
|
53
|
+
return translation;
|
|
54
|
+
},
|
|
55
|
+
[lang, locales],
|
|
56
|
+
);
|
|
37
57
|
|
|
38
|
-
return
|
|
58
|
+
return {
|
|
59
|
+
t: getLocaleText,
|
|
60
|
+
lang,
|
|
61
|
+
};
|
|
39
62
|
}
|
package/src/locales/ru_RU.ts
CHANGED
package/src/typeUtils.ts
CHANGED
|
@@ -46,3 +46,19 @@ type PartialReadonlySetDeep<T> = unknown & ReadonlySet<PartialDeep<T>>;
|
|
|
46
46
|
type PartialObjectDeep<ObjectType extends object> = {
|
|
47
47
|
[KeyType in keyof ObjectType]?: PartialDeep<ObjectType[KeyType]>;
|
|
48
48
|
};
|
|
49
|
+
|
|
50
|
+
export type PathsToStringProps<T> = T extends string
|
|
51
|
+
? []
|
|
52
|
+
: {
|
|
53
|
+
[K in Extract<keyof T, string>]: [K, ...PathsToStringProps<T[K]>];
|
|
54
|
+
}[Extract<keyof T, string>];
|
|
55
|
+
|
|
56
|
+
export type Join<T extends string[], D extends string> = T extends []
|
|
57
|
+
? never
|
|
58
|
+
: T extends [infer F]
|
|
59
|
+
? F
|
|
60
|
+
: T extends [infer F, ...infer R]
|
|
61
|
+
? F extends string
|
|
62
|
+
? `${F}${D}${Join<Extract<R, string[]>, D>}`
|
|
63
|
+
: never
|
|
64
|
+
: string;
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LOCALES } from './locales';
|
|
2
|
-
import { PartialDeep } from './typeUtils';
|
|
2
|
+
import { Join, PartialDeep, PathsToStringProps } from './typeUtils';
|
|
3
3
|
|
|
4
4
|
export type KnownLocaleLang = keyof typeof LOCALES;
|
|
5
5
|
|
|
@@ -7,4 +7,10 @@ export type LocaleLang = KnownLocaleLang | string;
|
|
|
7
7
|
|
|
8
8
|
export type LocaleDictionary = typeof LOCALES.en_GB;
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
// TODO: temporary changed type to fix typings mismatch for "locale" prop in LocaleProvider
|
|
11
|
+
// export type OverrideLocales = PartialDeep<Record<KnownLocaleLang, LocaleDictionary>> | Record<string, LocaleDictionary>;
|
|
12
|
+
export type OverrideLocales = PartialDeep<Record<LocaleLang, LocaleDictionary>>;
|
|
13
|
+
|
|
14
|
+
export type DottedTranslationKey<C extends keyof LocaleDictionary | undefined = undefined> = C extends string
|
|
15
|
+
? Join<PathsToStringProps<LocaleDictionary[C]>, '.'>
|
|
16
|
+
: Join<PathsToStringProps<LocaleDictionary>, '.'>;
|