@digitaldefiance/i18n-lib 3.8.2 → 3.8.3
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/package.json +6 -5
- package/src/{active-context.ts → active-context.d.ts} +1 -0
- package/src/active-context.d.ts.map +1 -0
- package/src/active-context.js +3 -0
- package/src/active-context.js.map +1 -0
- package/src/builders/i18n-builder.d.ts +26 -0
- package/src/builders/i18n-builder.d.ts.map +1 -0
- package/src/builders/i18n-builder.js +70 -0
- package/src/builders/i18n-builder.js.map +1 -0
- package/src/builders/{index.ts → index.d.ts} +1 -1
- package/src/builders/index.d.ts.map +1 -0
- package/src/builders/index.js +8 -0
- package/src/builders/index.js.map +1 -0
- package/src/component-definition.d.ts +12 -0
- package/src/component-definition.d.ts.map +1 -0
- package/src/component-definition.js +3 -0
- package/src/component-definition.js.map +1 -0
- package/src/component-registration.d.ts +22 -0
- package/src/component-registration.d.ts.map +1 -0
- package/src/component-registration.js +3 -0
- package/src/component-registration.js.map +1 -0
- package/src/component-registry.d.ts +102 -0
- package/src/component-registry.d.ts.map +1 -0
- package/src/component-registry.js +282 -0
- package/src/component-registry.js.map +1 -0
- package/src/context-error-type.d.ts +8 -0
- package/src/context-error-type.d.ts.map +1 -0
- package/src/context-error-type.js +12 -0
- package/src/context-error-type.js.map +1 -0
- package/src/core/component-store.d.ts +93 -0
- package/src/core/component-store.d.ts.map +1 -0
- package/src/core/component-store.js +198 -0
- package/src/core/component-store.js.map +1 -0
- package/src/core/context-manager.d.ts +72 -0
- package/src/core/context-manager.d.ts.map +1 -0
- package/src/core/context-manager.js +98 -0
- package/src/core/context-manager.js.map +1 -0
- package/src/core/enum-registry.d.ts +48 -0
- package/src/core/enum-registry.d.ts.map +1 -0
- package/src/core/enum-registry.js +85 -0
- package/src/core/enum-registry.js.map +1 -0
- package/src/core/i18n-engine.d.ts +241 -0
- package/src/core/i18n-engine.d.ts.map +1 -0
- package/src/core/i18n-engine.js +568 -0
- package/src/core/i18n-engine.js.map +1 -0
- package/src/core/{index.ts → index.d.ts} +1 -4
- package/src/core/index.d.ts.map +1 -0
- package/src/core/index.js +21 -0
- package/src/core/index.js.map +1 -0
- package/src/core/language-registry.d.ts +180 -0
- package/src/core/language-registry.d.ts.map +1 -0
- package/src/core/language-registry.js +298 -0
- package/src/core/language-registry.js.map +1 -0
- package/src/{core-component-id.ts → core-component-id.d.ts} +2 -1
- package/src/core-component-id.d.ts.map +1 -0
- package/src/core-component-id.js +9 -0
- package/src/core-component-id.js.map +1 -0
- package/src/core-i18n.d.ts +69 -0
- package/src/core-i18n.d.ts.map +1 -0
- package/src/core-i18n.js +219 -0
- package/src/core-i18n.js.map +1 -0
- package/src/core-plugin-factory.d.ts +28 -0
- package/src/core-plugin-factory.d.ts.map +1 -0
- package/src/core-plugin-factory.js +80 -0
- package/src/core-plugin-factory.js.map +1 -0
- package/src/core-string-key.d.ts +52 -0
- package/src/core-string-key.d.ts.map +1 -0
- package/src/core-string-key.js +61 -0
- package/src/core-string-key.js.map +1 -0
- package/src/create-translation-adapter.d.ts +33 -0
- package/src/create-translation-adapter.d.ts.map +1 -0
- package/src/create-translation-adapter.js +72 -0
- package/src/create-translation-adapter.js.map +1 -0
- package/src/enum-registry.d.ts +65 -0
- package/src/enum-registry.d.ts.map +1 -0
- package/src/enum-registry.js +123 -0
- package/src/enum-registry.js.map +1 -0
- package/src/errors/{base.ts → base.d.ts} +1 -1
- package/src/errors/base.d.ts.map +1 -0
- package/src/errors/base.js +11 -0
- package/src/errors/base.js.map +1 -0
- package/src/errors/context-error.d.ts +50 -0
- package/src/errors/context-error.d.ts.map +1 -0
- package/src/errors/context-error.js +93 -0
- package/src/errors/context-error.js.map +1 -0
- package/src/errors/enhanced-error-base.d.ts +125 -0
- package/src/errors/enhanced-error-base.d.ts.map +1 -0
- package/src/errors/enhanced-error-base.js +165 -0
- package/src/errors/enhanced-error-base.js.map +1 -0
- package/src/errors/handleable.d.ts +83 -0
- package/src/errors/handleable.d.ts.map +1 -0
- package/src/errors/handleable.js +136 -0
- package/src/errors/handleable.js.map +1 -0
- package/src/errors/i18n-error.d.ts +211 -0
- package/src/errors/i18n-error.d.ts.map +1 -0
- package/src/errors/i18n-error.js +358 -0
- package/src/errors/i18n-error.js.map +1 -0
- package/src/errors/{index.ts → index.d.ts} +1 -4
- package/src/errors/index.d.ts.map +1 -0
- package/src/errors/index.js +17 -0
- package/src/errors/index.js.map +1 -0
- package/src/errors/simple-typed-error.d.ts +53 -0
- package/src/errors/simple-typed-error.d.ts.map +1 -0
- package/src/errors/simple-typed-error.js +51 -0
- package/src/errors/simple-typed-error.js.map +1 -0
- package/src/errors/{translatable-exports.ts → translatable-exports.d.ts} +1 -1
- package/src/errors/translatable-exports.d.ts.map +1 -0
- package/src/errors/translatable-exports.js +15 -0
- package/src/errors/translatable-exports.js.map +1 -0
- package/src/errors/translatable-generic.d.ts +87 -0
- package/src/errors/translatable-generic.d.ts.map +1 -0
- package/src/errors/translatable-generic.js +139 -0
- package/src/errors/translatable-generic.js.map +1 -0
- package/src/errors/translatable-handleable-generic.d.ts +116 -0
- package/src/errors/translatable-handleable-generic.d.ts.map +1 -0
- package/src/errors/translatable-handleable-generic.js +121 -0
- package/src/errors/translatable-handleable-generic.js.map +1 -0
- package/src/errors/translatable.d.ts +63 -0
- package/src/errors/translatable.d.ts.map +1 -0
- package/src/errors/translatable.js +85 -0
- package/src/errors/translatable.js.map +1 -0
- package/src/errors/typed-handleable.d.ts +62 -0
- package/src/errors/typed-handleable.d.ts.map +1 -0
- package/src/errors/typed-handleable.js +108 -0
- package/src/errors/typed-handleable.js.map +1 -0
- package/src/errors/typed.d.ts +206 -0
- package/src/errors/typed.d.ts.map +1 -0
- package/src/errors/typed.js +458 -0
- package/src/errors/typed.js.map +1 -0
- package/src/gender/{gender-categories.ts → gender-categories.d.ts} +2 -6
- package/src/gender/gender-categories.d.ts.map +1 -0
- package/src/gender/gender-categories.js +15 -0
- package/src/gender/gender-categories.js.map +1 -0
- package/src/gender/gender-resolver.d.ts +14 -0
- package/src/gender/gender-resolver.d.ts.map +1 -0
- package/src/gender/gender-resolver.js +35 -0
- package/src/gender/gender-resolver.js.map +1 -0
- package/src/gender/{index.ts → index.d.ts} +1 -0
- package/src/gender/index.d.ts.map +1 -0
- package/src/gender/index.js +6 -0
- package/src/gender/index.js.map +1 -0
- package/src/global-active-context.d.ts +50 -0
- package/src/global-active-context.d.ts.map +1 -0
- package/src/global-active-context.js +185 -0
- package/src/global-active-context.js.map +1 -0
- package/src/icu/ast.d.ts +48 -0
- package/src/icu/ast.d.ts.map +1 -0
- package/src/icu/ast.js +16 -0
- package/src/icu/ast.js.map +1 -0
- package/src/icu/compiler.d.ts +16 -0
- package/src/icu/compiler.d.ts.map +1 -0
- package/src/icu/compiler.js +87 -0
- package/src/icu/compiler.js.map +1 -0
- package/src/icu/formatter-registry.d.ts +10 -0
- package/src/icu/formatter-registry.d.ts.map +1 -0
- package/src/icu/formatter-registry.js +34 -0
- package/src/icu/formatter-registry.js.map +1 -0
- package/src/icu/formatters/base-formatter.d.ts +8 -0
- package/src/icu/formatters/base-formatter.d.ts.map +1 -0
- package/src/icu/formatters/base-formatter.js +3 -0
- package/src/icu/formatters/base-formatter.js.map +1 -0
- package/src/icu/formatters/date-formatter.d.ts +5 -0
- package/src/icu/formatters/date-formatter.d.ts.map +1 -0
- package/src/icu/formatters/date-formatter.js +31 -0
- package/src/icu/formatters/date-formatter.js.map +1 -0
- package/src/icu/formatters/number-formatter.d.ts +5 -0
- package/src/icu/formatters/number-formatter.d.ts.map +1 -0
- package/src/icu/formatters/number-formatter.js +33 -0
- package/src/icu/formatters/number-formatter.js.map +1 -0
- package/src/icu/formatters/plural-formatter.d.ts +5 -0
- package/src/icu/formatters/plural-formatter.d.ts.map +1 -0
- package/src/icu/formatters/plural-formatter.js +15 -0
- package/src/icu/formatters/plural-formatter.js.map +1 -0
- package/src/icu/formatters/select-formatter.d.ts +5 -0
- package/src/icu/formatters/select-formatter.d.ts.map +1 -0
- package/src/icu/formatters/select-formatter.js +10 -0
- package/src/icu/formatters/select-formatter.js.map +1 -0
- package/src/icu/formatters/selectordinal-formatter.d.ts +5 -0
- package/src/icu/formatters/selectordinal-formatter.d.ts.map +1 -0
- package/src/icu/formatters/selectordinal-formatter.js +22 -0
- package/src/icu/formatters/selectordinal-formatter.js.map +1 -0
- package/src/icu/formatters/time-formatter.d.ts +5 -0
- package/src/icu/formatters/time-formatter.d.ts.map +1 -0
- package/src/icu/formatters/time-formatter.js +31 -0
- package/src/icu/formatters/time-formatter.js.map +1 -0
- package/src/icu/helpers.d.ts +9 -0
- package/src/icu/helpers.d.ts.map +1 -0
- package/src/icu/helpers.js +31 -0
- package/src/icu/helpers.js.map +1 -0
- package/src/icu/parser.d.ts +31 -0
- package/src/icu/parser.d.ts.map +1 -0
- package/src/icu/parser.js +203 -0
- package/src/icu/parser.js.map +1 -0
- package/src/icu/runtime.d.ts +10 -0
- package/src/icu/runtime.d.ts.map +1 -0
- package/src/icu/runtime.js +33 -0
- package/src/icu/runtime.js.map +1 -0
- package/src/icu/tokenizer.d.ts +37 -0
- package/src/icu/tokenizer.d.ts.map +1 -0
- package/src/icu/tokenizer.js +187 -0
- package/src/icu/tokenizer.js.map +1 -0
- package/src/icu/validator.d.ts +11 -0
- package/src/icu/validator.d.ts.map +1 -0
- package/src/icu/validator.js +140 -0
- package/src/icu/validator.js.map +1 -0
- package/src/{index.ts → index.d.ts} +6 -38
- package/src/index.d.ts.map +1 -0
- package/src/index.js +76 -0
- package/src/index.js.map +1 -0
- package/src/interfaces/active-context.interface.d.ts +36 -0
- package/src/interfaces/active-context.interface.d.ts.map +1 -0
- package/src/interfaces/active-context.interface.js +3 -0
- package/src/interfaces/active-context.interface.js.map +1 -0
- package/src/interfaces/component-config.interface.d.ts +16 -0
- package/src/interfaces/component-config.interface.d.ts.map +1 -0
- package/src/interfaces/component-config.interface.js +6 -0
- package/src/interfaces/component-config.interface.js.map +1 -0
- package/src/interfaces/engine-config.interface.d.ts +22 -0
- package/src/interfaces/engine-config.interface.d.ts.map +1 -0
- package/src/interfaces/engine-config.interface.js +6 -0
- package/src/interfaces/engine-config.interface.js.map +1 -0
- package/src/interfaces/global-active-context.d.ts +23 -0
- package/src/interfaces/global-active-context.d.ts.map +1 -0
- package/src/interfaces/global-active-context.js +3 -0
- package/src/interfaces/global-active-context.js.map +1 -0
- package/src/interfaces/handleable-error-options.d.ts +14 -0
- package/src/interfaces/handleable-error-options.d.ts.map +1 -0
- package/src/interfaces/handleable-error-options.js +3 -0
- package/src/interfaces/handleable-error-options.js.map +1 -0
- package/src/interfaces/handleable.d.ts +21 -0
- package/src/interfaces/handleable.d.ts.map +1 -0
- package/src/interfaces/handleable.js +3 -0
- package/src/interfaces/handleable.js.map +1 -0
- package/src/interfaces/i18n-engine.interface.d.ts +46 -0
- package/src/interfaces/i18n-engine.interface.d.ts.map +1 -0
- package/src/interfaces/i18n-engine.interface.js +6 -0
- package/src/interfaces/i18n-engine.interface.js.map +1 -0
- package/src/interfaces/{index.ts → index.d.ts} +1 -1
- package/src/interfaces/index.d.ts.map +1 -0
- package/src/interfaces/index.js +7 -0
- package/src/interfaces/index.js.map +1 -0
- package/src/interfaces/language-definition.interface.d.ts +17 -0
- package/src/interfaces/language-definition.interface.d.ts.map +1 -0
- package/src/interfaces/language-definition.interface.js +6 -0
- package/src/interfaces/language-definition.interface.js.map +1 -0
- package/src/interfaces/translation-options.interface.d.ts +15 -0
- package/src/interfaces/translation-options.interface.d.ts.map +1 -0
- package/src/interfaces/translation-options.interface.js +6 -0
- package/src/interfaces/translation-options.interface.js.map +1 -0
- package/src/interfaces/validation-result.interface.d.ts +24 -0
- package/src/interfaces/validation-result.interface.d.ts.map +1 -0
- package/src/interfaces/validation-result.interface.js +6 -0
- package/src/interfaces/validation-result.interface.js.map +1 -0
- package/src/language-codes.d.ts +28 -0
- package/src/language-codes.d.ts.map +1 -0
- package/src/language-codes.js +32 -0
- package/src/language-codes.js.map +1 -0
- package/src/language-definition.d.ts +14 -0
- package/src/language-definition.d.ts.map +1 -0
- package/src/language-definition.js +3 -0
- package/src/language-definition.js.map +1 -0
- package/src/plugin-i18n-engine.d.ts +164 -0
- package/src/plugin-i18n-engine.d.ts.map +1 -0
- package/src/plugin-i18n-engine.js +493 -0
- package/src/plugin-i18n-engine.js.map +1 -0
- package/src/pluralization/{index.ts → index.d.ts} +1 -1
- package/src/pluralization/index.d.ts.map +1 -0
- package/src/pluralization/index.js +10 -0
- package/src/pluralization/index.js.map +1 -0
- package/src/pluralization/language-plural-map.d.ts +29 -0
- package/src/pluralization/language-plural-map.d.ts.map +1 -0
- package/src/pluralization/language-plural-map.js +155 -0
- package/src/pluralization/language-plural-map.js.map +1 -0
- package/src/pluralization/{plural-categories.ts → plural-categories.d.ts} +3 -5
- package/src/pluralization/plural-categories.d.ts.map +1 -0
- package/src/pluralization/plural-categories.js +8 -0
- package/src/pluralization/plural-categories.js.map +1 -0
- package/src/pluralization/plural-rules.d.ts +102 -0
- package/src/pluralization/plural-rules.d.ts.map +1 -0
- package/src/pluralization/plural-rules.js +263 -0
- package/src/pluralization/plural-rules.js.map +1 -0
- package/src/registry-config.d.ts +16 -0
- package/src/registry-config.d.ts.map +1 -0
- package/src/registry-config.js +3 -0
- package/src/registry-config.js.map +1 -0
- package/src/registry-error-type.d.ts +20 -0
- package/src/registry-error-type.d.ts.map +1 -0
- package/src/registry-error-type.js +24 -0
- package/src/registry-error-type.js.map +1 -0
- package/src/registry-error.d.ts +25 -0
- package/src/registry-error.d.ts.map +1 -0
- package/src/registry-error.js +63 -0
- package/src/registry-error.js.map +1 -0
- package/src/strict-types.d.ts +19 -0
- package/src/strict-types.d.ts.map +1 -0
- package/src/strict-types.js +18 -0
- package/src/strict-types.js.map +1 -0
- package/src/strings/de.d.ts +3 -0
- package/src/strings/de.d.ts.map +1 -0
- package/src/strings/de.js +57 -0
- package/src/strings/de.js.map +1 -0
- package/src/strings/en-GB.d.ts +3 -0
- package/src/strings/en-GB.d.ts.map +1 -0
- package/src/strings/en-GB.js +57 -0
- package/src/strings/en-GB.js.map +1 -0
- package/src/strings/en-US.d.ts +3 -0
- package/src/strings/en-US.d.ts.map +1 -0
- package/src/strings/en-US.js +57 -0
- package/src/strings/en-US.js.map +1 -0
- package/src/strings/es.d.ts +3 -0
- package/src/strings/es.d.ts.map +1 -0
- package/src/strings/es.js +57 -0
- package/src/strings/es.js.map +1 -0
- package/src/strings/fr.d.ts +3 -0
- package/src/strings/fr.d.ts.map +1 -0
- package/src/strings/fr.js +57 -0
- package/src/strings/fr.js.map +1 -0
- package/src/strings/ja.d.ts +3 -0
- package/src/strings/ja.d.ts.map +1 -0
- package/src/strings/ja.js +57 -0
- package/src/strings/ja.js.map +1 -0
- package/src/strings/uk.d.ts +3 -0
- package/src/strings/uk.d.ts.map +1 -0
- package/src/strings/uk.js +57 -0
- package/src/strings/uk.js.map +1 -0
- package/src/strings/zh-CN.d.ts +3 -0
- package/src/strings/zh-CN.d.ts.map +1 -0
- package/src/strings/zh-CN.js +57 -0
- package/src/strings/zh-CN.js.map +1 -0
- package/src/template.d.ts +13 -0
- package/src/template.d.ts.map +1 -0
- package/src/template.js +40 -0
- package/src/template.js.map +1 -0
- package/src/translation-engine.d.ts +9 -0
- package/src/translation-engine.d.ts.map +1 -0
- package/src/translation-engine.js +3 -0
- package/src/translation-engine.js.map +1 -0
- package/src/translation-request.d.ts +10 -0
- package/src/translation-request.d.ts.map +1 -0
- package/src/translation-request.js +3 -0
- package/src/translation-request.js.map +1 -0
- package/src/translation-response.d.ts +9 -0
- package/src/translation-response.d.ts.map +1 -0
- package/src/translation-response.js +3 -0
- package/src/translation-response.js.map +1 -0
- package/src/types/engine.d.ts +47 -0
- package/src/types/engine.d.ts.map +1 -0
- package/src/types/engine.js +8 -0
- package/src/types/engine.js.map +1 -0
- package/src/types/{index.ts → index.d.ts} +1 -1
- package/src/types/index.d.ts.map +1 -0
- package/src/types/index.js +9 -0
- package/src/types/index.js.map +1 -0
- package/src/types/{plural-types.ts → plural-types.d.ts} +3 -29
- package/src/types/plural-types.d.ts.map +1 -0
- package/src/types/plural-types.js +39 -0
- package/src/types/plural-types.js.map +1 -0
- package/src/{types.ts → types.d.ts} +21 -72
- package/src/types.d.ts.map +1 -0
- package/src/types.js +23 -0
- package/src/types.js.map +1 -0
- package/src/utils/currency.d.ts +81 -0
- package/src/utils/currency.d.ts.map +1 -0
- package/src/utils/currency.js +99 -0
- package/src/utils/currency.js.map +1 -0
- package/src/utils/html-escape.d.ts +22 -0
- package/src/utils/html-escape.d.ts.map +1 -0
- package/src/utils/html-escape.js +53 -0
- package/src/utils/html-escape.js.map +1 -0
- package/src/utils/{index.ts → index.d.ts} +1 -0
- package/src/utils/index.d.ts.map +1 -0
- package/src/utils/index.js +12 -0
- package/src/utils/index.js.map +1 -0
- package/src/utils/lru-cache.d.ts +42 -0
- package/src/utils/lru-cache.d.ts.map +1 -0
- package/src/utils/lru-cache.js +73 -0
- package/src/utils/lru-cache.js.map +1 -0
- package/src/utils/{plural-helpers.ts → plural-helpers.d.ts} +4 -14
- package/src/utils/plural-helpers.d.ts.map +1 -0
- package/src/utils/plural-helpers.js +35 -0
- package/src/utils/plural-helpers.js.map +1 -0
- package/src/utils/safe-object.d.ts +39 -0
- package/src/utils/safe-object.d.ts.map +1 -0
- package/src/utils/{safe-object.ts → safe-object.js} +34 -37
- package/src/utils/safe-object.js.map +1 -0
- package/src/utils/string-utils.d.ts +28 -0
- package/src/utils/string-utils.d.ts.map +1 -0
- package/src/utils/string-utils.js +63 -0
- package/src/utils/string-utils.js.map +1 -0
- package/src/utils/timezone.d.ts +50 -0
- package/src/utils/timezone.d.ts.map +1 -0
- package/src/utils/timezone.js +74 -0
- package/src/utils/timezone.js.map +1 -0
- package/src/utils/validation.d.ts +40 -0
- package/src/utils/validation.d.ts.map +1 -0
- package/src/utils/validation.js +69 -0
- package/src/utils/validation.js.map +1 -0
- package/src/utils.d.ts +65 -0
- package/src/utils.d.ts.map +1 -0
- package/src/utils.js +129 -0
- package/src/utils.js.map +1 -0
- package/src/validation/{index.ts → index.d.ts} +1 -0
- package/src/validation/index.d.ts.map +1 -0
- package/src/validation/index.js +5 -0
- package/src/validation/index.js.map +1 -0
- package/src/validation/plural-validator.d.ts +46 -0
- package/src/validation/plural-validator.d.ts.map +1 -0
- package/src/validation/plural-validator.js +123 -0
- package/src/validation/plural-validator.js.map +1 -0
- package/src/validation-config.d.ts +12 -0
- package/src/validation-config.d.ts.map +1 -0
- package/src/validation-config.js +3 -0
- package/src/validation-config.js.map +1 -0
- package/src/validation-result.d.ts +13 -0
- package/src/validation-result.d.ts.map +1 -0
- package/src/validation-result.js +3 -0
- package/src/validation-result.js.map +1 -0
- package/LICENSE +0 -21
- package/src/builders/i18n-builder.ts +0 -82
- package/src/component-definition.ts +0 -11
- package/src/component-registration.ts +0 -29
- package/src/component-registry.ts +0 -432
- package/src/context-error-type.ts +0 -7
- package/src/core/component-store.ts +0 -241
- package/src/core/context-manager.ts +0 -113
- package/src/core/enum-registry.ts +0 -106
- package/src/core/i18n-engine.ts +0 -710
- package/src/core/language-registry.ts +0 -345
- package/src/core-i18n.ts +0 -270
- package/src/core-plugin-factory.ts +0 -111
- package/src/core-string-key.ts +0 -59
- package/src/create-translation-adapter.ts +0 -93
- package/src/enum-registry.ts +0 -152
- package/src/errors/context-error.ts +0 -122
- package/src/errors/enhanced-error-base.ts +0 -260
- package/src/errors/handleable.ts +0 -152
- package/src/errors/i18n-error.ts +0 -494
- package/src/errors/simple-typed-error.ts +0 -81
- package/src/errors/translatable-generic.ts +0 -245
- package/src/errors/translatable-handleable-generic.ts +0 -222
- package/src/errors/translatable.ts +0 -138
- package/src/errors/typed-handleable.ts +0 -138
- package/src/errors/typed.ts +0 -617
- package/src/gender/gender-resolver.ts +0 -40
- package/src/global-active-context.ts +0 -266
- package/src/icu/ast.ts +0 -56
- package/src/icu/compiler.ts +0 -96
- package/src/icu/formatter-registry.ts +0 -36
- package/src/icu/formatters/base-formatter.ts +0 -8
- package/src/icu/formatters/date-formatter.ts +0 -30
- package/src/icu/formatters/number-formatter.ts +0 -32
- package/src/icu/formatters/plural-formatter.ts +0 -12
- package/src/icu/formatters/select-formatter.ts +0 -7
- package/src/icu/formatters/selectordinal-formatter.ts +0 -17
- package/src/icu/formatters/time-formatter.ts +0 -30
- package/src/icu/helpers.ts +0 -34
- package/src/icu/parser.ts +0 -242
- package/src/icu/runtime.ts +0 -37
- package/src/icu/tokenizer.ts +0 -212
- package/src/icu/validator.ts +0 -163
- package/src/interfaces/active-context.interface.ts +0 -41
- package/src/interfaces/component-config.interface.ts +0 -17
- package/src/interfaces/engine-config.interface.ts +0 -22
- package/src/interfaces/global-active-context.ts +0 -39
- package/src/interfaces/handleable-error-options.ts +0 -13
- package/src/interfaces/handleable.ts +0 -20
- package/src/interfaces/i18n-engine.interface.ts +0 -57
- package/src/interfaces/language-definition.interface.ts +0 -17
- package/src/interfaces/translation-options.interface.ts +0 -15
- package/src/interfaces/validation-result.interface.ts +0 -24
- package/src/language-codes.ts +0 -40
- package/src/language-definition.ts +0 -13
- package/src/plugin-i18n-engine.ts +0 -707
- package/src/pluralization/language-plural-map.ts +0 -186
- package/src/pluralization/plural-rules.ts +0 -228
- package/src/registry-config.ts +0 -16
- package/src/registry-error-type.ts +0 -19
- package/src/registry-error.ts +0 -100
- package/src/strict-types.ts +0 -35
- package/src/strings/de.ts +0 -75
- package/src/strings/en-GB.ts +0 -74
- package/src/strings/en-US.ts +0 -74
- package/src/strings/es.ts +0 -74
- package/src/strings/fr.ts +0 -75
- package/src/strings/ja.ts +0 -73
- package/src/strings/uk.ts +0 -73
- package/src/strings/zh-CN.ts +0 -72
- package/src/template.ts +0 -72
- package/src/translation-engine.ts +0 -18
- package/src/translation-request.ts +0 -12
- package/src/translation-response.ts +0 -8
- package/src/types/engine.ts +0 -55
- package/src/utils/currency.ts +0 -141
- package/src/utils/html-escape.ts +0 -55
- package/src/utils/lru-cache.ts +0 -76
- package/src/utils/string-utils.ts +0 -77
- package/src/utils/timezone.ts +0 -76
- package/src/utils/validation.ts +0 -66
- package/src/utils.ts +0 -215
- package/src/validation/plural-validator.ts +0 -168
- package/src/validation-config.ts +0 -11
- package/src/validation-result.ts +0 -12
package/src/icu/parser.ts
DELETED
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ICU MessageFormat Parser
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { Tokenizer, Token, TokenType } from './tokenizer';
|
|
6
|
-
import {
|
|
7
|
-
MessageNode,
|
|
8
|
-
LiteralNode,
|
|
9
|
-
ArgumentNode,
|
|
10
|
-
PluralNode,
|
|
11
|
-
SelectNode,
|
|
12
|
-
SelectOrdinalNode,
|
|
13
|
-
NodeType,
|
|
14
|
-
ASTNode,
|
|
15
|
-
} from './ast';
|
|
16
|
-
|
|
17
|
-
export class ParseError extends Error {
|
|
18
|
-
constructor(message: string, public position: number) {
|
|
19
|
-
super(`Parse error at position ${position}: ${message}`);
|
|
20
|
-
this.name = 'ParseError';
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export class Parser {
|
|
25
|
-
private tokens: Token[];
|
|
26
|
-
private position: number = 0;
|
|
27
|
-
private depth: number = 0;
|
|
28
|
-
private readonly MAX_DEPTH = 10;
|
|
29
|
-
|
|
30
|
-
constructor(input: string) {
|
|
31
|
-
if (input.length > 10000) {
|
|
32
|
-
throw new ParseError('Input exceeds maximum length', 0);
|
|
33
|
-
}
|
|
34
|
-
this.tokens = new Tokenizer(input).tokenize();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
parse(): MessageNode {
|
|
38
|
-
return this.parseMessage();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
private parseMessage(): MessageNode {
|
|
42
|
-
if (++this.depth > this.MAX_DEPTH) {
|
|
43
|
-
throw new ParseError(`Maximum nesting depth of ${this.MAX_DEPTH} exceeded`, this.position);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const elements: ASTNode[] = [];
|
|
47
|
-
|
|
48
|
-
while (!this.isAtEnd() && !this.check(TokenType.CLOSE_BRACE)) {
|
|
49
|
-
if (this.check(TokenType.TEXT)) {
|
|
50
|
-
elements.push(this.parseLiteral());
|
|
51
|
-
} else if (this.check(TokenType.OPEN_BRACE)) {
|
|
52
|
-
elements.push(this.parseArgument());
|
|
53
|
-
} else if (this.check(TokenType.HASH)) {
|
|
54
|
-
// # is treated as literal in message context
|
|
55
|
-
this.advance();
|
|
56
|
-
elements.push({ type: NodeType.LITERAL, value: '#' });
|
|
57
|
-
} else {
|
|
58
|
-
this.advance(); // Skip unexpected tokens
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
this.depth--;
|
|
63
|
-
return { type: NodeType.MESSAGE, elements };
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
private parseLiteral(): LiteralNode {
|
|
67
|
-
const token = this.advance();
|
|
68
|
-
return { type: NodeType.LITERAL, value: token.value };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private parseArgument(): ArgumentNode | PluralNode | SelectNode | SelectOrdinalNode {
|
|
72
|
-
this.consume(TokenType.OPEN_BRACE, 'Expected {');
|
|
73
|
-
|
|
74
|
-
const name = this.consume(TokenType.IDENTIFIER, 'Expected argument name').value;
|
|
75
|
-
|
|
76
|
-
// Simple argument: {name}
|
|
77
|
-
if (this.check(TokenType.CLOSE_BRACE)) {
|
|
78
|
-
this.advance();
|
|
79
|
-
return { type: NodeType.ARGUMENT, name };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Formatted argument: {name, type} or {name, type, style}
|
|
83
|
-
this.consume(TokenType.COMMA, 'Expected ,');
|
|
84
|
-
|
|
85
|
-
const format = this.consume(TokenType.IDENTIFIER, 'Expected format type').value;
|
|
86
|
-
|
|
87
|
-
// Check for plural/select/selectordinal
|
|
88
|
-
if (format === 'plural') {
|
|
89
|
-
return this.parsePlural(name);
|
|
90
|
-
}
|
|
91
|
-
if (format === 'select') {
|
|
92
|
-
return this.parseSelect(name);
|
|
93
|
-
}
|
|
94
|
-
if (format === 'selectordinal') {
|
|
95
|
-
return this.parseSelectOrdinal(name);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Regular formatted argument: {name, type, style}
|
|
99
|
-
let style: string | undefined;
|
|
100
|
-
if (this.check(TokenType.COMMA)) {
|
|
101
|
-
this.advance();
|
|
102
|
-
style = this.consume(TokenType.IDENTIFIER, 'Expected style').value;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
this.consume(TokenType.CLOSE_BRACE, 'Expected }');
|
|
106
|
-
|
|
107
|
-
return { type: NodeType.ARGUMENT, name, format, style };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
private parsePlural(name: string): PluralNode {
|
|
111
|
-
this.consume(TokenType.COMMA, 'Expected ,');
|
|
112
|
-
this.skipWhitespace();
|
|
113
|
-
|
|
114
|
-
const cases: Record<string, MessageNode> = {};
|
|
115
|
-
let offset: number | undefined;
|
|
116
|
-
|
|
117
|
-
// Parse offset if present
|
|
118
|
-
if (this.check(TokenType.IDENTIFIER) && this.peek().value === 'offset') {
|
|
119
|
-
this.advance(); // offset
|
|
120
|
-
this.skipWhitespace();
|
|
121
|
-
this.consume(TokenType.IDENTIFIER, 'Expected offset value'); // number
|
|
122
|
-
offset = 0; // Simplified for now
|
|
123
|
-
this.skipWhitespace();
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Parse cases
|
|
127
|
-
while (!this.check(TokenType.CLOSE_BRACE) && !this.isAtEnd()) {
|
|
128
|
-
this.skipWhitespace();
|
|
129
|
-
if (this.check(TokenType.CLOSE_BRACE)) break;
|
|
130
|
-
|
|
131
|
-
const caseKey = this.consume(TokenType.IDENTIFIER, 'Expected case key').value;
|
|
132
|
-
this.skipWhitespace();
|
|
133
|
-
this.consume(TokenType.OPEN_BRACE, 'Expected {');
|
|
134
|
-
const caseMessage = this.parseMessage();
|
|
135
|
-
this.consume(TokenType.CLOSE_BRACE, 'Expected }');
|
|
136
|
-
cases[caseKey] = caseMessage;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (Object.keys(cases).length === 0) {
|
|
140
|
-
throw new ParseError('Plural must have at least one case', this.peek().position);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
this.consume(TokenType.CLOSE_BRACE, 'Expected }');
|
|
144
|
-
|
|
145
|
-
return { type: NodeType.PLURAL, name, offset, cases };
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
private parseSelect(name: string): SelectNode {
|
|
149
|
-
this.consume(TokenType.COMMA, 'Expected ,');
|
|
150
|
-
this.skipWhitespace();
|
|
151
|
-
|
|
152
|
-
const cases: Record<string, MessageNode> = {};
|
|
153
|
-
|
|
154
|
-
// Parse cases
|
|
155
|
-
while (!this.check(TokenType.CLOSE_BRACE) && !this.isAtEnd()) {
|
|
156
|
-
this.skipWhitespace();
|
|
157
|
-
if (this.check(TokenType.CLOSE_BRACE)) break;
|
|
158
|
-
|
|
159
|
-
const caseKey = this.consume(TokenType.IDENTIFIER, 'Expected case key').value;
|
|
160
|
-
this.skipWhitespace();
|
|
161
|
-
this.consume(TokenType.OPEN_BRACE, 'Expected {');
|
|
162
|
-
const caseMessage = this.parseMessage();
|
|
163
|
-
this.consume(TokenType.CLOSE_BRACE, 'Expected }');
|
|
164
|
-
cases[caseKey] = caseMessage;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
this.consume(TokenType.CLOSE_BRACE, 'Expected }');
|
|
168
|
-
|
|
169
|
-
return { type: NodeType.SELECT, name, cases };
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
private parseSelectOrdinal(name: string): SelectOrdinalNode {
|
|
173
|
-
this.consume(TokenType.COMMA, 'Expected ,');
|
|
174
|
-
this.skipWhitespace();
|
|
175
|
-
|
|
176
|
-
const cases: Record<string, MessageNode> = {};
|
|
177
|
-
let offset: number | undefined;
|
|
178
|
-
|
|
179
|
-
// Parse offset if present
|
|
180
|
-
if (this.check(TokenType.IDENTIFIER) && this.peek().value === 'offset') {
|
|
181
|
-
this.advance(); // offset
|
|
182
|
-
this.skipWhitespace();
|
|
183
|
-
this.consume(TokenType.IDENTIFIER, 'Expected offset value'); // number
|
|
184
|
-
offset = 0; // Simplified for now
|
|
185
|
-
this.skipWhitespace();
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Parse cases
|
|
189
|
-
while (!this.check(TokenType.CLOSE_BRACE) && !this.isAtEnd()) {
|
|
190
|
-
this.skipWhitespace();
|
|
191
|
-
if (this.check(TokenType.CLOSE_BRACE)) break;
|
|
192
|
-
|
|
193
|
-
const caseKey = this.consume(TokenType.IDENTIFIER, 'Expected case key').value;
|
|
194
|
-
this.skipWhitespace();
|
|
195
|
-
this.consume(TokenType.OPEN_BRACE, 'Expected {');
|
|
196
|
-
const caseMessage = this.parseMessage();
|
|
197
|
-
this.consume(TokenType.CLOSE_BRACE, 'Expected }');
|
|
198
|
-
cases[caseKey] = caseMessage;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
this.consume(TokenType.CLOSE_BRACE, 'Expected }');
|
|
202
|
-
|
|
203
|
-
return { type: NodeType.SELECTORDINAL, name, offset, cases };
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
private check(type: TokenType): boolean {
|
|
207
|
-
if (this.isAtEnd()) return false;
|
|
208
|
-
return this.peek().type === type;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
private advance(): Token {
|
|
212
|
-
if (!this.isAtEnd()) this.position++;
|
|
213
|
-
return this.previous();
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
private isAtEnd(): boolean {
|
|
217
|
-
return this.peek().type === TokenType.EOF;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
private peek(): Token {
|
|
221
|
-
return this.tokens[this.position];
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
private previous(): Token {
|
|
225
|
-
return this.tokens[this.position - 1];
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
private consume(type: TokenType, message: string): Token {
|
|
229
|
-
if (this.check(type)) return this.advance();
|
|
230
|
-
throw new ParseError(message, this.peek().position);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
private skipWhitespace(): void {
|
|
234
|
-
while (this.check(TokenType.TEXT) && this.peek().value.trim() === '') {
|
|
235
|
-
this.advance();
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
export function parse(input: string): MessageNode {
|
|
241
|
-
return new Parser(input).parse();
|
|
242
|
-
}
|
package/src/icu/runtime.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { parse } from './parser';
|
|
2
|
-
import { validate } from './validator';
|
|
3
|
-
import { Compiler, CompiledMessage } from './compiler';
|
|
4
|
-
import { FormatterRegistry } from './formatter-registry';
|
|
5
|
-
import { FormatterContext } from './formatters/base-formatter';
|
|
6
|
-
import { LRUCache } from '../utils/lru-cache';
|
|
7
|
-
|
|
8
|
-
export class Runtime {
|
|
9
|
-
private compiler: Compiler;
|
|
10
|
-
private cache = new LRUCache<string, CompiledMessage>(1000);
|
|
11
|
-
|
|
12
|
-
constructor(registry?: FormatterRegistry) {
|
|
13
|
-
this.compiler = new Compiler(registry);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
format(message: string, values: Record<string, any>, context: FormatterContext): string {
|
|
17
|
-
if (message.length > 10000) {
|
|
18
|
-
throw new Error('Message exceeds maximum length');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const cacheKey = `${context.locale}:${message}`;
|
|
22
|
-
let compiled = this.cache.get(cacheKey);
|
|
23
|
-
|
|
24
|
-
if (!compiled) {
|
|
25
|
-
const ast = parse(message);
|
|
26
|
-
validate(ast);
|
|
27
|
-
compiled = this.compiler.compile(ast);
|
|
28
|
-
this.cache.set(cacheKey, compiled);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return compiled(values, context);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
clearCache(): void {
|
|
35
|
-
this.cache.clear();
|
|
36
|
-
}
|
|
37
|
-
}
|
package/src/icu/tokenizer.ts
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ICU MessageFormat Tokenizer
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export enum TokenType {
|
|
6
|
-
TEXT = 'TEXT',
|
|
7
|
-
OPEN_BRACE = 'OPEN_BRACE',
|
|
8
|
-
CLOSE_BRACE = 'CLOSE_BRACE',
|
|
9
|
-
COMMA = 'COMMA',
|
|
10
|
-
HASH = 'HASH',
|
|
11
|
-
IDENTIFIER = 'IDENTIFIER',
|
|
12
|
-
EOF = 'EOF',
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface Token {
|
|
16
|
-
type: TokenType;
|
|
17
|
-
value: string;
|
|
18
|
-
position: number;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export class Tokenizer {
|
|
22
|
-
private input: string;
|
|
23
|
-
private position: number = 0;
|
|
24
|
-
private length: number;
|
|
25
|
-
private braceDepth: number = 0;
|
|
26
|
-
private lastTokenType: TokenType | null = null;
|
|
27
|
-
private formatDepths: Set<number> = new Set(); // Tracks which depths are format specs
|
|
28
|
-
private lastIdentifierWasAtFormatDepth: boolean = false;
|
|
29
|
-
|
|
30
|
-
constructor(input: string) {
|
|
31
|
-
this.input = input;
|
|
32
|
-
this.length = input.length;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
tokenize(): Token[] {
|
|
36
|
-
const tokens: Token[] = [];
|
|
37
|
-
while (this.position < this.length) {
|
|
38
|
-
const token = this.nextToken();
|
|
39
|
-
if (token.type !== TokenType.EOF) {
|
|
40
|
-
tokens.push(token);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
tokens.push({ type: TokenType.EOF, value: '', position: this.position });
|
|
44
|
-
return tokens;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
private nextToken(): Token {
|
|
48
|
-
if (this.position >= this.length) {
|
|
49
|
-
return { type: TokenType.EOF, value: '', position: this.position };
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const char = this.input[this.position];
|
|
53
|
-
|
|
54
|
-
// Handle escape sequences - quoted braces
|
|
55
|
-
if (char === "'") {
|
|
56
|
-
const next = this.peek();
|
|
57
|
-
if (next === '{' || next === '}') {
|
|
58
|
-
const pos = this.position;
|
|
59
|
-
this.position++; // Skip quote
|
|
60
|
-
this.position++; // Skip brace
|
|
61
|
-
return { type: TokenType.TEXT, value: next, position: pos };
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Special characters
|
|
66
|
-
if (char === '{') {
|
|
67
|
-
const prevDepth = this.braceDepth;
|
|
68
|
-
this.braceDepth++;
|
|
69
|
-
// Add to format depths if:
|
|
70
|
-
// 1. Start of message (null)
|
|
71
|
-
// 2. After TEXT - new format in message (unless after case name)
|
|
72
|
-
// 3. After CLOSE_BRACE at depth 0 - consecutive formats
|
|
73
|
-
// 4. After OPEN_BRACE - nested format (unless after case name)
|
|
74
|
-
// NOT after IDENTIFIER at format depth - that's a case name, next brace is message content
|
|
75
|
-
if (this.lastTokenType === null ||
|
|
76
|
-
(this.lastTokenType === TokenType.TEXT && !this.lastIdentifierWasAtFormatDepth) ||
|
|
77
|
-
(this.lastTokenType === TokenType.CLOSE_BRACE && prevDepth === 0) ||
|
|
78
|
-
(this.lastTokenType === TokenType.OPEN_BRACE && !this.lastIdentifierWasAtFormatDepth)) {
|
|
79
|
-
this.formatDepths.add(this.braceDepth);
|
|
80
|
-
}
|
|
81
|
-
this.lastIdentifierWasAtFormatDepth = false;
|
|
82
|
-
const token = { type: TokenType.OPEN_BRACE, value: char, position: this.position++ };
|
|
83
|
-
this.lastTokenType = TokenType.OPEN_BRACE;
|
|
84
|
-
return token;
|
|
85
|
-
}
|
|
86
|
-
if (char === '}') {
|
|
87
|
-
this.formatDepths.delete(this.braceDepth);
|
|
88
|
-
this.braceDepth--;
|
|
89
|
-
this.lastIdentifierWasAtFormatDepth = false; // Reset after closing
|
|
90
|
-
const token = { type: TokenType.CLOSE_BRACE, value: char, position: this.position++ };
|
|
91
|
-
this.lastTokenType = TokenType.CLOSE_BRACE;
|
|
92
|
-
return token;
|
|
93
|
-
}
|
|
94
|
-
if (char === ',') {
|
|
95
|
-
// Comma at depth 1+ is format separator, at depth 0 is text
|
|
96
|
-
if (this.braceDepth >= 1) {
|
|
97
|
-
const token = { type: TokenType.COMMA, value: char, position: this.position++ };
|
|
98
|
-
this.lastTokenType = TokenType.COMMA;
|
|
99
|
-
return token;
|
|
100
|
-
}
|
|
101
|
-
// At depth 0, comma is just text
|
|
102
|
-
return this.readText();
|
|
103
|
-
}
|
|
104
|
-
if (char === '#') {
|
|
105
|
-
return { type: TokenType.HASH, value: char, position: this.position++ };
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Whitespace - skip at format level OR after identifier at depth 1
|
|
109
|
-
if (this.isWhitespace(char) && (this.isAtFormatLevel() || (this.braceDepth === 1 && this.lastTokenType === TokenType.IDENTIFIER))) {
|
|
110
|
-
this.position++;
|
|
111
|
-
return this.nextToken();
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Identifier (variable names, keywords) - at format level
|
|
115
|
-
if (this.isIdentifierStart(char)) {
|
|
116
|
-
if (this.isAtFormatLevel()) {
|
|
117
|
-
return this.readIdentifier();
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Text (everything else)
|
|
122
|
-
return this.readText();
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private readIdentifier(): Token {
|
|
126
|
-
const start = this.position;
|
|
127
|
-
while (this.position < this.length && this.isIdentifierChar(this.input[this.position])) {
|
|
128
|
-
this.position++;
|
|
129
|
-
}
|
|
130
|
-
const token = {
|
|
131
|
-
type: TokenType.IDENTIFIER,
|
|
132
|
-
value: this.input.substring(start, this.position),
|
|
133
|
-
position: start,
|
|
134
|
-
};
|
|
135
|
-
this.lastTokenType = TokenType.IDENTIFIER;
|
|
136
|
-
this.lastIdentifierWasAtFormatDepth = this.formatDepths.has(this.braceDepth);
|
|
137
|
-
return token;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
private readText(): Token {
|
|
141
|
-
const start = this.position;
|
|
142
|
-
let text = '';
|
|
143
|
-
|
|
144
|
-
while (this.position < this.length) {
|
|
145
|
-
const char = this.input[this.position];
|
|
146
|
-
|
|
147
|
-
// Handle escaped quotes - stop before them
|
|
148
|
-
if (char === "'" && (this.peek() === '{' || this.peek() === '}')) {
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Stop at special characters (but not if they're escaped)
|
|
153
|
-
if (char === '{' || char === '#') {
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// For }, only stop if we're inside braces
|
|
158
|
-
if (char === '}' && this.braceDepth > 0) {
|
|
159
|
-
break;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Stop at comma if we're at format level (depth >= 1)
|
|
163
|
-
if (char === ',' && this.braceDepth >= 1) {
|
|
164
|
-
break;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
text += char;
|
|
168
|
-
this.position++;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const token = {
|
|
172
|
-
type: TokenType.TEXT,
|
|
173
|
-
value: text,
|
|
174
|
-
position: start,
|
|
175
|
-
};
|
|
176
|
-
this.lastTokenType = TokenType.TEXT;
|
|
177
|
-
// Don't reset the identifier flag for whitespace-only text
|
|
178
|
-
if (text.trim() !== '') {
|
|
179
|
-
this.lastIdentifierWasAtFormatDepth = false;
|
|
180
|
-
}
|
|
181
|
-
return token;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
private peek(): string {
|
|
185
|
-
return this.position + 1 < this.length ? this.input[this.position + 1] : '';
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
private isIdentifierStart(char: string): boolean {
|
|
189
|
-
return /[a-zA-Z_]/.test(char);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
private isIdentifierChar(char: string): boolean {
|
|
193
|
-
return /[a-zA-Z0-9_]/.test(char);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
private isWhitespace(char: string): boolean {
|
|
197
|
-
return /\s/.test(char);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
private isAtFormatLevel(): boolean {
|
|
201
|
-
// We're at format level if current depth is marked as format AND:
|
|
202
|
-
// 1. After OPEN_BRACE (expecting variable name)
|
|
203
|
-
// 2. After COMMA (expecting format type or case name)
|
|
204
|
-
// 3. After CLOSE_BRACE (just finished a case message, expecting another case name)
|
|
205
|
-
if (!this.formatDepths.has(this.braceDepth)) {
|
|
206
|
-
return false;
|
|
207
|
-
}
|
|
208
|
-
return this.lastTokenType === TokenType.OPEN_BRACE ||
|
|
209
|
-
this.lastTokenType === TokenType.COMMA ||
|
|
210
|
-
this.lastTokenType === TokenType.CLOSE_BRACE;
|
|
211
|
-
}
|
|
212
|
-
}
|
package/src/icu/validator.ts
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { MessageNode, NodeType, ArgumentNode, PluralNode, SelectNode, SelectOrdinalNode } from './ast';
|
|
2
|
-
|
|
3
|
-
export class ValidationError extends Error {
|
|
4
|
-
constructor(message: string) {
|
|
5
|
-
super(message);
|
|
6
|
-
this.name = 'ValidationError';
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface ValidationOptions {
|
|
11
|
-
requireOtherCase?: boolean;
|
|
12
|
-
allowCircularReferences?: boolean;
|
|
13
|
-
maxDepth?: number;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const DEFAULT_OPTIONS: ValidationOptions = {
|
|
17
|
-
requireOtherCase: true,
|
|
18
|
-
allowCircularReferences: false,
|
|
19
|
-
maxDepth: 10,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export function validate(ast: MessageNode, options: ValidationOptions = {}): void {
|
|
23
|
-
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
24
|
-
const context = new ValidationContext(opts);
|
|
25
|
-
validateMessage(ast, context);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
class ValidationContext {
|
|
29
|
-
private argumentNames = new Set<string>();
|
|
30
|
-
private currentDepth = 0;
|
|
31
|
-
|
|
32
|
-
constructor(public options: ValidationOptions) {}
|
|
33
|
-
|
|
34
|
-
addArgument(name: string): void {
|
|
35
|
-
this.argumentNames.add(name);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
hasArgument(name: string): boolean {
|
|
39
|
-
return this.argumentNames.has(name);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
enterDepth(): void {
|
|
43
|
-
this.currentDepth++;
|
|
44
|
-
if (this.currentDepth > this.options.maxDepth!) {
|
|
45
|
-
throw new ValidationError(`Maximum nesting depth of ${this.options.maxDepth} exceeded`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
exitDepth(): void {
|
|
50
|
-
this.currentDepth--;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function validateMessage(node: MessageNode, context: ValidationContext): void {
|
|
55
|
-
for (const element of node.elements) {
|
|
56
|
-
validateNode(element, context);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function validateNode(node: any, context: ValidationContext): void {
|
|
61
|
-
switch (node.type) {
|
|
62
|
-
case NodeType.LITERAL:
|
|
63
|
-
break;
|
|
64
|
-
case NodeType.ARGUMENT:
|
|
65
|
-
validateArgument(node, context);
|
|
66
|
-
break;
|
|
67
|
-
case NodeType.PLURAL:
|
|
68
|
-
validatePlural(node, context);
|
|
69
|
-
break;
|
|
70
|
-
case NodeType.SELECT:
|
|
71
|
-
validateSelect(node, context);
|
|
72
|
-
break;
|
|
73
|
-
case NodeType.SELECTORDINAL:
|
|
74
|
-
validateSelectOrdinal(node, context);
|
|
75
|
-
break;
|
|
76
|
-
default:
|
|
77
|
-
throw new ValidationError(`Unknown node type: ${node.type}`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function validateArgument(node: ArgumentNode, context: ValidationContext): void {
|
|
82
|
-
if (!node.name || node.name.trim() === '') {
|
|
83
|
-
throw new ValidationError('Argument name cannot be empty');
|
|
84
|
-
}
|
|
85
|
-
context.addArgument(node.name);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function validatePlural(node: PluralNode, context: ValidationContext): void {
|
|
89
|
-
if (!node.name || node.name.trim() === '') {
|
|
90
|
-
throw new ValidationError('Plural variable name cannot be empty');
|
|
91
|
-
}
|
|
92
|
-
context.addArgument(node.name);
|
|
93
|
-
|
|
94
|
-
if (!node.cases || Object.keys(node.cases).length === 0) {
|
|
95
|
-
throw new ValidationError(`Plural '${node.name}' must have at least one case`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (context.options.requireOtherCase && !node.cases.other) {
|
|
99
|
-
throw new ValidationError(`Plural '${node.name}' must have an 'other' case`);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const validCases = ['zero', 'one', 'two', 'few', 'many', 'other'];
|
|
103
|
-
for (const caseName of Object.keys(node.cases)) {
|
|
104
|
-
if (!validCases.includes(caseName)) {
|
|
105
|
-
throw new ValidationError(`Invalid plural case '${caseName}' in '${node.name}'`);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
context.enterDepth();
|
|
110
|
-
for (const caseMessage of Object.values(node.cases)) {
|
|
111
|
-
validateMessage(caseMessage, context);
|
|
112
|
-
}
|
|
113
|
-
context.exitDepth();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function validateSelect(node: SelectNode, context: ValidationContext): void {
|
|
117
|
-
if (!node.name || node.name.trim() === '') {
|
|
118
|
-
throw new ValidationError('Select variable name cannot be empty');
|
|
119
|
-
}
|
|
120
|
-
context.addArgument(node.name);
|
|
121
|
-
|
|
122
|
-
if (!node.cases || Object.keys(node.cases).length === 0) {
|
|
123
|
-
throw new ValidationError(`Select '${node.name}' must have at least one case`);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (context.options.requireOtherCase && !node.cases.other) {
|
|
127
|
-
throw new ValidationError(`Select '${node.name}' must have an 'other' case`);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
context.enterDepth();
|
|
131
|
-
for (const caseMessage of Object.values(node.cases)) {
|
|
132
|
-
validateMessage(caseMessage, context);
|
|
133
|
-
}
|
|
134
|
-
context.exitDepth();
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function validateSelectOrdinal(node: SelectOrdinalNode, context: ValidationContext): void {
|
|
138
|
-
if (!node.name || node.name.trim() === '') {
|
|
139
|
-
throw new ValidationError('SelectOrdinal variable name cannot be empty');
|
|
140
|
-
}
|
|
141
|
-
context.addArgument(node.name);
|
|
142
|
-
|
|
143
|
-
if (!node.cases || Object.keys(node.cases).length === 0) {
|
|
144
|
-
throw new ValidationError(`SelectOrdinal '${node.name}' must have at least one case`);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (context.options.requireOtherCase && !node.cases.other) {
|
|
148
|
-
throw new ValidationError(`SelectOrdinal '${node.name}' must have an 'other' case`);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const validCases = ['zero', 'one', 'two', 'few', 'many', 'other'];
|
|
152
|
-
for (const caseName of Object.keys(node.cases)) {
|
|
153
|
-
if (!validCases.includes(caseName)) {
|
|
154
|
-
throw new ValidationError(`Invalid selectordinal case '${caseName}' in '${node.name}'`);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
context.enterDepth();
|
|
159
|
-
for (const caseMessage of Object.values(node.cases)) {
|
|
160
|
-
validateMessage(caseMessage, context);
|
|
161
|
-
}
|
|
162
|
-
context.exitDepth();
|
|
163
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { LanguageContextSpace } from '../types';
|
|
2
|
-
import type { CurrencyCode } from '../utils/currency';
|
|
3
|
-
import type { Timezone } from '../utils/timezone';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Represents the active internationalization context for user and admin interfaces,
|
|
7
|
-
* including language, currency, and timezone settings.
|
|
8
|
-
*
|
|
9
|
-
* @template TLanguage The type of language codes (e.g., 'en-US', 'fr').
|
|
10
|
-
*/
|
|
11
|
-
export interface IActiveContext<TLanguage extends string> {
|
|
12
|
-
/**
|
|
13
|
-
* The default language for the user-facing application.
|
|
14
|
-
*/
|
|
15
|
-
language: TLanguage;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* The default language for the admin interface.
|
|
19
|
-
*/
|
|
20
|
-
adminLanguage: TLanguage;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* The default currency code for the user-facing application.
|
|
24
|
-
*/
|
|
25
|
-
currencyCode: CurrencyCode;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* The current language context space (e.g., 'user' or 'admin').
|
|
29
|
-
*/
|
|
30
|
-
currentContext: LanguageContextSpace;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* The default timezone for the user-facing application.
|
|
34
|
-
*/
|
|
35
|
-
timezone: Timezone;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* The default timezone for the admin interface.
|
|
39
|
-
*/
|
|
40
|
-
adminTimezone: Timezone;
|
|
41
|
-
}
|