@digitaldefiance/i18n-lib 3.7.5 → 3.8.1
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/README.md +261 -0
- package/package.json +12 -4
- package/src/active-context.ts +4 -0
- package/src/builders/i18n-builder.ts +82 -0
- package/src/builders/{index.d.ts → index.ts} +1 -1
- package/src/component-definition.ts +11 -0
- package/src/component-registration.ts +29 -0
- package/src/component-registry.ts +432 -0
- package/src/context-error-type.ts +7 -0
- package/src/core/component-store.ts +241 -0
- package/src/core/context-manager.ts +113 -0
- package/src/core/enum-registry.ts +106 -0
- package/src/core/i18n-engine.ts +710 -0
- package/src/core/index.ts +16 -0
- package/src/core/language-registry.ts +345 -0
- package/src/core-component-id.ts +5 -0
- package/src/core-i18n.ts +270 -0
- package/src/core-plugin-factory.ts +111 -0
- package/src/core-string-key.ts +59 -0
- package/src/create-translation-adapter.ts +93 -0
- package/src/enum-registry.ts +152 -0
- package/src/errors/base.ts +8 -0
- package/src/errors/context-error.ts +122 -0
- package/src/errors/enhanced-error-base.ts +260 -0
- package/src/errors/handleable.ts +152 -0
- package/src/errors/i18n-error.ts +494 -0
- package/src/errors/index.ts +15 -0
- package/src/errors/simple-typed-error.ts +81 -0
- package/src/errors/{index.d.ts → translatable-exports.ts} +3 -5
- package/src/errors/translatable-generic.ts +245 -0
- package/src/errors/translatable-handleable-generic.ts +222 -0
- package/src/errors/translatable.ts +138 -0
- package/src/errors/typed-handleable.ts +138 -0
- package/src/errors/typed.ts +617 -0
- package/src/gender/{gender-categories.d.ts → gender-categories.ts} +6 -2
- package/src/gender/gender-resolver.ts +40 -0
- package/src/gender/{index.d.ts → index.ts} +0 -1
- package/src/global-active-context.ts +266 -0
- package/src/icu/ast.ts +56 -0
- package/src/icu/compiler.ts +96 -0
- package/src/icu/formatter-registry.ts +36 -0
- package/src/icu/formatters/base-formatter.ts +8 -0
- package/src/icu/formatters/date-formatter.ts +30 -0
- package/src/icu/formatters/number-formatter.ts +32 -0
- package/src/icu/formatters/plural-formatter.ts +12 -0
- package/src/icu/formatters/select-formatter.ts +7 -0
- package/src/icu/formatters/selectordinal-formatter.ts +17 -0
- package/src/icu/formatters/time-formatter.ts +30 -0
- package/src/icu/helpers.ts +34 -0
- package/src/icu/parser.ts +242 -0
- package/src/icu/runtime.ts +37 -0
- package/src/icu/tokenizer.ts +212 -0
- package/src/icu/validator.ts +163 -0
- package/src/{index.d.ts → index.ts} +46 -14
- package/src/interfaces/active-context.interface.ts +41 -0
- package/src/interfaces/component-config.interface.ts +17 -0
- package/src/interfaces/engine-config.interface.ts +22 -0
- package/src/interfaces/global-active-context.ts +39 -0
- package/src/interfaces/handleable-error-options.ts +13 -0
- package/src/interfaces/handleable.ts +20 -0
- package/src/interfaces/i18n-engine.interface.ts +57 -0
- package/src/interfaces/index.ts +13 -0
- package/src/interfaces/language-definition.interface.ts +17 -0
- package/src/interfaces/translation-options.interface.ts +15 -0
- package/src/interfaces/validation-result.interface.ts +24 -0
- package/src/language-codes.ts +40 -0
- package/src/language-definition.ts +13 -0
- package/src/plugin-i18n-engine.ts +707 -0
- package/src/pluralization/{index.d.ts → index.ts} +1 -1
- package/src/pluralization/language-plural-map.ts +186 -0
- package/src/pluralization/{plural-categories.d.ts → plural-categories.ts} +5 -3
- package/src/pluralization/plural-rules.ts +228 -0
- package/src/registry-config.ts +16 -0
- package/src/registry-error-type.ts +19 -0
- package/src/registry-error.ts +100 -0
- package/src/strict-types.ts +35 -0
- package/src/strings/de.ts +75 -0
- package/src/strings/en-GB.ts +74 -0
- package/src/strings/en-US.ts +74 -0
- package/src/strings/es.ts +74 -0
- package/src/strings/fr.ts +75 -0
- package/src/strings/ja.ts +73 -0
- package/src/strings/uk.ts +73 -0
- package/src/strings/zh-CN.ts +72 -0
- package/src/template.ts +72 -0
- package/src/translation-engine.ts +18 -0
- package/src/translation-request.ts +12 -0
- package/src/translation-response.ts +8 -0
- package/src/types/engine.ts +55 -0
- package/src/types/{index.d.ts → index.ts} +1 -1
- package/src/types/{plural-types.d.ts → plural-types.ts} +29 -3
- package/src/types.ts +142 -0
- package/src/utils/currency.ts +141 -0
- package/src/utils/html-escape.ts +55 -0
- package/src/utils/{index.d.ts → index.ts} +0 -1
- package/src/utils/lru-cache.ts +76 -0
- package/src/utils/{plural-helpers.d.ts → plural-helpers.ts} +14 -4
- package/src/utils/{safe-object.js → safe-object.ts} +37 -34
- package/src/utils/string-utils.ts +77 -0
- package/src/utils/timezone.ts +76 -0
- package/src/utils/validation.ts +66 -0
- package/src/utils.ts +215 -0
- package/src/validation/{index.d.ts → index.ts} +0 -1
- package/src/validation/plural-validator.ts +168 -0
- package/src/validation-config.ts +11 -0
- package/src/validation-result.ts +12 -0
- package/src/active-context.d.ts +0 -36
- package/src/active-context.d.ts.map +0 -1
- package/src/active-context.js +0 -3
- package/src/active-context.js.map +0 -1
- package/src/builders/i18n-builder.d.ts +0 -26
- package/src/builders/i18n-builder.d.ts.map +0 -1
- package/src/builders/i18n-builder.js +0 -70
- package/src/builders/i18n-builder.js.map +0 -1
- package/src/builders/index.d.ts.map +0 -1
- package/src/builders/index.js +0 -8
- package/src/builders/index.js.map +0 -1
- package/src/component-definition.d.ts +0 -12
- package/src/component-definition.d.ts.map +0 -1
- package/src/component-definition.js +0 -3
- package/src/component-definition.js.map +0 -1
- package/src/component-registration.d.ts +0 -13
- package/src/component-registration.d.ts.map +0 -1
- package/src/component-registration.js +0 -3
- package/src/component-registration.js.map +0 -1
- package/src/component-registry.d.ts +0 -102
- package/src/component-registry.d.ts.map +0 -1
- package/src/component-registry.js +0 -282
- package/src/component-registry.js.map +0 -1
- package/src/context-error-type.d.ts +0 -8
- package/src/context-error-type.d.ts.map +0 -1
- package/src/context-error-type.js +0 -12
- package/src/context-error-type.js.map +0 -1
- package/src/core/component-store.d.ts +0 -93
- package/src/core/component-store.d.ts.map +0 -1
- package/src/core/component-store.js +0 -198
- package/src/core/component-store.js.map +0 -1
- package/src/core/context-manager.d.ts +0 -72
- package/src/core/context-manager.d.ts.map +0 -1
- package/src/core/context-manager.js +0 -98
- package/src/core/context-manager.js.map +0 -1
- package/src/core/enum-registry.d.ts +0 -48
- package/src/core/enum-registry.d.ts.map +0 -1
- package/src/core/enum-registry.js +0 -85
- package/src/core/enum-registry.js.map +0 -1
- package/src/core/i18n-engine.d.ts +0 -241
- package/src/core/i18n-engine.d.ts.map +0 -1
- package/src/core/i18n-engine.js +0 -568
- package/src/core/i18n-engine.js.map +0 -1
- package/src/core/index.d.ts +0 -9
- package/src/core/index.d.ts.map +0 -1
- package/src/core/index.js +0 -12
- package/src/core/index.js.map +0 -1
- package/src/core/language-registry.d.ts +0 -180
- package/src/core/language-registry.d.ts.map +0 -1
- package/src/core/language-registry.js +0 -295
- package/src/core/language-registry.js.map +0 -1
- package/src/core-i18n.d.ts +0 -91
- package/src/core-i18n.d.ts.map +0 -1
- package/src/core-i18n.js +0 -287
- package/src/core-i18n.js.map +0 -1
- package/src/core-string-key.d.ts +0 -52
- package/src/core-string-key.d.ts.map +0 -1
- package/src/core-string-key.js +0 -61
- package/src/core-string-key.js.map +0 -1
- package/src/create-translation-adapter.d.ts +0 -33
- package/src/create-translation-adapter.d.ts.map +0 -1
- package/src/create-translation-adapter.js +0 -72
- package/src/create-translation-adapter.js.map +0 -1
- package/src/enum-registry.d.ts +0 -65
- package/src/enum-registry.d.ts.map +0 -1
- package/src/enum-registry.js +0 -123
- package/src/enum-registry.js.map +0 -1
- package/src/errors/context-error.d.ts +0 -50
- package/src/errors/context-error.d.ts.map +0 -1
- package/src/errors/context-error.js +0 -75
- package/src/errors/context-error.js.map +0 -1
- package/src/errors/enhanced-error-base.d.ts +0 -125
- package/src/errors/enhanced-error-base.d.ts.map +0 -1
- package/src/errors/enhanced-error-base.js +0 -165
- package/src/errors/enhanced-error-base.js.map +0 -1
- package/src/errors/handleable.d.ts +0 -83
- package/src/errors/handleable.d.ts.map +0 -1
- package/src/errors/handleable.js +0 -136
- package/src/errors/handleable.js.map +0 -1
- package/src/errors/i18n-error.d.ts +0 -211
- package/src/errors/i18n-error.d.ts.map +0 -1
- package/src/errors/i18n-error.js +0 -358
- package/src/errors/i18n-error.js.map +0 -1
- package/src/errors/index.d.ts.map +0 -1
- package/src/errors/index.js +0 -17
- package/src/errors/index.js.map +0 -1
- package/src/errors/simple-typed-error.d.ts +0 -53
- package/src/errors/simple-typed-error.d.ts.map +0 -1
- package/src/errors/simple-typed-error.js +0 -51
- package/src/errors/simple-typed-error.js.map +0 -1
- package/src/errors/translatable-generic.d.ts +0 -84
- package/src/errors/translatable-generic.d.ts.map +0 -1
- package/src/errors/translatable-generic.js +0 -134
- package/src/errors/translatable-generic.js.map +0 -1
- package/src/errors/translatable-handleable-generic.d.ts +0 -116
- package/src/errors/translatable-handleable-generic.d.ts.map +0 -1
- package/src/errors/translatable-handleable-generic.js +0 -121
- package/src/errors/translatable-handleable-generic.js.map +0 -1
- package/src/errors/translatable.d.ts +0 -59
- package/src/errors/translatable.d.ts.map +0 -1
- package/src/errors/translatable.js +0 -80
- package/src/errors/translatable.js.map +0 -1
- package/src/errors/typed-handleable.d.ts +0 -62
- package/src/errors/typed-handleable.d.ts.map +0 -1
- package/src/errors/typed-handleable.js +0 -106
- package/src/errors/typed-handleable.js.map +0 -1
- package/src/errors/typed.d.ts +0 -206
- package/src/errors/typed.d.ts.map +0 -1
- package/src/errors/typed.js +0 -452
- package/src/errors/typed.js.map +0 -1
- package/src/gender/gender-categories.d.ts.map +0 -1
- package/src/gender/gender-categories.js +0 -15
- package/src/gender/gender-categories.js.map +0 -1
- package/src/gender/gender-resolver.d.ts +0 -14
- package/src/gender/gender-resolver.d.ts.map +0 -1
- package/src/gender/gender-resolver.js +0 -35
- package/src/gender/gender-resolver.js.map +0 -1
- package/src/gender/index.d.ts.map +0 -1
- package/src/gender/index.js +0 -6
- package/src/gender/index.js.map +0 -1
- package/src/global-active-context.d.ts +0 -50
- package/src/global-active-context.d.ts.map +0 -1
- package/src/global-active-context.js +0 -185
- package/src/global-active-context.js.map +0 -1
- package/src/icu/ast.d.ts +0 -48
- package/src/icu/ast.d.ts.map +0 -1
- package/src/icu/ast.js +0 -16
- package/src/icu/ast.js.map +0 -1
- package/src/icu/compiler.d.ts +0 -16
- package/src/icu/compiler.d.ts.map +0 -1
- package/src/icu/compiler.js +0 -87
- package/src/icu/compiler.js.map +0 -1
- package/src/icu/formatter-registry.d.ts +0 -10
- package/src/icu/formatter-registry.d.ts.map +0 -1
- package/src/icu/formatter-registry.js +0 -34
- package/src/icu/formatter-registry.js.map +0 -1
- package/src/icu/formatters/base-formatter.d.ts +0 -8
- package/src/icu/formatters/base-formatter.d.ts.map +0 -1
- package/src/icu/formatters/base-formatter.js +0 -3
- package/src/icu/formatters/base-formatter.js.map +0 -1
- package/src/icu/formatters/date-formatter.d.ts +0 -5
- package/src/icu/formatters/date-formatter.d.ts.map +0 -1
- package/src/icu/formatters/date-formatter.js +0 -31
- package/src/icu/formatters/date-formatter.js.map +0 -1
- package/src/icu/formatters/number-formatter.d.ts +0 -5
- package/src/icu/formatters/number-formatter.d.ts.map +0 -1
- package/src/icu/formatters/number-formatter.js +0 -33
- package/src/icu/formatters/number-formatter.js.map +0 -1
- package/src/icu/formatters/plural-formatter.d.ts +0 -5
- package/src/icu/formatters/plural-formatter.d.ts.map +0 -1
- package/src/icu/formatters/plural-formatter.js +0 -15
- package/src/icu/formatters/plural-formatter.js.map +0 -1
- package/src/icu/formatters/select-formatter.d.ts +0 -5
- package/src/icu/formatters/select-formatter.d.ts.map +0 -1
- package/src/icu/formatters/select-formatter.js +0 -10
- package/src/icu/formatters/select-formatter.js.map +0 -1
- package/src/icu/formatters/selectordinal-formatter.d.ts +0 -5
- package/src/icu/formatters/selectordinal-formatter.d.ts.map +0 -1
- package/src/icu/formatters/selectordinal-formatter.js +0 -22
- package/src/icu/formatters/selectordinal-formatter.js.map +0 -1
- package/src/icu/formatters/time-formatter.d.ts +0 -5
- package/src/icu/formatters/time-formatter.d.ts.map +0 -1
- package/src/icu/formatters/time-formatter.js +0 -31
- package/src/icu/formatters/time-formatter.js.map +0 -1
- package/src/icu/helpers.d.ts +0 -9
- package/src/icu/helpers.d.ts.map +0 -1
- package/src/icu/helpers.js +0 -31
- package/src/icu/helpers.js.map +0 -1
- package/src/icu/parser.d.ts +0 -31
- package/src/icu/parser.d.ts.map +0 -1
- package/src/icu/parser.js +0 -203
- package/src/icu/parser.js.map +0 -1
- package/src/icu/runtime.d.ts +0 -10
- package/src/icu/runtime.d.ts.map +0 -1
- package/src/icu/runtime.js +0 -33
- package/src/icu/runtime.js.map +0 -1
- package/src/icu/tokenizer.d.ts +0 -37
- package/src/icu/tokenizer.d.ts.map +0 -1
- package/src/icu/tokenizer.js +0 -187
- package/src/icu/tokenizer.js.map +0 -1
- package/src/icu/validator.d.ts +0 -11
- package/src/icu/validator.d.ts.map +0 -1
- package/src/icu/validator.js +0 -140
- package/src/icu/validator.js.map +0 -1
- package/src/index.d.ts.map +0 -1
- package/src/index.js +0 -76
- package/src/index.js.map +0 -1
- package/src/interfaces/component-config.interface.d.ts +0 -16
- package/src/interfaces/component-config.interface.d.ts.map +0 -1
- package/src/interfaces/component-config.interface.js +0 -6
- package/src/interfaces/component-config.interface.js.map +0 -1
- package/src/interfaces/engine-config.interface.d.ts +0 -22
- package/src/interfaces/engine-config.interface.d.ts.map +0 -1
- package/src/interfaces/engine-config.interface.js +0 -6
- package/src/interfaces/engine-config.interface.js.map +0 -1
- package/src/interfaces/global-active-context.d.ts +0 -23
- package/src/interfaces/global-active-context.d.ts.map +0 -1
- package/src/interfaces/global-active-context.js +0 -3
- package/src/interfaces/global-active-context.js.map +0 -1
- package/src/interfaces/handleable-error-options.d.ts +0 -14
- package/src/interfaces/handleable-error-options.d.ts.map +0 -1
- package/src/interfaces/handleable-error-options.js +0 -3
- package/src/interfaces/handleable-error-options.js.map +0 -1
- package/src/interfaces/handleable.d.ts +0 -21
- package/src/interfaces/handleable.d.ts.map +0 -1
- package/src/interfaces/handleable.js +0 -3
- package/src/interfaces/handleable.js.map +0 -1
- package/src/interfaces/i18n-engine.interface.d.ts +0 -46
- package/src/interfaces/i18n-engine.interface.d.ts.map +0 -1
- package/src/interfaces/i18n-engine.interface.js +0 -6
- package/src/interfaces/i18n-engine.interface.js.map +0 -1
- package/src/interfaces/index.d.ts +0 -11
- package/src/interfaces/index.d.ts.map +0 -1
- package/src/interfaces/index.js +0 -14
- package/src/interfaces/index.js.map +0 -1
- package/src/interfaces/language-definition.interface.d.ts +0 -17
- package/src/interfaces/language-definition.interface.d.ts.map +0 -1
- package/src/interfaces/language-definition.interface.js +0 -6
- package/src/interfaces/language-definition.interface.js.map +0 -1
- package/src/interfaces/translation-options.interface.d.ts +0 -15
- package/src/interfaces/translation-options.interface.d.ts.map +0 -1
- package/src/interfaces/translation-options.interface.js +0 -6
- package/src/interfaces/translation-options.interface.js.map +0 -1
- package/src/interfaces/validation-result.interface.d.ts +0 -24
- package/src/interfaces/validation-result.interface.d.ts.map +0 -1
- package/src/interfaces/validation-result.interface.js +0 -6
- package/src/interfaces/validation-result.interface.js.map +0 -1
- package/src/language-codes.d.ts +0 -28
- package/src/language-codes.d.ts.map +0 -1
- package/src/language-codes.js +0 -32
- package/src/language-codes.js.map +0 -1
- package/src/language-definition.d.ts +0 -14
- package/src/language-definition.d.ts.map +0 -1
- package/src/language-definition.js +0 -3
- package/src/language-definition.js.map +0 -1
- package/src/plugin-i18n-engine.d.ts +0 -164
- package/src/plugin-i18n-engine.d.ts.map +0 -1
- package/src/plugin-i18n-engine.js +0 -489
- package/src/plugin-i18n-engine.js.map +0 -1
- package/src/pluralization/index.d.ts.map +0 -1
- package/src/pluralization/index.js +0 -10
- package/src/pluralization/index.js.map +0 -1
- package/src/pluralization/language-plural-map.d.ts +0 -29
- package/src/pluralization/language-plural-map.d.ts.map +0 -1
- package/src/pluralization/language-plural-map.js +0 -155
- package/src/pluralization/language-plural-map.js.map +0 -1
- package/src/pluralization/plural-categories.d.ts.map +0 -1
- package/src/pluralization/plural-categories.js +0 -8
- package/src/pluralization/plural-categories.js.map +0 -1
- package/src/pluralization/plural-rules.d.ts +0 -102
- package/src/pluralization/plural-rules.d.ts.map +0 -1
- package/src/pluralization/plural-rules.js +0 -263
- package/src/pluralization/plural-rules.js.map +0 -1
- package/src/registry-config.d.ts +0 -16
- package/src/registry-config.d.ts.map +0 -1
- package/src/registry-config.js +0 -3
- package/src/registry-config.js.map +0 -1
- package/src/registry-error-type.d.ts +0 -20
- package/src/registry-error-type.d.ts.map +0 -1
- package/src/registry-error-type.js +0 -24
- package/src/registry-error-type.js.map +0 -1
- package/src/registry-error.d.ts +0 -19
- package/src/registry-error.d.ts.map +0 -1
- package/src/registry-error.js +0 -49
- package/src/registry-error.js.map +0 -1
- package/src/strict-types.d.ts +0 -19
- package/src/strict-types.d.ts.map +0 -1
- package/src/strict-types.js +0 -18
- package/src/strict-types.js.map +0 -1
- package/src/strings/de.d.ts +0 -3
- package/src/strings/de.d.ts.map +0 -1
- package/src/strings/de.js +0 -57
- package/src/strings/de.js.map +0 -1
- package/src/strings/en-GB.d.ts +0 -3
- package/src/strings/en-GB.d.ts.map +0 -1
- package/src/strings/en-GB.js +0 -57
- package/src/strings/en-GB.js.map +0 -1
- package/src/strings/en-US.d.ts +0 -3
- package/src/strings/en-US.d.ts.map +0 -1
- package/src/strings/en-US.js +0 -57
- package/src/strings/en-US.js.map +0 -1
- package/src/strings/es.d.ts +0 -3
- package/src/strings/es.d.ts.map +0 -1
- package/src/strings/es.js +0 -57
- package/src/strings/es.js.map +0 -1
- package/src/strings/fr.d.ts +0 -3
- package/src/strings/fr.d.ts.map +0 -1
- package/src/strings/fr.js +0 -57
- package/src/strings/fr.js.map +0 -1
- package/src/strings/ja.d.ts +0 -3
- package/src/strings/ja.d.ts.map +0 -1
- package/src/strings/ja.js +0 -57
- package/src/strings/ja.js.map +0 -1
- package/src/strings/uk.d.ts +0 -3
- package/src/strings/uk.d.ts.map +0 -1
- package/src/strings/uk.js +0 -57
- package/src/strings/uk.js.map +0 -1
- package/src/strings/zh-CN.d.ts +0 -3
- package/src/strings/zh-CN.d.ts.map +0 -1
- package/src/strings/zh-CN.js +0 -57
- package/src/strings/zh-CN.js.map +0 -1
- package/src/template.d.ts +0 -13
- package/src/template.d.ts.map +0 -1
- package/src/template.js +0 -40
- package/src/template.js.map +0 -1
- package/src/translation-engine.d.ts +0 -9
- package/src/translation-engine.d.ts.map +0 -1
- package/src/translation-engine.js +0 -3
- package/src/translation-engine.js.map +0 -1
- package/src/translation-request.d.ts +0 -10
- package/src/translation-request.d.ts.map +0 -1
- package/src/translation-request.js +0 -3
- package/src/translation-request.js.map +0 -1
- package/src/translation-response.d.ts +0 -9
- package/src/translation-response.d.ts.map +0 -1
- package/src/translation-response.js +0 -3
- package/src/translation-response.js.map +0 -1
- package/src/types/engine.d.ts +0 -47
- package/src/types/engine.d.ts.map +0 -1
- package/src/types/engine.js +0 -8
- package/src/types/engine.js.map +0 -1
- package/src/types/index.d.ts.map +0 -1
- package/src/types/index.js +0 -9
- package/src/types/index.js.map +0 -1
- package/src/types/plural-types.d.ts.map +0 -1
- package/src/types/plural-types.js +0 -39
- package/src/types/plural-types.js.map +0 -1
- package/src/types.d.ts +0 -96
- package/src/types.d.ts.map +0 -1
- package/src/types.js +0 -23
- package/src/types.js.map +0 -1
- package/src/utils/currency.d.ts +0 -81
- package/src/utils/currency.d.ts.map +0 -1
- package/src/utils/currency.js +0 -101
- package/src/utils/currency.js.map +0 -1
- package/src/utils/html-escape.d.ts +0 -22
- package/src/utils/html-escape.d.ts.map +0 -1
- package/src/utils/html-escape.js +0 -53
- package/src/utils/html-escape.js.map +0 -1
- package/src/utils/index.d.ts.map +0 -1
- package/src/utils/index.js +0 -12
- package/src/utils/index.js.map +0 -1
- package/src/utils/lru-cache.d.ts +0 -42
- package/src/utils/lru-cache.d.ts.map +0 -1
- package/src/utils/lru-cache.js +0 -73
- package/src/utils/lru-cache.js.map +0 -1
- package/src/utils/plural-helpers.d.ts.map +0 -1
- package/src/utils/plural-helpers.js +0 -35
- package/src/utils/plural-helpers.js.map +0 -1
- package/src/utils/safe-object.d.ts +0 -39
- package/src/utils/safe-object.d.ts.map +0 -1
- package/src/utils/safe-object.js.map +0 -1
- package/src/utils/string-utils.d.ts +0 -28
- package/src/utils/string-utils.d.ts.map +0 -1
- package/src/utils/string-utils.js +0 -63
- package/src/utils/string-utils.js.map +0 -1
- package/src/utils/timezone.d.ts +0 -50
- package/src/utils/timezone.d.ts.map +0 -1
- package/src/utils/timezone.js +0 -74
- package/src/utils/timezone.js.map +0 -1
- package/src/utils/validation.d.ts +0 -40
- package/src/utils/validation.d.ts.map +0 -1
- package/src/utils/validation.js +0 -69
- package/src/utils/validation.js.map +0 -1
- package/src/utils.d.ts +0 -65
- package/src/utils.d.ts.map +0 -1
- package/src/utils.js +0 -129
- package/src/utils.js.map +0 -1
- package/src/validation/index.d.ts.map +0 -1
- package/src/validation/index.js +0 -5
- package/src/validation/index.js.map +0 -1
- package/src/validation/plural-validator.d.ts +0 -46
- package/src/validation/plural-validator.d.ts.map +0 -1
- package/src/validation/plural-validator.js +0 -123
- package/src/validation/plural-validator.js.map +0 -1
- package/src/validation-config.d.ts +0 -12
- package/src/validation-config.d.ts.map +0 -1
- package/src/validation-config.js +0 -3
- package/src/validation-config.js.map +0 -1
- package/src/validation-result.d.ts +0 -13
- package/src/validation-result.d.ts.map +0 -1
- package/src/validation-result.js +0 -3
- package/src/validation-result.js.map +0 -1
|
@@ -0,0 +1,710 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main I18n Engine (no generics)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { CoreI18nComponentId } from '../core-component-id';
|
|
6
|
+
import { I18nError } from '../errors/i18n-error';
|
|
7
|
+
import {
|
|
8
|
+
ComponentConfig,
|
|
9
|
+
EngineConfig,
|
|
10
|
+
II18nEngine,
|
|
11
|
+
LanguageDefinition,
|
|
12
|
+
ValidationResult,
|
|
13
|
+
} from '../interfaces';
|
|
14
|
+
import { CurrencyCode } from '../utils/currency';
|
|
15
|
+
import {
|
|
16
|
+
createSafeObject,
|
|
17
|
+
safeAssign,
|
|
18
|
+
validateObjectKeys,
|
|
19
|
+
} from '../utils/safe-object';
|
|
20
|
+
import { Timezone } from '../utils/timezone';
|
|
21
|
+
import {
|
|
22
|
+
validateComponentId,
|
|
23
|
+
validateTemplateLength,
|
|
24
|
+
} from '../utils/validation';
|
|
25
|
+
import { ComponentStore } from './component-store';
|
|
26
|
+
import { ContextManager } from './context-manager';
|
|
27
|
+
import { EnumRegistry } from './enum-registry';
|
|
28
|
+
import { LanguageRegistry } from './language-registry';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* I18nEngine implements the II18nEngine interface, providing translation,
|
|
32
|
+
* component registration, enum translation, and context management.
|
|
33
|
+
*/
|
|
34
|
+
export class I18nEngine implements II18nEngine {
|
|
35
|
+
private static instances = new Map<string, I18nEngine>();
|
|
36
|
+
private static defaultKey: string | null = null;
|
|
37
|
+
private static readonly DEFAULT_KEY = 'default';
|
|
38
|
+
private static readonly contextManager = new ContextManager();
|
|
39
|
+
|
|
40
|
+
private readonly componentStore: ComponentStore;
|
|
41
|
+
private readonly enumRegistry: EnumRegistry;
|
|
42
|
+
private readonly instanceKey: string;
|
|
43
|
+
private readonly config: Required<EngineConfig>;
|
|
44
|
+
private readonly aliasToComponent = new Map<string, string>();
|
|
45
|
+
private readonly componentKeyLookup = new Map<string, Map<string, string>>();
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Constructs an I18nEngine instance, registering languages, setting defaults,
|
|
49
|
+
* and optionally registering and setting this instance as default.
|
|
50
|
+
*
|
|
51
|
+
* @param languages - Array of language definitions to register.
|
|
52
|
+
* @param config - Engine configuration options.
|
|
53
|
+
* @param options - Optional creation options.
|
|
54
|
+
* @param options.instanceKey - Key to identify this instance.
|
|
55
|
+
* @param options.registerInstance - Whether to add this instance to the registry.
|
|
56
|
+
* @param options.setAsDefault - Whether to set this instance as the default.
|
|
57
|
+
* @throws {I18nError} If an instance with the same key already exists.
|
|
58
|
+
*/
|
|
59
|
+
constructor(
|
|
60
|
+
languages: readonly LanguageDefinition[],
|
|
61
|
+
config: EngineConfig = {},
|
|
62
|
+
options?: {
|
|
63
|
+
instanceKey?: string;
|
|
64
|
+
registerInstance?: boolean;
|
|
65
|
+
setAsDefault?: boolean;
|
|
66
|
+
},
|
|
67
|
+
) {
|
|
68
|
+
// Register languages
|
|
69
|
+
for (const lang of languages) {
|
|
70
|
+
if (!LanguageRegistry.has(lang.id)) {
|
|
71
|
+
LanguageRegistry.register(lang);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Set defaults
|
|
76
|
+
const defaultLang = languages.find((l) => l.isDefault) || languages[0];
|
|
77
|
+
this.config = {
|
|
78
|
+
defaultLanguage: config.defaultLanguage || defaultLang.id,
|
|
79
|
+
fallbackLanguage: config.fallbackLanguage || defaultLang.id,
|
|
80
|
+
constants: config.constants || {},
|
|
81
|
+
validation: {
|
|
82
|
+
requireCompleteStrings: false,
|
|
83
|
+
allowPartialRegistration: true,
|
|
84
|
+
...config.validation,
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
this.componentStore = new ComponentStore(this.config.constants);
|
|
89
|
+
this.enumRegistry = new EnumRegistry((key, vars) =>
|
|
90
|
+
this.safeTranslate(CoreI18nComponentId, key, vars),
|
|
91
|
+
);
|
|
92
|
+
this.instanceKey = options?.instanceKey || I18nEngine.DEFAULT_KEY;
|
|
93
|
+
|
|
94
|
+
// Create context
|
|
95
|
+
I18nEngine.contextManager.create(
|
|
96
|
+
this.instanceKey,
|
|
97
|
+
this.config.defaultLanguage,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// Register instance
|
|
101
|
+
if (options?.registerInstance !== false) {
|
|
102
|
+
if (I18nEngine.instances.has(this.instanceKey)) {
|
|
103
|
+
throw I18nError.instanceExists(this.instanceKey);
|
|
104
|
+
}
|
|
105
|
+
I18nEngine.instances.set(this.instanceKey, this);
|
|
106
|
+
|
|
107
|
+
if (options?.setAsDefault !== false || !I18nEngine.defaultKey) {
|
|
108
|
+
I18nEngine.defaultKey = this.instanceKey;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Registers a translation component configuration.
|
|
115
|
+
* @param config - Component configuration object.
|
|
116
|
+
* @returns ValidationResult containing any warnings or errors.
|
|
117
|
+
*/
|
|
118
|
+
register(config: ComponentConfig): ValidationResult {
|
|
119
|
+
validateComponentId(config.id);
|
|
120
|
+
this.registerComponentMetadata(config);
|
|
121
|
+
return this.componentStore.register(config);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Registers a component if not already registered.
|
|
126
|
+
* @param config - Component configuration object.
|
|
127
|
+
* @returns ValidationResult containing any warnings or errors.
|
|
128
|
+
*/
|
|
129
|
+
registerIfNotExists(config: ComponentConfig): ValidationResult {
|
|
130
|
+
if (this.hasComponent(config.id)) {
|
|
131
|
+
return { isValid: true, errors: [], warnings: [] };
|
|
132
|
+
}
|
|
133
|
+
return this.register(config);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Internal: Builds metadata lookup maps from component config.
|
|
138
|
+
* @param config - Component configuration object.
|
|
139
|
+
*/
|
|
140
|
+
private registerComponentMetadata(config: ComponentConfig): void {
|
|
141
|
+
const componentId = config.id;
|
|
142
|
+
const aliases = config.aliases || [];
|
|
143
|
+
// These properties may exist on extended config types
|
|
144
|
+
// Use type-safe property access with index signature
|
|
145
|
+
const configWithOptional = config as ComponentConfig & {
|
|
146
|
+
enumName?: string;
|
|
147
|
+
enumObject?: Record<string, unknown>;
|
|
148
|
+
};
|
|
149
|
+
const enumName = configWithOptional.enumName;
|
|
150
|
+
const enumObject = configWithOptional.enumObject;
|
|
151
|
+
|
|
152
|
+
const aliasSet = new Set<string>();
|
|
153
|
+
if (componentId) aliasSet.add(componentId);
|
|
154
|
+
if (enumName) aliasSet.add(enumName);
|
|
155
|
+
aliases.forEach((alias) => {
|
|
156
|
+
if (alias) aliasSet.add(alias);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
aliasSet.forEach((alias) => {
|
|
160
|
+
const trimmed = alias.trim();
|
|
161
|
+
if (trimmed.length > 0) {
|
|
162
|
+
this.aliasToComponent.set(trimmed, componentId);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (!this.componentKeyLookup.has(componentId)) {
|
|
167
|
+
this.componentKeyLookup.set(componentId, new Map<string, string>());
|
|
168
|
+
}
|
|
169
|
+
const keyMap = this.componentKeyLookup.get(componentId)!;
|
|
170
|
+
|
|
171
|
+
const addKeyVariant = (aliasKey: string, canonicalKey: string) => {
|
|
172
|
+
if (!aliasKey || !canonicalKey) return;
|
|
173
|
+
keyMap.set(aliasKey, canonicalKey);
|
|
174
|
+
const normalized = this.normalizeLegacyKey(aliasKey);
|
|
175
|
+
if (normalized && normalized !== aliasKey) {
|
|
176
|
+
keyMap.set(normalized, canonicalKey);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// Get string keys from the strings object
|
|
181
|
+
const firstLang = Object.keys(config.strings)[0];
|
|
182
|
+
if (firstLang) {
|
|
183
|
+
Object.keys(config.strings[firstLang]).forEach((key: string) => {
|
|
184
|
+
addKeyVariant(key, key);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (enumObject) {
|
|
189
|
+
Object.entries(enumObject).forEach(([enumKey, enumValue]) => {
|
|
190
|
+
if (typeof enumValue === 'string') {
|
|
191
|
+
addKeyVariant(enumKey, enumValue);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Internal: Normalizes legacy keys into snake_case lowercased.
|
|
199
|
+
* @param rawKey - The raw key string to normalize.
|
|
200
|
+
* @returns Normalized key or null if empty.
|
|
201
|
+
*/
|
|
202
|
+
private normalizeLegacyKey(rawKey: string): string | null {
|
|
203
|
+
if (!rawKey) return null;
|
|
204
|
+
const normalized = rawKey
|
|
205
|
+
.replace(/[-\s]+/g, '_')
|
|
206
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
207
|
+
.replace(/__+/g, '_')
|
|
208
|
+
.toLowerCase();
|
|
209
|
+
return normalized.length > 0 ? normalized : null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Internal: Resolves the component prefix and key to actual IDs.
|
|
214
|
+
* @param prefix - Component or enum alias.
|
|
215
|
+
* @param rawKey - Raw translation key.
|
|
216
|
+
* @returns Object containing resolved componentId and stringKey.
|
|
217
|
+
*/
|
|
218
|
+
private resolveComponentAndKey(
|
|
219
|
+
prefix: string,
|
|
220
|
+
rawKey: string,
|
|
221
|
+
): { componentId: string; stringKey: string } {
|
|
222
|
+
const componentId = this.aliasToComponent.get(prefix) ?? prefix;
|
|
223
|
+
const keyLookup = this.componentKeyLookup.get(componentId);
|
|
224
|
+
|
|
225
|
+
if (!keyLookup) {
|
|
226
|
+
return { componentId, stringKey: rawKey };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const directMatch = keyLookup.get(rawKey);
|
|
230
|
+
if (directMatch) {
|
|
231
|
+
return { componentId, stringKey: directMatch };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const normalized = this.normalizeLegacyKey(rawKey);
|
|
235
|
+
if (normalized) {
|
|
236
|
+
const normalizedMatch = keyLookup.get(normalized);
|
|
237
|
+
if (normalizedMatch) {
|
|
238
|
+
return { componentId, stringKey: normalizedMatch };
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return { componentId, stringKey: rawKey };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Updates translation strings for a component.
|
|
247
|
+
* @param componentId - ID of the component to update.
|
|
248
|
+
* @param strings - Language-keyed string records.
|
|
249
|
+
* @returns ValidationResult containing any warnings or errors.
|
|
250
|
+
*/
|
|
251
|
+
updateStrings(
|
|
252
|
+
componentId: string,
|
|
253
|
+
strings: Record<string, Record<string, string>>,
|
|
254
|
+
): ValidationResult {
|
|
255
|
+
return this.componentStore.update(componentId, strings);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Checks if a component is registered.
|
|
260
|
+
* @param componentId - ID of the component.
|
|
261
|
+
* @returns True if the component exists.
|
|
262
|
+
*/
|
|
263
|
+
hasComponent(componentId: string): boolean {
|
|
264
|
+
return this.componentStore.has(componentId);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Retrieves all registered component configs.
|
|
269
|
+
* @returns Array of ComponentConfig.
|
|
270
|
+
*/
|
|
271
|
+
getComponents(): readonly ComponentConfig[] {
|
|
272
|
+
return this.componentStore.getAll();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Translates a key for a component in a given or current language.
|
|
277
|
+
* @param componentId - ID of the component.
|
|
278
|
+
* @param key - Translation key.
|
|
279
|
+
* @param variables - Optional variables for template.
|
|
280
|
+
* @param language - Language code to translate into.
|
|
281
|
+
* @returns Translated string.
|
|
282
|
+
*/
|
|
283
|
+
translate(
|
|
284
|
+
componentId: string,
|
|
285
|
+
key: string,
|
|
286
|
+
variables?: Record<string, any>,
|
|
287
|
+
language?: string,
|
|
288
|
+
): string {
|
|
289
|
+
const lang =
|
|
290
|
+
language ||
|
|
291
|
+
I18nEngine.contextManager.getCurrentLanguage(this.instanceKey);
|
|
292
|
+
const combinedVars = this.buildCombinedVariables(variables);
|
|
293
|
+
return this.componentStore.translate(componentId, key, combinedVars, lang);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Safely translates a key, returning a placeholder for missing translations.
|
|
298
|
+
* @param componentId - ID of the component.
|
|
299
|
+
* @param key - Translation key.
|
|
300
|
+
* @param variables - Optional variables for template.
|
|
301
|
+
* @param language - Language code to translate into.
|
|
302
|
+
* @returns Safe translated string.
|
|
303
|
+
*/
|
|
304
|
+
safeTranslate(
|
|
305
|
+
componentId: string,
|
|
306
|
+
key: string,
|
|
307
|
+
variables?: Record<string, any>,
|
|
308
|
+
language?: string,
|
|
309
|
+
): string {
|
|
310
|
+
const lang =
|
|
311
|
+
language ||
|
|
312
|
+
I18nEngine.contextManager.getCurrentLanguage(this.instanceKey);
|
|
313
|
+
const combinedVars = this.buildCombinedVariables(variables);
|
|
314
|
+
return this.componentStore.safeTranslate(
|
|
315
|
+
componentId,
|
|
316
|
+
key,
|
|
317
|
+
combinedVars,
|
|
318
|
+
lang,
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Processes a translation template, replacing component and variable placeholders.
|
|
324
|
+
* @param template - Template string containing {{component.key}} and {variable}.
|
|
325
|
+
* @param variables - Optional variables for substitution.
|
|
326
|
+
* @param language - Language code to translate into.
|
|
327
|
+
* @returns Processed template string.
|
|
328
|
+
* @throws {I18nError} If template length exceeds limits.
|
|
329
|
+
*/
|
|
330
|
+
t(
|
|
331
|
+
template: string,
|
|
332
|
+
variables?: Record<string, any>,
|
|
333
|
+
language?: string,
|
|
334
|
+
): string {
|
|
335
|
+
validateTemplateLength(template);
|
|
336
|
+
const lang =
|
|
337
|
+
language ||
|
|
338
|
+
I18nEngine.contextManager.getCurrentLanguage(this.instanceKey);
|
|
339
|
+
|
|
340
|
+
// Build combined variables: constants + context + provided (provided overrides all)
|
|
341
|
+
const combinedVars = this.buildCombinedVariables(variables);
|
|
342
|
+
|
|
343
|
+
// Replace {{component.key}} or {{EnumName.key}} patterns with alias support
|
|
344
|
+
// Limited pattern to prevent ReDoS: max 100 chars between braces
|
|
345
|
+
let result = template.replace(
|
|
346
|
+
/\{\{([^}]{1,100})\}\}/g,
|
|
347
|
+
(match, pattern) => {
|
|
348
|
+
const parts = pattern.split('.');
|
|
349
|
+
if (parts.length === 2) {
|
|
350
|
+
const [rawPrefix, rawKey] = parts;
|
|
351
|
+
const prefix = rawPrefix.trim();
|
|
352
|
+
const key = rawKey.trim();
|
|
353
|
+
|
|
354
|
+
// Always pass combined variables to translations
|
|
355
|
+
// The translation will use them if the string has placeholders
|
|
356
|
+
// Resolve aliases and enum names to actual component IDs
|
|
357
|
+
const { componentId, stringKey } = this.resolveComponentAndKey(
|
|
358
|
+
prefix,
|
|
359
|
+
key,
|
|
360
|
+
);
|
|
361
|
+
return this.safeTranslate(componentId, stringKey, combinedVars, lang);
|
|
362
|
+
}
|
|
363
|
+
return match;
|
|
364
|
+
},
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
// Replace {variable} patterns with combined variables
|
|
368
|
+
// Limited pattern to prevent ReDoS: max 50 chars for variable names
|
|
369
|
+
result = result.replace(/\{(\w{1,50})\}/g, (match, varName) => {
|
|
370
|
+
return combinedVars[varName] !== undefined
|
|
371
|
+
? String(combinedVars[varName])
|
|
372
|
+
: match;
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
return result;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Internal: Combines constants, context, and provided variables for translation.
|
|
380
|
+
* @param variables - Optional overrides for context and constants.
|
|
381
|
+
* @returns Combined variables record.
|
|
382
|
+
*/
|
|
383
|
+
private buildCombinedVariables(
|
|
384
|
+
variables?: Record<string, any>,
|
|
385
|
+
): Record<string, any> {
|
|
386
|
+
if (variables) {
|
|
387
|
+
validateObjectKeys(variables);
|
|
388
|
+
}
|
|
389
|
+
const combined: Record<string, any> = createSafeObject();
|
|
390
|
+
|
|
391
|
+
// 1. Start with constants from config
|
|
392
|
+
if (this.config.constants) {
|
|
393
|
+
// Extract values from any wrapper objects in constants
|
|
394
|
+
for (const [key, value] of Object.entries(this.config.constants)) {
|
|
395
|
+
combined[key] = this.extractValue(value);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// 2. Add context variables (timezone, currency, language, etc.)
|
|
400
|
+
// GlobalActiveContext is optional and may not be available in all environments
|
|
401
|
+
try {
|
|
402
|
+
// Check if GlobalActiveContext is available in global scope
|
|
403
|
+
const GlobalActiveContext = globalThis.GlobalActiveContext;
|
|
404
|
+
|
|
405
|
+
if (
|
|
406
|
+
GlobalActiveContext &&
|
|
407
|
+
typeof GlobalActiveContext.getInstance === 'function'
|
|
408
|
+
) {
|
|
409
|
+
const context = GlobalActiveContext.getInstance()?.context;
|
|
410
|
+
if (context) {
|
|
411
|
+
// Add context variables
|
|
412
|
+
combined['language'] = context.language;
|
|
413
|
+
combined['adminLanguage'] = context.adminLanguage;
|
|
414
|
+
combined['currentContext'] = context.currentContext;
|
|
415
|
+
|
|
416
|
+
if (context.currencyCode) {
|
|
417
|
+
// Extract value from CurrencyCode object
|
|
418
|
+
const currencyValue = this.extractValue(context.currencyCode);
|
|
419
|
+
combined['currencyCode'] = currencyValue;
|
|
420
|
+
combined['currency'] = currencyValue;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (context.timezone) {
|
|
424
|
+
// Extract value from Timezone object
|
|
425
|
+
const timezoneValue = this.extractValue(context.timezone);
|
|
426
|
+
combined['timezone'] = timezoneValue;
|
|
427
|
+
combined['userTimezone'] = timezoneValue;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (context.adminTimezone) {
|
|
431
|
+
// Extract value from Timezone object
|
|
432
|
+
combined['adminTimezone'] = this.extractValue(
|
|
433
|
+
context.adminTimezone,
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
} catch (error) {
|
|
439
|
+
// GlobalActiveContext not available or not initialized - continue without context vars
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// 3. Override with provided variables (highest priority)
|
|
443
|
+
// Also extract values from any CurrencyCode or Timezone objects
|
|
444
|
+
if (variables) {
|
|
445
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
446
|
+
if (!['__proto__', 'constructor', 'prototype'].includes(key)) {
|
|
447
|
+
combined[key] = this.extractValue(value);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return combined;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Internal: Extracts primitive or object 'value' fields, handling CurrencyCode and Timezone.
|
|
457
|
+
* @param value - Value or wrapper object.
|
|
458
|
+
* @returns Extracted primitive value.
|
|
459
|
+
*/
|
|
460
|
+
private extractValue(value: any): any {
|
|
461
|
+
if (value instanceof CurrencyCode) return value.value;
|
|
462
|
+
if (value instanceof Timezone) return value.value;
|
|
463
|
+
if (
|
|
464
|
+
value &&
|
|
465
|
+
typeof value === 'object' &&
|
|
466
|
+
'value' in value &&
|
|
467
|
+
typeof value.value !== 'function'
|
|
468
|
+
) {
|
|
469
|
+
return value.value;
|
|
470
|
+
}
|
|
471
|
+
// Return as-is for primitives and other objects
|
|
472
|
+
return value;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Registers a language in the global LanguageRegistry.
|
|
477
|
+
* @param language - LanguageDefinition to register.
|
|
478
|
+
*/
|
|
479
|
+
registerLanguage(language: LanguageDefinition): void {
|
|
480
|
+
LanguageRegistry.register(language);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Sets the current translation language for this instance.
|
|
485
|
+
* @param language - Language code to set.
|
|
486
|
+
* @throws {I18nError} If the language is not registered.
|
|
487
|
+
*/
|
|
488
|
+
setLanguage(language: string): void {
|
|
489
|
+
if (!LanguageRegistry.has(language)) {
|
|
490
|
+
throw I18nError.languageNotFound(language);
|
|
491
|
+
}
|
|
492
|
+
I18nEngine.contextManager.setLanguage(this.instanceKey, language);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Sets the current admin translation language for this instance.
|
|
497
|
+
* @param language - Language code to set.
|
|
498
|
+
* @throws {I18nError} If the language is not registered.
|
|
499
|
+
*/
|
|
500
|
+
setAdminLanguage(language: string): void {
|
|
501
|
+
if (!LanguageRegistry.has(language)) {
|
|
502
|
+
throw I18nError.languageNotFound(language);
|
|
503
|
+
}
|
|
504
|
+
I18nEngine.contextManager.setAdminLanguage(this.instanceKey, language);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Retrieves all registered languages.
|
|
509
|
+
* @returns Array of LanguageDefinition.
|
|
510
|
+
*/
|
|
511
|
+
getLanguages(): readonly LanguageDefinition[] {
|
|
512
|
+
return LanguageRegistry.getAll();
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Checks if a language is registered in the global registry.
|
|
517
|
+
* @param language - Language code to check.
|
|
518
|
+
* @returns True if the language exists.
|
|
519
|
+
*/
|
|
520
|
+
hasLanguage(language: string): boolean {
|
|
521
|
+
return LanguageRegistry.has(language);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Merges new constants into existing config constants.
|
|
526
|
+
* @param constants - Key-value constants to merge.
|
|
527
|
+
*/
|
|
528
|
+
mergeConstants(constants: Record<string, any>): void {
|
|
529
|
+
validateObjectKeys(constants);
|
|
530
|
+
safeAssign(this.config.constants, constants);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Updates config constants and componentStore constants to new values.
|
|
535
|
+
* @param constants - New constants record.
|
|
536
|
+
*/
|
|
537
|
+
updateConstants(constants: Record<string, any>): void {
|
|
538
|
+
validateObjectKeys(constants);
|
|
539
|
+
this.config.constants = constants;
|
|
540
|
+
this.componentStore.setConstants(constants);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Switches translation context to admin.
|
|
545
|
+
*/
|
|
546
|
+
switchToAdmin(): void {
|
|
547
|
+
I18nEngine.contextManager.switchToAdmin(this.instanceKey);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Switches translation context to user.
|
|
552
|
+
*/
|
|
553
|
+
switchToUser(): void {
|
|
554
|
+
I18nEngine.contextManager.switchToUser(this.instanceKey);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Retrieves the current language for this instance.
|
|
559
|
+
* @returns Current language code.
|
|
560
|
+
*/
|
|
561
|
+
getCurrentLanguage(): string {
|
|
562
|
+
return I18nEngine.contextManager.getCurrentLanguage(this.instanceKey);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Registers an enum for translation.
|
|
567
|
+
* @param enumObj - Enum object to register.
|
|
568
|
+
* @param translations - Language keyed translations for enum values.
|
|
569
|
+
* @param enumName - Name to identify the enum in templates.
|
|
570
|
+
*/
|
|
571
|
+
registerEnum<TEnum extends string | number>(
|
|
572
|
+
enumObj: Record<string, TEnum>,
|
|
573
|
+
translations: Record<string, Record<TEnum, string>>,
|
|
574
|
+
enumName: string,
|
|
575
|
+
): void {
|
|
576
|
+
this.enumRegistry.register(enumObj, translations, enumName);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Translates an enum value for the current or specified language.
|
|
581
|
+
* @param enumObj - Enum object.
|
|
582
|
+
* @param value - Enum value to translate.
|
|
583
|
+
* @param language - Optional language code.
|
|
584
|
+
* @returns Translated enum string.
|
|
585
|
+
*/
|
|
586
|
+
translateEnum<TEnum extends string | number>(
|
|
587
|
+
enumObj: Record<string, TEnum>,
|
|
588
|
+
value: TEnum,
|
|
589
|
+
language?: string,
|
|
590
|
+
): string {
|
|
591
|
+
const lang = language || this.getCurrentLanguage();
|
|
592
|
+
return this.enumRegistry.translate(enumObj, value, lang);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Checks if an enum is registered.
|
|
597
|
+
* @param enumObj - Enum object to check.
|
|
598
|
+
* @returns True if the enum is registered.
|
|
599
|
+
*/
|
|
600
|
+
hasEnum(enumObj: any): boolean {
|
|
601
|
+
return this.enumRegistry.has(enumObj);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Validates all registered components for missing translations or warnings.
|
|
606
|
+
* @returns ValidationResult containing errors and warnings.
|
|
607
|
+
*/
|
|
608
|
+
validate(): ValidationResult {
|
|
609
|
+
const errors: string[] = [];
|
|
610
|
+
const warnings: string[] = [];
|
|
611
|
+
|
|
612
|
+
for (const component of this.componentStore.getAll()) {
|
|
613
|
+
const result = this.componentStore.register(component);
|
|
614
|
+
errors.push(...result.errors);
|
|
615
|
+
warnings.push(...result.warnings);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
return {
|
|
619
|
+
isValid: errors.length === 0,
|
|
620
|
+
errors,
|
|
621
|
+
warnings,
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Creates a new engine instance with the given key, languages, and config.
|
|
627
|
+
* @param key - Unique key for the new instance.
|
|
628
|
+
* @param languages - Array of language definitions to register.
|
|
629
|
+
* @param config - Optional engine configuration.
|
|
630
|
+
* @returns Newly created I18nEngine instance.
|
|
631
|
+
*/
|
|
632
|
+
static createInstance(
|
|
633
|
+
key: string,
|
|
634
|
+
languages: readonly LanguageDefinition[],
|
|
635
|
+
config?: EngineConfig,
|
|
636
|
+
): I18nEngine {
|
|
637
|
+
return new I18nEngine(languages, config, {
|
|
638
|
+
instanceKey: key,
|
|
639
|
+
registerInstance: true,
|
|
640
|
+
setAsDefault: false,
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Registers or retrieves an existing engine instance by key.
|
|
646
|
+
* @param key - Unique key for the instance.
|
|
647
|
+
* @param languages - Array of language definitions.
|
|
648
|
+
* @param config - Optional engine configuration.
|
|
649
|
+
* @returns Existing or newly created I18nEngine instance.
|
|
650
|
+
*/
|
|
651
|
+
static registerIfNotExists(
|
|
652
|
+
key: string,
|
|
653
|
+
languages: readonly LanguageDefinition[],
|
|
654
|
+
config?: EngineConfig,
|
|
655
|
+
): I18nEngine {
|
|
656
|
+
if (I18nEngine.hasInstance(key)) {
|
|
657
|
+
return I18nEngine.getInstance(key);
|
|
658
|
+
}
|
|
659
|
+
return I18nEngine.createInstance(key, languages, config);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Retrieves an engine instance by key or default if none provided.
|
|
664
|
+
* @param key - Optional instance key.
|
|
665
|
+
* @returns I18nEngine instance.
|
|
666
|
+
* @throws {I18nError} If instance not found.
|
|
667
|
+
*/
|
|
668
|
+
static getInstance(key?: string): I18nEngine {
|
|
669
|
+
const instanceKey = key || I18nEngine.defaultKey || I18nEngine.DEFAULT_KEY;
|
|
670
|
+
const instance = I18nEngine.instances.get(instanceKey);
|
|
671
|
+
if (!instance) {
|
|
672
|
+
throw I18nError.instanceNotFound(instanceKey);
|
|
673
|
+
}
|
|
674
|
+
return instance;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Checks if an engine instance exists.
|
|
679
|
+
* @param key - Optional instance key.
|
|
680
|
+
* @returns True if instance exists.
|
|
681
|
+
*/
|
|
682
|
+
static hasInstance(key?: string): boolean {
|
|
683
|
+
const instanceKey = key || I18nEngine.DEFAULT_KEY;
|
|
684
|
+
return I18nEngine.instances.has(instanceKey);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* Removes an engine instance by key.
|
|
689
|
+
* @param key - Optional instance key.
|
|
690
|
+
* @returns True if the instance was removed.
|
|
691
|
+
*/
|
|
692
|
+
static removeInstance(key?: string): boolean {
|
|
693
|
+
const instanceKey = key || I18nEngine.DEFAULT_KEY;
|
|
694
|
+
const removed = I18nEngine.instances.delete(instanceKey);
|
|
695
|
+
if (removed && I18nEngine.defaultKey === instanceKey) {
|
|
696
|
+
I18nEngine.defaultKey = null;
|
|
697
|
+
}
|
|
698
|
+
return removed;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Resets all engine instances and clears global registries.
|
|
703
|
+
*/
|
|
704
|
+
static resetAll(): void {
|
|
705
|
+
I18nEngine.instances.clear();
|
|
706
|
+
I18nEngine.defaultKey = null;
|
|
707
|
+
I18nEngine.contextManager.clear();
|
|
708
|
+
LanguageRegistry.clear();
|
|
709
|
+
}
|
|
710
|
+
}
|