@digitaldefiance/i18n-lib 1.3.11 → 1.3.13
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 +8 -0
- package/package.json +12 -27
- package/src/active-context.ts +30 -0
- package/src/component-definition.ts +11 -0
- package/src/component-registration.ts +13 -0
- package/src/component-registry.ts +392 -0
- package/src/context-error-type.ts +3 -0
- package/src/context-error.ts +16 -0
- package/src/context-manager.ts +71 -0
- package/src/context.ts +90 -0
- package/src/core-i18n.ts +609 -0
- package/src/core-string-key.ts +49 -0
- package/src/create-translation-adapter.ts +47 -0
- package/src/currency-code.ts +35 -0
- package/{dist/currency-format.d.ts → src/currency-format.ts} +5 -4
- package/src/currency.ts +52 -0
- package/src/default-config.ts +199 -0
- package/src/enum-registry.ts +138 -0
- package/src/global-active-context.ts +255 -0
- package/src/handleable.ts +79 -0
- package/src/i-global-active-context.ts +59 -0
- package/src/i-handleable-error-options.ts +6 -0
- package/src/i-handleable.ts +5 -0
- package/src/i18n-config.ts +29 -0
- package/{dist/i18n-context.d.ts → src/i18n-context.ts} +7 -6
- package/src/i18n-engine.ts +491 -0
- package/{dist/index.d.ts → src/index.ts} +10 -1
- package/{dist/language-codes.d.ts → src/language-codes.ts} +23 -11
- package/src/language-definition.ts +13 -0
- package/src/language-registry.ts +292 -0
- package/src/plugin-i18n-engine.ts +520 -0
- package/src/plugin-translatable-generic-error.ts +106 -0
- package/src/plugin-translatable-handleable-generic.ts +60 -0
- package/src/plugin-typed-handleable.ts +77 -0
- package/src/registry-config.ts +15 -0
- package/src/registry-error-type.ts +12 -0
- package/src/registry-error.ts +74 -0
- package/src/strict-types.ts +35 -0
- package/src/template.ts +63 -0
- package/src/timezone.ts +20 -0
- package/src/translatable.ts +15 -0
- package/src/translation-engine.ts +8 -0
- package/src/translation-request.ts +12 -0
- package/src/translation-response.ts +8 -0
- package/src/typed-error.ts +384 -0
- package/src/typed-handleable.ts +70 -0
- package/{dist/types.d.ts → src/types.ts} +75 -20
- package/src/unified-translator.ts +96 -0
- package/src/utils.ts +213 -0
- package/src/validation-config.ts +11 -0
- package/src/validation-result.ts +12 -0
- package/dist/active-context.d.ts +0 -29
- package/dist/active-context.js +0 -2
- package/dist/component-definition.d.ts +0 -11
- package/dist/component-definition.js +0 -2
- package/dist/component-registration.d.ts +0 -9
- package/dist/component-registration.js +0 -2
- package/dist/component-registry.d.ts +0 -68
- package/dist/component-registry.js +0 -245
- package/dist/context-error-type.d.ts +0 -3
- package/dist/context-error-type.js +0 -7
- package/dist/context-error.d.ts +0 -6
- package/dist/context-error.js +0 -15
- package/dist/context-manager.d.ts +0 -33
- package/dist/context-manager.js +0 -61
- package/dist/context.d.ts +0 -44
- package/dist/context.js +0 -69
- package/dist/core-i18n.d.ts +0 -62
- package/dist/core-i18n.js +0 -477
- package/dist/core-string-key.d.ts +0 -42
- package/dist/core-string-key.js +0 -50
- package/dist/create-translation-adapter.d.ts +0 -20
- package/dist/create-translation-adapter.js +0 -36
- package/dist/currency-code.d.ts +0 -19
- package/dist/currency-code.js +0 -36
- package/dist/currency-format.js +0 -2
- package/dist/currency.d.ts +0 -11
- package/dist/currency.js +0 -48
- package/dist/default-config.d.ts +0 -32
- package/dist/default-config.js +0 -101
- package/dist/enum-registry.d.ts +0 -44
- package/dist/enum-registry.js +0 -100
- package/dist/global-active-context.d.ts +0 -50
- package/dist/global-active-context.js +0 -177
- package/dist/handleable.d.ts +0 -13
- package/dist/handleable.js +0 -56
- package/dist/i-global-active-context.d.ts +0 -22
- package/dist/i-global-active-context.js +0 -2
- package/dist/i-handleable-error-options.d.ts +0 -6
- package/dist/i-handleable-error-options.js +0 -2
- package/dist/i-handleable.d.ts +0 -5
- package/dist/i-handleable.js +0 -2
- package/dist/i18n-config.d.ts +0 -20
- package/dist/i18n-config.js +0 -2
- package/dist/i18n-context.js +0 -2
- package/dist/i18n-engine.d.ts +0 -178
- package/dist/i18n-engine.js +0 -338
- package/dist/index.js +0 -83
- package/dist/language-codes.js +0 -31
- package/dist/language-definition.d.ts +0 -13
- package/dist/language-definition.js +0 -2
- package/dist/language-registry.d.ts +0 -113
- package/dist/language-registry.js +0 -216
- package/dist/plugin-i18n-engine.d.ts +0 -146
- package/dist/plugin-i18n-engine.js +0 -360
- package/dist/plugin-translatable-generic-error.d.ts +0 -29
- package/dist/plugin-translatable-generic-error.js +0 -66
- package/dist/plugin-translatable-handleable-generic.d.ts +0 -28
- package/dist/plugin-translatable-handleable-generic.js +0 -40
- package/dist/plugin-typed-handleable.d.ts +0 -14
- package/dist/plugin-typed-handleable.js +0 -45
- package/dist/registry-config.d.ts +0 -14
- package/dist/registry-config.js +0 -2
- package/dist/registry-error-type.d.ts +0 -12
- package/dist/registry-error-type.js +0 -16
- package/dist/registry-error.d.ts +0 -18
- package/dist/registry-error.js +0 -45
- package/dist/strict-types.d.ts +0 -18
- package/dist/strict-types.js +0 -17
- package/dist/template.d.ts +0 -12
- package/dist/template.js +0 -30
- package/dist/timezone.d.ts +0 -11
- package/dist/timezone.js +0 -22
- package/dist/translatable-generic-error.d.ts +0 -29
- package/dist/translatable-generic-error.js +0 -66
- package/dist/translatable-handleable-generic.d.ts +0 -28
- package/dist/translatable-handleable-generic.js +0 -40
- package/dist/translatable.d.ts +0 -5
- package/dist/translatable.js +0 -11
- package/dist/translation-engine.d.ts +0 -8
- package/dist/translation-engine.js +0 -2
- package/dist/translation-request.d.ts +0 -9
- package/dist/translation-request.js +0 -2
- package/dist/translation-response.d.ts +0 -8
- package/dist/translation-response.js +0 -2
- package/dist/typed-error.d.ts +0 -72
- package/dist/typed-error.js +0 -251
- package/dist/typed-handleable.d.ts +0 -14
- package/dist/typed-handleable.js +0 -40
- package/dist/types.js +0 -18
- package/dist/unified-translator.d.ts +0 -30
- package/dist/unified-translator.js +0 -68
- package/dist/utils.d.ts +0 -64
- package/dist/utils.js +0 -130
- package/dist/validation-config.d.ts +0 -11
- package/dist/validation-config.js +0 -2
- package/dist/validation-result.d.ts +0 -12
- package/dist/validation-result.js +0 -2
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { PluginI18nEngine } from './plugin-i18n-engine';
|
|
2
|
+
import { TranslationEngine } from './translation-engine';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a TranslationEngine adapter from a PluginI18nEngine for a specific component.
|
|
6
|
+
* This allows PluginI18nEngine to be used where TranslationEngine interface is expected.
|
|
7
|
+
*
|
|
8
|
+
* @param pluginEngine - The PluginI18nEngine instance to wrap
|
|
9
|
+
* @param componentId - The component ID to use for translations
|
|
10
|
+
* @returns A TranslationEngine that delegates to the PluginI18nEngine
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const pluginEngine = getMyPluginI18nEngine();
|
|
15
|
+
* const adapter = createTranslationAdapter(pluginEngine, 'my-component');
|
|
16
|
+
*
|
|
17
|
+
* // Now can be used where TranslationEngine is expected
|
|
18
|
+
* const error = new MyError(errorType, adapter);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function createTranslationAdapter<TStringKey extends string, TLanguage extends string>(
|
|
22
|
+
pluginEngine: PluginI18nEngine<TLanguage>,
|
|
23
|
+
componentId: string,
|
|
24
|
+
): TranslationEngine<TStringKey> {
|
|
25
|
+
return {
|
|
26
|
+
translate: (
|
|
27
|
+
key: TStringKey,
|
|
28
|
+
vars?: Record<string, string | number>,
|
|
29
|
+
lang?: TLanguage,
|
|
30
|
+
): string => {
|
|
31
|
+
try {
|
|
32
|
+
return pluginEngine.translate(componentId, key, vars, lang);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
// Fallback to key if translation fails
|
|
35
|
+
return String(key);
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
safeTranslate: (
|
|
40
|
+
key: TStringKey,
|
|
41
|
+
vars?: Record<string, string | number>,
|
|
42
|
+
lang?: TLanguage,
|
|
43
|
+
): string => {
|
|
44
|
+
return pluginEngine.safeTranslate(componentId, key, vars, lang);
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { codes } from 'currency-codes';
|
|
2
|
+
import { DefaultCurrencyCode } from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Class representing a validated currency code.
|
|
6
|
+
*/
|
|
7
|
+
export class CurrencyCode {
|
|
8
|
+
private _value: string = DefaultCurrencyCode;
|
|
9
|
+
/**
|
|
10
|
+
* Gets the currency code value.
|
|
11
|
+
*/
|
|
12
|
+
public get value(): string {
|
|
13
|
+
return this._value;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Sets the currency code value after validating it.
|
|
17
|
+
*/
|
|
18
|
+
public set value(value: string) {
|
|
19
|
+
if (!CurrencyCode.values.includes(value)) {
|
|
20
|
+
throw new Error('Invalid currency code');
|
|
21
|
+
}
|
|
22
|
+
this._value = value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Gets the list of all valid currency codes.
|
|
27
|
+
*/
|
|
28
|
+
public static get values(): string[] {
|
|
29
|
+
return codes();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
constructor(value: string = DefaultCurrencyCode) {
|
|
33
|
+
this.value = value;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { CurrencyPosition } from './types';
|
|
2
|
+
|
|
2
3
|
/**
|
|
3
4
|
* Represents the format details for a specific currency in a given locale.
|
|
4
5
|
*/
|
|
5
6
|
export interface CurrencyFormat {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
symbol: string;
|
|
8
|
+
position: CurrencyPosition;
|
|
9
|
+
groupSeparator: string;
|
|
10
|
+
decimalSeparator: string;
|
|
10
11
|
}
|
package/src/currency.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Currency formatting utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { CurrencyFormat } from './currency-format';
|
|
6
|
+
import { CurrencyPosition } from './types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get currency format details for a given locale and currency code.
|
|
10
|
+
* @param locale The locale string (e.g., 'en-US')
|
|
11
|
+
* @param currencyCode The ISO 4217 currency code (e.g., 'USD')
|
|
12
|
+
* @returns The currency format details
|
|
13
|
+
*/
|
|
14
|
+
export function getCurrencyFormat(
|
|
15
|
+
locale: string,
|
|
16
|
+
currencyCode: string,
|
|
17
|
+
): CurrencyFormat {
|
|
18
|
+
const formatter = new Intl.NumberFormat(locale, {
|
|
19
|
+
style: 'currency',
|
|
20
|
+
currency: currencyCode,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const parts = formatter.formatToParts(1234567.89);
|
|
24
|
+
const symbol = parts.find((part) => part.type === 'currency')?.value || '';
|
|
25
|
+
const symbolIndex = parts.findIndex((part) => part.type === 'currency');
|
|
26
|
+
const decimalIndex = parts.findIndex((part) => part.type === 'decimal');
|
|
27
|
+
const integerIndex = parts.findIndex((part) => part.type === 'integer');
|
|
28
|
+
|
|
29
|
+
let position: CurrencyPosition;
|
|
30
|
+
if (decimalIndex === -1) {
|
|
31
|
+
// No decimal separator
|
|
32
|
+
if (symbolIndex < integerIndex) {
|
|
33
|
+
position = 'prefix';
|
|
34
|
+
} else {
|
|
35
|
+
position = 'postfix';
|
|
36
|
+
}
|
|
37
|
+
} else if (symbolIndex < decimalIndex && symbolIndex < integerIndex) {
|
|
38
|
+
position = 'prefix';
|
|
39
|
+
} else if (symbolIndex > decimalIndex) {
|
|
40
|
+
position = 'postfix';
|
|
41
|
+
} else {
|
|
42
|
+
position = 'infix';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
symbol,
|
|
47
|
+
position,
|
|
48
|
+
groupSeparator: parts.find((part) => part.type === 'group')?.value || ',',
|
|
49
|
+
decimalSeparator:
|
|
50
|
+
parts.find((part) => part.type === 'decimal')?.value || '.',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { CurrencyCode } from './currency-code';
|
|
2
|
+
import { I18nConfig } from './i18n-config';
|
|
3
|
+
import { I18nContext } from './i18n-context';
|
|
4
|
+
import { I18nEngine } from './i18n-engine';
|
|
5
|
+
import { LanguageCodes } from './language-codes';
|
|
6
|
+
import { Timezone } from './timezone';
|
|
7
|
+
import {
|
|
8
|
+
DefaultCurrencyCode,
|
|
9
|
+
LanguageCodeCollection,
|
|
10
|
+
LanguageContextSpace,
|
|
11
|
+
} from './types';
|
|
12
|
+
|
|
13
|
+
// Default enum types that can be augmented by consumers
|
|
14
|
+
export enum DefaultStringKey {
|
|
15
|
+
Common_Test = 'common_test',
|
|
16
|
+
Error_InstanceAlreadyExistsTemplate = 'error_instanceAlreadyExistsTemplate',
|
|
17
|
+
Error_InstanceNotFoundTemplate = 'error_instanceNotFoundTemplate',
|
|
18
|
+
Error_MissingStringCollectionTemplate = 'error_missingStringCollectionTemplate',
|
|
19
|
+
Error_MissingTranslationTemplate = 'error_missingTranslationTemplate',
|
|
20
|
+
Error_DefaultLanguageNoCollectionTemplate = 'error_defaultLanguageNoCollectionTemplate',
|
|
21
|
+
Error_MissingTranslationKeyTemplate = 'error_missingTranslationKeyTemplate',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Default language codes used by the library
|
|
25
|
+
export type DefaultLanguageCode =
|
|
26
|
+
| typeof LanguageCodes.EN_US
|
|
27
|
+
| typeof LanguageCodes.EN_GB
|
|
28
|
+
| typeof LanguageCodes.FR
|
|
29
|
+
| typeof LanguageCodes.ES
|
|
30
|
+
| typeof LanguageCodes.ZH_CN
|
|
31
|
+
| typeof LanguageCodes.UK;
|
|
32
|
+
|
|
33
|
+
export const DefaultLanguageCodes: LanguageCodeCollection<DefaultLanguageCode> = {
|
|
34
|
+
[LanguageCodes.EN_US]: 'en-US',
|
|
35
|
+
[LanguageCodes.EN_GB]: 'en-GB',
|
|
36
|
+
[LanguageCodes.FR]: 'fr',
|
|
37
|
+
[LanguageCodes.ES]: 'es',
|
|
38
|
+
[LanguageCodes.ZH_CN]: 'zh-CN',
|
|
39
|
+
[LanguageCodes.UK]: 'uk',
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Global interface that can be augmented by consumers
|
|
43
|
+
declare global {
|
|
44
|
+
namespace I18n {
|
|
45
|
+
interface Config {
|
|
46
|
+
StringKey: DefaultStringKey;
|
|
47
|
+
Language: DefaultLanguageCode;
|
|
48
|
+
LanguageCodes: LanguageCodeCollection<DefaultLanguageCode>;
|
|
49
|
+
engine: I18nEngine<
|
|
50
|
+
I18n.Config['StringKey'],
|
|
51
|
+
I18n.Config['Language'],
|
|
52
|
+
Record<any, any>
|
|
53
|
+
>;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Convenient type aliases that automatically pick up augmented types
|
|
59
|
+
export type StringKey = I18n.Config['StringKey'];
|
|
60
|
+
export type Language = I18n.Config['Language'];
|
|
61
|
+
export type Engine = I18n.Config['engine'];
|
|
62
|
+
export type DefaultLanguageCodesType = I18n.Config['LanguageCodes'];
|
|
63
|
+
|
|
64
|
+
// Singleton instance that uses the augmented types
|
|
65
|
+
export const getI18nEngine = (): Engine => I18nEngine.getInstance() as Engine;
|
|
66
|
+
|
|
67
|
+
const getConfig = <
|
|
68
|
+
TConstants extends Record<string, any>,
|
|
69
|
+
>(
|
|
70
|
+
constants: TConstants,
|
|
71
|
+
timezone?: Timezone,
|
|
72
|
+
adminTimezone?: Timezone,
|
|
73
|
+
): I18nConfig<StringKey, Language, TConstants> => ({
|
|
74
|
+
strings: {
|
|
75
|
+
[LanguageCodes.EN_US]: {
|
|
76
|
+
[DefaultStringKey.Common_Test]: 'Test',
|
|
77
|
+
[DefaultStringKey.Error_InstanceAlreadyExistsTemplate]:
|
|
78
|
+
"Instance with key '{key}' already exists",
|
|
79
|
+
[DefaultStringKey.Error_InstanceNotFoundTemplate]:
|
|
80
|
+
"Instance with key '{key}' not found",
|
|
81
|
+
[DefaultStringKey.Error_MissingStringCollectionTemplate]:
|
|
82
|
+
'Missing string collection for language: {language}',
|
|
83
|
+
[DefaultStringKey.Error_MissingTranslationTemplate]:
|
|
84
|
+
"Missing translation for key '{key}' in language '{language}'",
|
|
85
|
+
[DefaultStringKey.Error_DefaultLanguageNoCollectionTemplate]:
|
|
86
|
+
"Default language '{language}' has no string collection",
|
|
87
|
+
[DefaultStringKey.Error_MissingTranslationKeyTemplate]:
|
|
88
|
+
'Missing translation key for type: {type}',
|
|
89
|
+
},
|
|
90
|
+
[LanguageCodes.EN_GB]: {
|
|
91
|
+
[DefaultStringKey.Common_Test]: 'Test',
|
|
92
|
+
[DefaultStringKey.Error_InstanceAlreadyExistsTemplate]:
|
|
93
|
+
"Instance with key '{key}' already exists",
|
|
94
|
+
[DefaultStringKey.Error_InstanceNotFoundTemplate]:
|
|
95
|
+
"Instance with key '{key}' not found",
|
|
96
|
+
[DefaultStringKey.Error_MissingStringCollectionTemplate]:
|
|
97
|
+
'Missing string collection for language: {language}',
|
|
98
|
+
[DefaultStringKey.Error_MissingTranslationTemplate]:
|
|
99
|
+
"Missing translation for key '{key}' in language '{language}'",
|
|
100
|
+
[DefaultStringKey.Error_DefaultLanguageNoCollectionTemplate]:
|
|
101
|
+
"Default language '{language}' has no string collection",
|
|
102
|
+
[DefaultStringKey.Error_MissingTranslationKeyTemplate]:
|
|
103
|
+
'Missing translation key for type: {type}',
|
|
104
|
+
},
|
|
105
|
+
[LanguageCodes.FR]: {
|
|
106
|
+
[DefaultStringKey.Common_Test]: 'Test',
|
|
107
|
+
[DefaultStringKey.Error_InstanceAlreadyExistsTemplate]:
|
|
108
|
+
"Instance avec clé '{key}' existe déjà",
|
|
109
|
+
[DefaultStringKey.Error_InstanceNotFoundTemplate]:
|
|
110
|
+
"Instance avec clé '{key}' introuvable",
|
|
111
|
+
[DefaultStringKey.Error_MissingStringCollectionTemplate]:
|
|
112
|
+
'Collection de chaînes manquante pour la langue: {language}',
|
|
113
|
+
[DefaultStringKey.Error_MissingTranslationTemplate]:
|
|
114
|
+
"Traduction manquante pour la clé '{key}' dans la langue '{language}'",
|
|
115
|
+
[DefaultStringKey.Error_DefaultLanguageNoCollectionTemplate]:
|
|
116
|
+
"La langue par défaut '{language}' n'a pas de collection de chaînes",
|
|
117
|
+
[DefaultStringKey.Error_MissingTranslationKeyTemplate]:
|
|
118
|
+
'Clé de traduction manquante pour le type: {type}',
|
|
119
|
+
},
|
|
120
|
+
[LanguageCodes.ZH_CN]: {
|
|
121
|
+
[DefaultStringKey.Common_Test]: '测试',
|
|
122
|
+
[DefaultStringKey.Error_InstanceAlreadyExistsTemplate]:
|
|
123
|
+
"键为'{key}'的实例已存在",
|
|
124
|
+
[DefaultStringKey.Error_InstanceNotFoundTemplate]:
|
|
125
|
+
"未找到键为'{key}'的实例",
|
|
126
|
+
[DefaultStringKey.Error_MissingStringCollectionTemplate]:
|
|
127
|
+
'缺少语言的字符串集合: {language}',
|
|
128
|
+
[DefaultStringKey.Error_MissingTranslationTemplate]:
|
|
129
|
+
"在语言'{language}'中缺少键'{key}'的翻译",
|
|
130
|
+
[DefaultStringKey.Error_DefaultLanguageNoCollectionTemplate]:
|
|
131
|
+
"默认语言'{language}'没有字符串集合",
|
|
132
|
+
[DefaultStringKey.Error_MissingTranslationKeyTemplate]:
|
|
133
|
+
'类型缺少翻译键: {type}',
|
|
134
|
+
},
|
|
135
|
+
[LanguageCodes.ES]: {
|
|
136
|
+
[DefaultStringKey.Common_Test]: 'Prueba',
|
|
137
|
+
[DefaultStringKey.Error_InstanceAlreadyExistsTemplate]:
|
|
138
|
+
"La instancia con clave '{key}' ya existe",
|
|
139
|
+
[DefaultStringKey.Error_InstanceNotFoundTemplate]:
|
|
140
|
+
"Instancia con clave '{key}' no encontrada",
|
|
141
|
+
[DefaultStringKey.Error_MissingStringCollectionTemplate]:
|
|
142
|
+
'Falta colección de cadenas para el idioma: {language}',
|
|
143
|
+
[DefaultStringKey.Error_MissingTranslationTemplate]:
|
|
144
|
+
"Falta traducción para la clave '{key}' en el idioma '{language}'",
|
|
145
|
+
[DefaultStringKey.Error_DefaultLanguageNoCollectionTemplate]:
|
|
146
|
+
"El idioma predeterminado '{language}' no tiene colección de cadenas",
|
|
147
|
+
[DefaultStringKey.Error_MissingTranslationKeyTemplate]:
|
|
148
|
+
'Falta clave de traducción para el tipo: {type}',
|
|
149
|
+
},
|
|
150
|
+
[LanguageCodes.UK]: {
|
|
151
|
+
[DefaultStringKey.Common_Test]: 'Тест',
|
|
152
|
+
[DefaultStringKey.Error_InstanceAlreadyExistsTemplate]:
|
|
153
|
+
"Екземпляр з ключем '{key}' вже існує",
|
|
154
|
+
[DefaultStringKey.Error_InstanceNotFoundTemplate]:
|
|
155
|
+
"Екземпляр з ключем '{key}' не знайдено",
|
|
156
|
+
[DefaultStringKey.Error_MissingStringCollectionTemplate]:
|
|
157
|
+
'Відсутня колекція рядків для мови: {language}',
|
|
158
|
+
[DefaultStringKey.Error_MissingTranslationTemplate]:
|
|
159
|
+
"Відсутній переклад для ключа '{key}' в мові '{language}'",
|
|
160
|
+
[DefaultStringKey.Error_DefaultLanguageNoCollectionTemplate]:
|
|
161
|
+
"Мова за замовчуванням '{language}' не має колекції рядків",
|
|
162
|
+
[DefaultStringKey.Error_MissingTranslationKeyTemplate]:
|
|
163
|
+
'Відсутній ключ перекладу для типу: {type}',
|
|
164
|
+
},
|
|
165
|
+
} as any,
|
|
166
|
+
stringNames: Object.values(DefaultStringKey),
|
|
167
|
+
defaultLanguage: LanguageCodes.EN_US,
|
|
168
|
+
defaultTranslationContext: 'user' as LanguageContextSpace,
|
|
169
|
+
defaultCurrencyCode: new CurrencyCode(DefaultCurrencyCode),
|
|
170
|
+
languageCodes: DefaultLanguageCodes,
|
|
171
|
+
languages: [LanguageCodes.EN_US, LanguageCodes.EN_GB, LanguageCodes.FR, LanguageCodes.ES, LanguageCodes.ZH_CN, LanguageCodes.UK],
|
|
172
|
+
constants: constants,
|
|
173
|
+
enumName: 'DefaultStringKey',
|
|
174
|
+
enumObj: DefaultStringKey as Record<string, DefaultStringKey>,
|
|
175
|
+
timezone: timezone ?? new Timezone('UTC'),
|
|
176
|
+
adminTimezone: adminTimezone ?? new Timezone('UTC'),
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
export const getDefaultI18nEngine = <
|
|
180
|
+
TConstants extends Record<string, any>,
|
|
181
|
+
TContext extends I18nContext<DefaultLanguageCode>,
|
|
182
|
+
>(
|
|
183
|
+
constants: TConstants,
|
|
184
|
+
timezone?: Timezone,
|
|
185
|
+
adminTimezone?: Timezone,
|
|
186
|
+
) =>
|
|
187
|
+
new I18nEngine<
|
|
188
|
+
DefaultStringKey,
|
|
189
|
+
DefaultLanguageCode,
|
|
190
|
+
TConstants,
|
|
191
|
+
TContext
|
|
192
|
+
>(
|
|
193
|
+
getConfig<TConstants>(
|
|
194
|
+
constants,
|
|
195
|
+
timezone,
|
|
196
|
+
adminTimezone,
|
|
197
|
+
),
|
|
198
|
+
'user' as LanguageContextSpace,
|
|
199
|
+
);
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { EnumLanguageTranslation } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Registry for managing enum translations across multiple languages.
|
|
5
|
+
*/
|
|
6
|
+
export class EnumTranslationRegistry<
|
|
7
|
+
TStringKey extends string,
|
|
8
|
+
TLanguage extends string,
|
|
9
|
+
> {
|
|
10
|
+
protected translations = new Map<
|
|
11
|
+
any,
|
|
12
|
+
EnumLanguageTranslation<any, TLanguage>
|
|
13
|
+
>();
|
|
14
|
+
protected enumNames = new WeakMap<any, string>();
|
|
15
|
+
protected availableLanguages: Set<TLanguage>;
|
|
16
|
+
protected translateFn?: (
|
|
17
|
+
key: TStringKey,
|
|
18
|
+
vars?: Record<string, any>,
|
|
19
|
+
) => string;
|
|
20
|
+
|
|
21
|
+
constructor(
|
|
22
|
+
availableLanguages: TLanguage[],
|
|
23
|
+
translateFn?: (key: TStringKey, vars?: Record<string, any>) => string,
|
|
24
|
+
) {
|
|
25
|
+
this.availableLanguages = new Set(availableLanguages);
|
|
26
|
+
this.translateFn = translateFn;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Registers an enumeration with its translations and a name.
|
|
31
|
+
* @param enumObj The enumeration object
|
|
32
|
+
* @param translations The translations for the enumeration
|
|
33
|
+
* @param enumName The name of the enumeration
|
|
34
|
+
*/
|
|
35
|
+
public register<TEnum extends string | number>(
|
|
36
|
+
enumObj: Record<string, TEnum>,
|
|
37
|
+
translations: EnumLanguageTranslation<TEnum, TLanguage>,
|
|
38
|
+
enumName: string,
|
|
39
|
+
): void {
|
|
40
|
+
this.validateTranslations(translations, enumName);
|
|
41
|
+
this.translations.set(enumObj, translations);
|
|
42
|
+
this.enumNames.set(enumObj, enumName);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Translates a value from the given enumeration to the specified language.
|
|
47
|
+
* @param enumObj The enumeration object
|
|
48
|
+
* @param value The value to translate
|
|
49
|
+
* @param language The target language for translation
|
|
50
|
+
* @returns The translated string
|
|
51
|
+
*/
|
|
52
|
+
public translate<TEnum extends string | number>(
|
|
53
|
+
enumObj: Record<string, TEnum>,
|
|
54
|
+
value: TEnum,
|
|
55
|
+
language: TLanguage,
|
|
56
|
+
): string {
|
|
57
|
+
const translations = this.translations.get(enumObj);
|
|
58
|
+
if (!translations) {
|
|
59
|
+
const message = this.translateFn
|
|
60
|
+
? this.translateFn('Error_EnumNotFoundTemplate' as TStringKey, {
|
|
61
|
+
enumName: this.getEnumName(enumObj),
|
|
62
|
+
})
|
|
63
|
+
: `No translations found for enum: ${this.getEnumName(enumObj)}`;
|
|
64
|
+
throw new Error(message);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const langTranslations = translations[language];
|
|
68
|
+
if (!langTranslations) {
|
|
69
|
+
const message = this.translateFn
|
|
70
|
+
? this.translateFn('Error_EnumLanguageNotFoundTemplate' as TStringKey, {
|
|
71
|
+
language,
|
|
72
|
+
})
|
|
73
|
+
: `No translations found for language: ${language}`;
|
|
74
|
+
throw new Error(message);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let result = langTranslations[value];
|
|
78
|
+
if (!result && typeof value === 'number') {
|
|
79
|
+
const stringKey = Object.keys(enumObj).find(
|
|
80
|
+
(key) => enumObj[key] === value,
|
|
81
|
+
);
|
|
82
|
+
if (stringKey) {
|
|
83
|
+
result = langTranslations[stringKey as TEnum];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!result) {
|
|
88
|
+
const message = this.translateFn
|
|
89
|
+
? this.translateFn('Error_EnumValueNotFoundTemplate' as TStringKey, {
|
|
90
|
+
value: String(value),
|
|
91
|
+
})
|
|
92
|
+
: `No translation found for value: ${String(value)}`;
|
|
93
|
+
throw new Error(message);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Gets the name of the enumeration.
|
|
101
|
+
* @param enumObj The enumeration object
|
|
102
|
+
* @returns The name of the enumeration
|
|
103
|
+
*/
|
|
104
|
+
private getEnumName(enumObj: any): string {
|
|
105
|
+
return this.enumNames.get(enumObj) || 'UnknownEnum';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Checks if the registry has translations for the given enumeration.
|
|
110
|
+
* @param enumObj The enumeration object
|
|
111
|
+
* @returns True if translations exist, false otherwise
|
|
112
|
+
*/
|
|
113
|
+
has(enumObj: any): boolean {
|
|
114
|
+
return this.translations.has(enumObj);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Validates that enum translations only contain available languages.
|
|
119
|
+
* @param translations The translations to validate
|
|
120
|
+
* @param enumName The name of the enumeration for error messages
|
|
121
|
+
*/
|
|
122
|
+
private validateTranslations<TEnum extends string | number>(
|
|
123
|
+
translations: EnumLanguageTranslation<TEnum, TLanguage>,
|
|
124
|
+
enumName: string,
|
|
125
|
+
): void {
|
|
126
|
+
for (const language of Object.keys(translations) as TLanguage[]) {
|
|
127
|
+
if (!this.availableLanguages.has(language)) {
|
|
128
|
+
const message = this.translateFn
|
|
129
|
+
? this.translateFn(
|
|
130
|
+
'Error_EnumLanguageNotAvailableTemplate' as TStringKey,
|
|
131
|
+
{ language, enumName },
|
|
132
|
+
)
|
|
133
|
+
: `Language '${language}' in enum '${enumName}' is not available in this engine instance`;
|
|
134
|
+
throw new Error(message);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|