@digitaldefiance/i18n-lib 3.8.0 → 3.8.2
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 +182 -0
- package/package.json +12 -4
- package/src/{active-context.d.ts → active-context.ts} +0 -1
- 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.d.ts → index.ts} +4 -1
- package/src/core/language-registry.ts +345 -0
- package/src/{core-component-id.d.ts → core-component-id.ts} +1 -2
- 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.d.ts → base.ts} +1 -1
- 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.d.ts → index.ts} +4 -1
- package/src/errors/simple-typed-error.ts +81 -0
- package/src/errors/{translatable-exports.d.ts → translatable-exports.ts} +1 -1
- 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} +38 -6
- 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.d.ts → index.ts} +1 -1
- 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.d.ts → types.ts} +72 -21
- 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.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 -22
- 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.map +0 -1
- package/src/core/index.js +0 -21
- 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 -298
- package/src/core/language-registry.js.map +0 -1
- package/src/core-component-id.d.ts.map +0 -1
- package/src/core-component-id.js +0 -9
- package/src/core-component-id.js.map +0 -1
- package/src/core-i18n.d.ts +0 -69
- package/src/core-i18n.d.ts.map +0 -1
- package/src/core-i18n.js +0 -219
- package/src/core-i18n.js.map +0 -1
- package/src/core-plugin-factory.d.ts +0 -28
- package/src/core-plugin-factory.d.ts.map +0 -1
- package/src/core-plugin-factory.js +0 -80
- package/src/core-plugin-factory.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/base.d.ts.map +0 -1
- package/src/errors/base.js +0 -11
- package/src/errors/base.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 -93
- 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-exports.d.ts.map +0 -1
- package/src/errors/translatable-exports.js +0 -15
- package/src/errors/translatable-exports.js.map +0 -1
- package/src/errors/translatable-generic.d.ts +0 -87
- package/src/errors/translatable-generic.d.ts.map +0 -1
- package/src/errors/translatable-generic.js +0 -139
- 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 -63
- package/src/errors/translatable.d.ts.map +0 -1
- package/src/errors/translatable.js +0 -85
- 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 -108
- 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 -458
- 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/active-context.interface.d.ts +0 -36
- package/src/interfaces/active-context.interface.d.ts.map +0 -1
- package/src/interfaces/active-context.interface.js +0 -3
- package/src/interfaces/active-context.interface.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.map +0 -1
- package/src/interfaces/index.js +0 -7
- 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 -493
- 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 -25
- package/src/registry-error.d.ts.map +0 -1
- package/src/registry-error.js +0 -63
- 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.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 -99
- 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,432 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component registry for managing internationalization components and their string translations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ComponentDefinition } from './component-definition';
|
|
6
|
+
import { ComponentRegistration } from './component-registration';
|
|
7
|
+
import { RegistryError } from './registry-error';
|
|
8
|
+
import { RegistryErrorType } from './registry-error-type';
|
|
9
|
+
import { TranslationRequest } from './translation-request';
|
|
10
|
+
import { TranslationResponse } from './translation-response';
|
|
11
|
+
import {
|
|
12
|
+
ComponentLanguageStrings,
|
|
13
|
+
ComponentStrings,
|
|
14
|
+
PartialComponentLanguageStrings,
|
|
15
|
+
PartialComponentStrings,
|
|
16
|
+
} from './types';
|
|
17
|
+
import { isTemplate, replaceVariables } from './utils';
|
|
18
|
+
import { ValidationConfig } from './validation-config';
|
|
19
|
+
import { ValidationResult } from './validation-result';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Registry for managing components and their translations
|
|
23
|
+
*/
|
|
24
|
+
export class ComponentRegistry<TLanguages extends string> {
|
|
25
|
+
private readonly components = new Map<string, ComponentDefinition<any>>();
|
|
26
|
+
private readonly componentStrings = new Map<
|
|
27
|
+
string,
|
|
28
|
+
ComponentLanguageStrings<any, TLanguages>
|
|
29
|
+
>();
|
|
30
|
+
private readonly validationConfig: ValidationConfig;
|
|
31
|
+
private readonly registeredLanguages: Set<TLanguages>;
|
|
32
|
+
private readonly constants?: Record<string, any>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Creates a new ComponentRegistry.
|
|
36
|
+
* @param languages - Array of supported language codes.
|
|
37
|
+
* @param validationConfig - Configuration for validation rules.
|
|
38
|
+
* @param constants - Optional constants for variable replacement in templates.
|
|
39
|
+
*/
|
|
40
|
+
constructor(
|
|
41
|
+
languages: readonly TLanguages[],
|
|
42
|
+
validationConfig: ValidationConfig,
|
|
43
|
+
constants?: Record<string, any>,
|
|
44
|
+
) {
|
|
45
|
+
this.registeredLanguages = new Set(languages);
|
|
46
|
+
this.validationConfig = validationConfig;
|
|
47
|
+
this.constants = constants;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Update the set of registered languages (for dynamic language addition).
|
|
52
|
+
* @param languages - Array of language codes to register.
|
|
53
|
+
*/
|
|
54
|
+
public updateRegisteredLanguages(languages: readonly TLanguages[]): void {
|
|
55
|
+
this.registeredLanguages.clear();
|
|
56
|
+
languages.forEach((lang) => this.registeredLanguages.add(lang));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Register a new component with its translations.
|
|
61
|
+
* @param registration - Component registration payload.
|
|
62
|
+
* @returns ValidationResult indicating success or errors.
|
|
63
|
+
* @throws RegistryError if component is already registered or validation fails.
|
|
64
|
+
*/
|
|
65
|
+
public registerComponent<TStringKeys extends string>(
|
|
66
|
+
registration: ComponentRegistration<TStringKeys, TLanguages>,
|
|
67
|
+
): ValidationResult {
|
|
68
|
+
const { component, strings } = registration;
|
|
69
|
+
|
|
70
|
+
// Check for duplicate component
|
|
71
|
+
if (this.components.has(component.id)) {
|
|
72
|
+
throw RegistryError.createSimple(
|
|
73
|
+
RegistryErrorType.DuplicateComponent,
|
|
74
|
+
`Component '${component.id}' is already registered`,
|
|
75
|
+
{ componentId: component.id },
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Validate the registration
|
|
80
|
+
const validationResult = this.validateComponentRegistration(registration);
|
|
81
|
+
|
|
82
|
+
if (
|
|
83
|
+
!validationResult.isValid &&
|
|
84
|
+
!this.validationConfig.allowPartialRegistration
|
|
85
|
+
) {
|
|
86
|
+
throw RegistryError.createSimple(
|
|
87
|
+
RegistryErrorType.ValidationFailed,
|
|
88
|
+
`Component registration validation failed: ${validationResult.errors.join(
|
|
89
|
+
', ',
|
|
90
|
+
)}`,
|
|
91
|
+
{
|
|
92
|
+
componentId: component.id,
|
|
93
|
+
missingKeys: validationResult.missingKeys,
|
|
94
|
+
errors: validationResult.errors,
|
|
95
|
+
},
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Complete missing strings with fallbacks if partial registration is allowed
|
|
100
|
+
const completeStrings = this.completeStringsWithFallbacks(
|
|
101
|
+
component,
|
|
102
|
+
strings,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// Register the component
|
|
106
|
+
this.components.set(component.id, component);
|
|
107
|
+
this.componentStrings.set(component.id, completeStrings);
|
|
108
|
+
|
|
109
|
+
return validationResult;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Update strings for an existing component.
|
|
114
|
+
* @param componentId - The ID of the component to update.
|
|
115
|
+
* @param strings - Partial strings to update.
|
|
116
|
+
* @returns ValidationResult indicating success or errors.
|
|
117
|
+
* @throws RegistryError if component is not found.
|
|
118
|
+
*/
|
|
119
|
+
public updateComponentStrings<TStringKeys extends string>(
|
|
120
|
+
componentId: string,
|
|
121
|
+
strings: PartialComponentLanguageStrings<TStringKeys, TLanguages>,
|
|
122
|
+
): ValidationResult {
|
|
123
|
+
const component = this.components.get(componentId);
|
|
124
|
+
if (!component) {
|
|
125
|
+
throw RegistryError.createSimple(
|
|
126
|
+
RegistryErrorType.ComponentNotFound,
|
|
127
|
+
`Component with ID '${componentId}' not found`,
|
|
128
|
+
{ componentId },
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const registration: ComponentRegistration<TStringKeys, TLanguages> = {
|
|
133
|
+
component: component as ComponentDefinition<TStringKeys>,
|
|
134
|
+
strings,
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const validationResult = this.validateComponentRegistration(registration);
|
|
138
|
+
|
|
139
|
+
if (
|
|
140
|
+
validationResult.isValid ||
|
|
141
|
+
this.validationConfig.allowPartialRegistration
|
|
142
|
+
) {
|
|
143
|
+
const existingStrings =
|
|
144
|
+
this.componentStrings.get(componentId) ||
|
|
145
|
+
({} as ComponentLanguageStrings<TStringKeys, TLanguages>);
|
|
146
|
+
const updatedStrings = this.mergeStrings(existingStrings, strings);
|
|
147
|
+
const completeStrings = this.completeStringsWithFallbacks(
|
|
148
|
+
component,
|
|
149
|
+
updatedStrings,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
this.componentStrings.set(componentId, completeStrings);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return validationResult;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Get a translation for a specific component, string key, and language.
|
|
160
|
+
* @param request - Translation request containing componentId, stringKey, language, and variables.
|
|
161
|
+
* @returns TranslationResponse with the translated string and metadata.
|
|
162
|
+
* @throws RegistryError if component, language, or string key is not found.
|
|
163
|
+
*/
|
|
164
|
+
public getTranslation<TStringKeys extends string>(
|
|
165
|
+
request: TranslationRequest<TStringKeys, TLanguages>,
|
|
166
|
+
): TranslationResponse {
|
|
167
|
+
const { componentId, stringKey, language, variables } = request;
|
|
168
|
+
|
|
169
|
+
// Check if component exists
|
|
170
|
+
if (!this.components.has(componentId)) {
|
|
171
|
+
throw RegistryError.createSimple(
|
|
172
|
+
RegistryErrorType.ComponentNotFound,
|
|
173
|
+
`Component '${componentId}' not found`,
|
|
174
|
+
{ componentId },
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const componentStrings = this.componentStrings.get(componentId);
|
|
179
|
+
if (!componentStrings) {
|
|
180
|
+
throw RegistryError.createSimple(
|
|
181
|
+
RegistryErrorType.StringKeyNotFound,
|
|
182
|
+
`No strings registered for component '${componentId}'`,
|
|
183
|
+
{ componentId },
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const targetLanguage =
|
|
188
|
+
language || (this.validationConfig.fallbackLanguageId as TLanguages);
|
|
189
|
+
let actualLanguage = targetLanguage;
|
|
190
|
+
let wasFallback = false;
|
|
191
|
+
|
|
192
|
+
// Try to get the string in the requested language
|
|
193
|
+
let languageStrings = componentStrings[targetLanguage];
|
|
194
|
+
|
|
195
|
+
// If not found and different from fallback, try fallback language
|
|
196
|
+
if (
|
|
197
|
+
!languageStrings &&
|
|
198
|
+
targetLanguage !== this.validationConfig.fallbackLanguageId
|
|
199
|
+
) {
|
|
200
|
+
languageStrings =
|
|
201
|
+
componentStrings[
|
|
202
|
+
this.validationConfig.fallbackLanguageId as TLanguages
|
|
203
|
+
];
|
|
204
|
+
actualLanguage = this.validationConfig.fallbackLanguageId as TLanguages;
|
|
205
|
+
wasFallback = true;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (!languageStrings) {
|
|
209
|
+
throw RegistryError.createSimple(
|
|
210
|
+
RegistryErrorType.LanguageNotFound,
|
|
211
|
+
`No strings found for language '${targetLanguage}' in component '${componentId}'`,
|
|
212
|
+
{ componentId, language: targetLanguage },
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const translation = languageStrings[stringKey];
|
|
217
|
+
if (!translation) {
|
|
218
|
+
throw RegistryError.createSimple(
|
|
219
|
+
RegistryErrorType.StringKeyNotFound,
|
|
220
|
+
`String key '${stringKey}' not found for component '${componentId}' in language '${actualLanguage}'`,
|
|
221
|
+
{ componentId, stringKey, language: actualLanguage },
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Process variables if the string key indicates it's a template
|
|
226
|
+
let processedTranslation: string = translation;
|
|
227
|
+
if (isTemplate(stringKey)) {
|
|
228
|
+
processedTranslation = replaceVariables(
|
|
229
|
+
translation,
|
|
230
|
+
variables,
|
|
231
|
+
this.constants,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
translation: processedTranslation,
|
|
237
|
+
actualLanguage,
|
|
238
|
+
wasFallback,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Get all registered components.
|
|
244
|
+
* @returns Array of all registered ComponentDefinition objects.
|
|
245
|
+
*/
|
|
246
|
+
public getComponents(): ReadonlyArray<ComponentDefinition<any>> {
|
|
247
|
+
return Array.from(this.components.values());
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Get a specific component by ID.
|
|
252
|
+
* @param componentId - The ID of the component to retrieve.
|
|
253
|
+
* @returns The ComponentDefinition or undefined if not found.
|
|
254
|
+
*/
|
|
255
|
+
public getComponent<TStringKeys extends string>(
|
|
256
|
+
componentId: string,
|
|
257
|
+
): ComponentDefinition<TStringKeys> | undefined {
|
|
258
|
+
return this.components.get(componentId) as
|
|
259
|
+
| ComponentDefinition<TStringKeys>
|
|
260
|
+
| undefined;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Check if a component is registered.
|
|
265
|
+
* @param componentId - The ID of the component to check.
|
|
266
|
+
* @returns True if the component is registered, false otherwise.
|
|
267
|
+
*/
|
|
268
|
+
public hasComponent(componentId: string): boolean {
|
|
269
|
+
return this.components.has(componentId);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Get all strings for a component in all languages.
|
|
274
|
+
* @param componentId - The ID of the component.
|
|
275
|
+
* @returns ComponentLanguageStrings or undefined if not found.
|
|
276
|
+
*/
|
|
277
|
+
public getComponentStrings<TStringKeys extends string>(
|
|
278
|
+
componentId: string,
|
|
279
|
+
): ComponentLanguageStrings<TStringKeys, TLanguages> | undefined {
|
|
280
|
+
return this.componentStrings.get(componentId) as
|
|
281
|
+
| ComponentLanguageStrings<TStringKeys, TLanguages>
|
|
282
|
+
| undefined;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Validate a component registration.
|
|
287
|
+
* @param registration - Component registration to validate.
|
|
288
|
+
* @returns ValidationResult with details of missing keys and errors.
|
|
289
|
+
*/
|
|
290
|
+
private validateComponentRegistration<TStringKeys extends string>(
|
|
291
|
+
registration: ComponentRegistration<TStringKeys, TLanguages>,
|
|
292
|
+
): ValidationResult {
|
|
293
|
+
const { component, strings } = registration;
|
|
294
|
+
const missingKeys: Array<{
|
|
295
|
+
languageId: string;
|
|
296
|
+
componentId: string;
|
|
297
|
+
stringKey: string;
|
|
298
|
+
}> = [];
|
|
299
|
+
const errors: string[] = [];
|
|
300
|
+
|
|
301
|
+
// Check if all required string keys are provided for each language
|
|
302
|
+
for (const languageId of this.registeredLanguages) {
|
|
303
|
+
const languageStrings = strings[languageId];
|
|
304
|
+
|
|
305
|
+
if (!languageStrings) {
|
|
306
|
+
if (this.validationConfig.requireCompleteStrings) {
|
|
307
|
+
errors.push(
|
|
308
|
+
`Missing all strings for language '${languageId}' in component '${component.id}'`,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
// Add all missing keys for this language
|
|
312
|
+
for (const stringKey of component.stringKeys) {
|
|
313
|
+
missingKeys.push({
|
|
314
|
+
languageId,
|
|
315
|
+
componentId: component.id,
|
|
316
|
+
stringKey,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Check individual string keys
|
|
323
|
+
for (const stringKey of component.stringKeys) {
|
|
324
|
+
if (!languageStrings[stringKey]) {
|
|
325
|
+
missingKeys.push({
|
|
326
|
+
languageId,
|
|
327
|
+
componentId: component.id,
|
|
328
|
+
stringKey,
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
if (this.validationConfig.requireCompleteStrings) {
|
|
332
|
+
errors.push(
|
|
333
|
+
`Missing string key '${stringKey}' for language '${languageId}' in component '${component.id}'`,
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return {
|
|
341
|
+
isValid: missingKeys.length === 0,
|
|
342
|
+
missingKeys,
|
|
343
|
+
errors,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Complete missing strings with fallbacks.
|
|
349
|
+
* @param component - The component definition.
|
|
350
|
+
* @param strings - Partial strings provided.
|
|
351
|
+
* @returns Complete strings with fallbacks filled in.
|
|
352
|
+
*/
|
|
353
|
+
private completeStringsWithFallbacks<TStringKeys extends string>(
|
|
354
|
+
component: ComponentDefinition<TStringKeys>,
|
|
355
|
+
strings: PartialComponentLanguageStrings<TStringKeys, TLanguages>,
|
|
356
|
+
): ComponentLanguageStrings<TStringKeys, TLanguages> {
|
|
357
|
+
const result: Partial<{
|
|
358
|
+
[L in TLanguages]: ComponentStrings<TStringKeys>;
|
|
359
|
+
}> = {};
|
|
360
|
+
const fallbackLanguage = this.validationConfig
|
|
361
|
+
.fallbackLanguageId as TLanguages;
|
|
362
|
+
const fallbackStrings = strings[fallbackLanguage];
|
|
363
|
+
|
|
364
|
+
// Ensure all languages have all required keys
|
|
365
|
+
for (const languageId of this.registeredLanguages) {
|
|
366
|
+
const existingLanguageStrings =
|
|
367
|
+
strings[languageId] || ({} as PartialComponentStrings<TStringKeys>);
|
|
368
|
+
const languageStrings: Partial<{ [K in TStringKeys]: string }> = {};
|
|
369
|
+
|
|
370
|
+
for (const stringKey of component.stringKeys) {
|
|
371
|
+
if (existingLanguageStrings[stringKey]) {
|
|
372
|
+
languageStrings[stringKey] = existingLanguageStrings[stringKey]!;
|
|
373
|
+
} else if (fallbackStrings && fallbackStrings[stringKey]) {
|
|
374
|
+
// Try to use fallback language
|
|
375
|
+
languageStrings[stringKey] = fallbackStrings[stringKey]!;
|
|
376
|
+
} else {
|
|
377
|
+
// Last resort: use a placeholder
|
|
378
|
+
languageStrings[stringKey] = `[${component.id}.${stringKey}]`;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
result[languageId] = languageStrings as ComponentStrings<TStringKeys>;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return result as ComponentLanguageStrings<TStringKeys, TLanguages>;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Merge existing strings with new strings.
|
|
390
|
+
* @param existing - Existing complete strings.
|
|
391
|
+
* @param updates - Partial updates to apply.
|
|
392
|
+
* @returns Merged partial strings.
|
|
393
|
+
*/
|
|
394
|
+
private mergeStrings<TStringKeys extends string>(
|
|
395
|
+
existing: ComponentLanguageStrings<TStringKeys, TLanguages>,
|
|
396
|
+
updates: PartialComponentLanguageStrings<TStringKeys, TLanguages>,
|
|
397
|
+
): PartialComponentLanguageStrings<TStringKeys, TLanguages> {
|
|
398
|
+
const result: { [L in TLanguages]?: PartialComponentStrings<TStringKeys> } =
|
|
399
|
+
{};
|
|
400
|
+
|
|
401
|
+
// Copy existing strings
|
|
402
|
+
for (const [languageId, languageStrings] of Object.entries(existing) as [
|
|
403
|
+
TLanguages,
|
|
404
|
+
ComponentStrings<TStringKeys>,
|
|
405
|
+
][]) {
|
|
406
|
+
result[languageId] = { ...languageStrings };
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Apply updates
|
|
410
|
+
for (const [languageId, languageStrings] of Object.entries(updates) as [
|
|
411
|
+
TLanguages,
|
|
412
|
+
PartialComponentStrings<TStringKeys> | undefined,
|
|
413
|
+
][]) {
|
|
414
|
+
if (languageStrings) {
|
|
415
|
+
result[languageId] = {
|
|
416
|
+
...result[languageId],
|
|
417
|
+
...languageStrings,
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return result;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Clear all components and their strings (useful for testing).
|
|
427
|
+
*/
|
|
428
|
+
public clearAllComponents(): void {
|
|
429
|
+
this.components.clear();
|
|
430
|
+
this.componentStrings.clear();
|
|
431
|
+
}
|
|
432
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component storage (no generics)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { I18nError } from '../errors/i18n-error';
|
|
6
|
+
import { ComponentConfig, ValidationResult } from '../interfaces';
|
|
7
|
+
import { getPluralCategory } from '../pluralization/language-plural-map';
|
|
8
|
+
import { PluralString, resolvePluralString } from '../types/plural-types';
|
|
9
|
+
import { replaceVariables } from '../utils';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Class representing a storage for component configurations and translations.
|
|
13
|
+
*/
|
|
14
|
+
export class ComponentStore {
|
|
15
|
+
private components = new Map<string, ComponentConfig>();
|
|
16
|
+
private aliasMap = new Map<string, string>();
|
|
17
|
+
private constants?: Record<string, any>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Creates a new ComponentStore instance.
|
|
21
|
+
* @param constants - Optional constants to be used in variable replacement.
|
|
22
|
+
*/
|
|
23
|
+
constructor(constants?: Record<string, any>) {
|
|
24
|
+
this.constants = constants;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Registers a new component configuration.
|
|
29
|
+
* @param config - The component configuration to register.
|
|
30
|
+
* @returns ValidationResult indicating the result of the registration.
|
|
31
|
+
* @throws {I18nError} If the component ID is already registered.
|
|
32
|
+
*/
|
|
33
|
+
register(config: ComponentConfig): ValidationResult {
|
|
34
|
+
if (this.components.has(config.id)) {
|
|
35
|
+
throw I18nError.duplicateComponent(config.id);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const validation = this.validate(config);
|
|
39
|
+
this.components.set(config.id, config);
|
|
40
|
+
|
|
41
|
+
// Register aliases
|
|
42
|
+
if (config.aliases) {
|
|
43
|
+
for (const alias of config.aliases) {
|
|
44
|
+
this.aliasMap.set(alias, config.id);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return validation;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Updates an existing component's strings.
|
|
53
|
+
* @param componentId - The ID of the component to update.
|
|
54
|
+
* @param strings - The new strings to merge into the component.
|
|
55
|
+
* @returns ValidationResult indicating the result of the update.
|
|
56
|
+
* @throws {I18nError} If the component is not found.
|
|
57
|
+
*/
|
|
58
|
+
update(
|
|
59
|
+
componentId: string,
|
|
60
|
+
strings: Record<string, Record<string, string>>,
|
|
61
|
+
): ValidationResult {
|
|
62
|
+
const existing = this.components.get(componentId);
|
|
63
|
+
if (!existing) {
|
|
64
|
+
throw I18nError.componentNotFound(componentId);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const updated: ComponentConfig = {
|
|
68
|
+
...existing,
|
|
69
|
+
strings: { ...existing.strings, ...strings },
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
this.components.set(componentId, updated);
|
|
73
|
+
return this.validate(updated);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Checks if a component or alias is registered.
|
|
78
|
+
* @param componentId - The component ID or alias to check.
|
|
79
|
+
* @returns True if the component or alias is registered, false otherwise.
|
|
80
|
+
*/
|
|
81
|
+
has(componentId: string): boolean {
|
|
82
|
+
return this.components.has(componentId) || this.aliasMap.has(componentId);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Retrieves a component configuration by ID or alias.
|
|
87
|
+
* @param componentId - The component ID or alias to retrieve.
|
|
88
|
+
* @returns The component configuration.
|
|
89
|
+
* @throws {I18nError} If the component is not found.
|
|
90
|
+
*/
|
|
91
|
+
get(componentId: string): ComponentConfig {
|
|
92
|
+
const id = this.aliasMap.get(componentId) || componentId;
|
|
93
|
+
const component = this.components.get(id);
|
|
94
|
+
if (!component) {
|
|
95
|
+
throw I18nError.componentNotFound(componentId);
|
|
96
|
+
}
|
|
97
|
+
return component;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Retrieves all registered component configurations.
|
|
102
|
+
* @returns An array of all component configurations.
|
|
103
|
+
*/
|
|
104
|
+
getAll(): readonly ComponentConfig[] {
|
|
105
|
+
return Array.from(this.components.values());
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Translates a key for a component in a given language, replacing variables.
|
|
110
|
+
* @param componentId - The component ID.
|
|
111
|
+
* @param key - The translation key.
|
|
112
|
+
* @param variables - Optional variables for replacement.
|
|
113
|
+
* @param language - Optional language code (default is 'en-US').
|
|
114
|
+
* @returns The translated string.
|
|
115
|
+
* @throws {I18nError} If the language or translation key is not found.
|
|
116
|
+
*/
|
|
117
|
+
translate(
|
|
118
|
+
componentId: string,
|
|
119
|
+
key: string,
|
|
120
|
+
variables?: Record<string, any>,
|
|
121
|
+
language?: string,
|
|
122
|
+
): string {
|
|
123
|
+
const component = this.get(componentId);
|
|
124
|
+
const lang = language || 'en-US';
|
|
125
|
+
const langStrings = component.strings[lang];
|
|
126
|
+
|
|
127
|
+
if (!langStrings) {
|
|
128
|
+
throw I18nError.languageNotFound(lang);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const value = langStrings[key];
|
|
132
|
+
if (!value) {
|
|
133
|
+
throw I18nError.translationMissing(componentId, key, lang);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Resolve plural form if needed
|
|
137
|
+
const translation = this.resolvePluralForm(value, variables?.count, lang);
|
|
138
|
+
|
|
139
|
+
return replaceVariables(translation, variables, this.constants);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Resolve plural form from a PluralString based on count variable.
|
|
144
|
+
* @param value - The string or PluralString to resolve.
|
|
145
|
+
* @param count - The count for pluralization.
|
|
146
|
+
* @param language - The language code.
|
|
147
|
+
* @returns The resolved plural form string.
|
|
148
|
+
*/
|
|
149
|
+
private resolvePluralForm(
|
|
150
|
+
value: string | PluralString,
|
|
151
|
+
count: number | undefined,
|
|
152
|
+
language: string,
|
|
153
|
+
): string {
|
|
154
|
+
// If it's a simple string, return as-is
|
|
155
|
+
if (typeof value === 'string') {
|
|
156
|
+
return value;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// If no count provided, use 'other' form or first available
|
|
160
|
+
if (count === undefined) {
|
|
161
|
+
return resolvePluralString(value, 'other') || '';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Get the appropriate plural category for this count and language
|
|
165
|
+
const category = getPluralCategory(language, count);
|
|
166
|
+
|
|
167
|
+
// Resolve the plural form with fallback logic
|
|
168
|
+
return resolvePluralString(value, category) || '';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Safely translates a key for a component, returning a fallback string on error.
|
|
173
|
+
* @param componentId - The component ID.
|
|
174
|
+
* @param key - The translation key.
|
|
175
|
+
* @param variables - Optional variables for replacement.
|
|
176
|
+
* @param language - Optional language code.
|
|
177
|
+
* @returns The translated string or a fallback string if translation fails.
|
|
178
|
+
*/
|
|
179
|
+
safeTranslate(
|
|
180
|
+
componentId: string,
|
|
181
|
+
key: string,
|
|
182
|
+
variables?: Record<string, any>,
|
|
183
|
+
language?: string,
|
|
184
|
+
): string {
|
|
185
|
+
try {
|
|
186
|
+
return this.translate(componentId, key, variables, language);
|
|
187
|
+
} catch {
|
|
188
|
+
return `[${componentId}.${key}]`;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Validates a component configuration for missing keys across languages.
|
|
194
|
+
* @param config - The component configuration to validate.
|
|
195
|
+
* @returns ValidationResult containing errors and warnings.
|
|
196
|
+
*/
|
|
197
|
+
private validate(config: ComponentConfig): ValidationResult {
|
|
198
|
+
const errors: string[] = [];
|
|
199
|
+
const warnings: string[] = [];
|
|
200
|
+
|
|
201
|
+
// Check if all languages have all keys
|
|
202
|
+
const allKeys = new Set<string>();
|
|
203
|
+
for (const langStrings of Object.values(config.strings)) {
|
|
204
|
+
for (const key of Object.keys(langStrings)) {
|
|
205
|
+
allKeys.add(key);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
for (const [lang, langStrings] of Object.entries(config.strings)) {
|
|
210
|
+
for (const key of allKeys) {
|
|
211
|
+
if (!langStrings[key]) {
|
|
212
|
+
warnings.push(
|
|
213
|
+
`Missing key '${key}' for language '${lang}' in component '${config.id}'`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
isValid: errors.length === 0,
|
|
221
|
+
errors,
|
|
222
|
+
warnings,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Sets constants for variable replacement.
|
|
228
|
+
* @param constants - The constants to set.
|
|
229
|
+
*/
|
|
230
|
+
setConstants(constants: Record<string, any>): void {
|
|
231
|
+
this.constants = constants;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Clears all registered components and aliases.
|
|
236
|
+
*/
|
|
237
|
+
clear(): void {
|
|
238
|
+
this.components.clear();
|
|
239
|
+
this.aliasMap.clear();
|
|
240
|
+
}
|
|
241
|
+
}
|