From fa75f9a34a93b006045cd416599f442ed73aa340 Mon Sep 17 00:00:00 2001 From: isc-auf Date: Tue, 25 Apr 2023 10:31:36 +0200 Subject: [PATCH] feat(transloco): add intlmessageformat transpiler Adding an alternative messageformat transpiler based on formatjs/intlmessageformat white_check_mark Closes: #364 Signed-off-by: isc-auf --- angular.json | 1 + .../.eslintrc.json | 36 ++ libs/transloco-intlmessageformat/CHANGELOG.md | 3 + libs/transloco-intlmessageformat/LICENSE | 22 ++ libs/transloco-intlmessageformat/README.md | 3 + .../transloco-intlmessageformat/karma.conf.js | 16 + .../ng-package.json | 10 + libs/transloco-intlmessageformat/package.json | 38 +++ libs/transloco-intlmessageformat/project.json | 46 +++ libs/transloco-intlmessageformat/src/index.ts | 6 + .../src/lib/intlmessageformat.config.ts | 17 + .../src/lib/intlmessageformat.factory.ts | 42 +++ .../src/lib/intlmessageformat.module.ts | 25 ++ .../lib/intlmessageformat.transpiler.spec.ts | 226 +++++++++++++ .../src/lib/intlmessageformat.transpiler.ts | 71 ++++ .../src/test-setup.ts | 24 ++ .../transloco-intlmessageformat/tsconfig.json | 27 ++ .../tsconfig.lib.json | 14 + .../tsconfig.lib.prod.json | 9 + .../tsconfig.spec.json | 10 + package-lock.json | 317 +++++++++++++++++- package.json | 2 + tsconfig.base.json | 3 + 23 files changed, 966 insertions(+), 2 deletions(-) create mode 100644 libs/transloco-intlmessageformat/.eslintrc.json create mode 100644 libs/transloco-intlmessageformat/CHANGELOG.md create mode 100644 libs/transloco-intlmessageformat/LICENSE create mode 100644 libs/transloco-intlmessageformat/README.md create mode 100644 libs/transloco-intlmessageformat/karma.conf.js create mode 100644 libs/transloco-intlmessageformat/ng-package.json create mode 100644 libs/transloco-intlmessageformat/package.json create mode 100644 libs/transloco-intlmessageformat/project.json create mode 100644 libs/transloco-intlmessageformat/src/index.ts create mode 100644 libs/transloco-intlmessageformat/src/lib/intlmessageformat.config.ts create mode 100644 libs/transloco-intlmessageformat/src/lib/intlmessageformat.factory.ts create mode 100644 libs/transloco-intlmessageformat/src/lib/intlmessageformat.module.ts create mode 100644 libs/transloco-intlmessageformat/src/lib/intlmessageformat.transpiler.spec.ts create mode 100644 libs/transloco-intlmessageformat/src/lib/intlmessageformat.transpiler.ts create mode 100644 libs/transloco-intlmessageformat/src/test-setup.ts create mode 100644 libs/transloco-intlmessageformat/tsconfig.json create mode 100644 libs/transloco-intlmessageformat/tsconfig.lib.json create mode 100644 libs/transloco-intlmessageformat/tsconfig.lib.prod.json create mode 100644 libs/transloco-intlmessageformat/tsconfig.spec.json diff --git a/angular.json b/angular.json index 6a14d6c37..febd274e0 100644 --- a/angular.json +++ b/angular.json @@ -4,6 +4,7 @@ "transloco": "libs/transloco", "transloco-locale": "libs/transloco-locale", "transloco-messageformat": "libs/transloco-messageformat", + "transloco-intlmessageformat": "libs/transloco-intlmessageformat", "transloco-optimize": "libs/transloco-optimize", "transloco-persist-lang": "libs/transloco-persist-lang", "transloco-persist-translations": "libs/transloco-persist-translations", diff --git a/libs/transloco-intlmessageformat/.eslintrc.json b/libs/transloco-intlmessageformat/.eslintrc.json new file mode 100644 index 000000000..6f907933f --- /dev/null +++ b/libs/transloco-intlmessageformat/.eslintrc.json @@ -0,0 +1,36 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nrwl/nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "translocoNxShell", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "transloco-nx-shell", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nrwl/nx/angular-template"], + "rules": {} + } + ] +} diff --git a/libs/transloco-intlmessageformat/CHANGELOG.md b/libs/transloco-intlmessageformat/CHANGELOG.md new file mode 100644 index 000000000..99e9777f2 --- /dev/null +++ b/libs/transloco-intlmessageformat/CHANGELOG.md @@ -0,0 +1,3 @@ +# Changelog + +This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). diff --git a/libs/transloco-intlmessageformat/LICENSE b/libs/transloco-intlmessageformat/LICENSE new file mode 100644 index 000000000..67df55285 --- /dev/null +++ b/libs/transloco-intlmessageformat/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2019-2021 Netanel Basal, Shahar Kazaz, and Itay Oded. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/libs/transloco-intlmessageformat/README.md b/libs/transloco-intlmessageformat/README.md new file mode 100644 index 000000000..134a7a36d --- /dev/null +++ b/libs/transloco-intlmessageformat/README.md @@ -0,0 +1,3 @@ +# Transloco MessageFormat + +Please visit the [official Transloco docs](https://ngneat.github.io/transloco/docs/plugins/intlmessage-format). diff --git a/libs/transloco-intlmessageformat/karma.conf.js b/libs/transloco-intlmessageformat/karma.conf.js new file mode 100644 index 000000000..1dc0f4259 --- /dev/null +++ b/libs/transloco-intlmessageformat/karma.conf.js @@ -0,0 +1,16 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +const { join } = require('path'); +const getBaseKarmaConfig = require('../../karma.conf'); + +module.exports = function (config) { + const baseConfig = getBaseKarmaConfig(); + config.set({ + ...baseConfig, + coverageIstanbulReporter: { + ...baseConfig.coverageIstanbulReporter, + dir: join(__dirname, '../../coverage/libs/transloco-intlmessageformat'), + }, + }); +}; diff --git a/libs/transloco-intlmessageformat/ng-package.json b/libs/transloco-intlmessageformat/ng-package.json new file mode 100644 index 000000000..2181dfca3 --- /dev/null +++ b/libs/transloco-intlmessageformat/ng-package.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/libs/transloco-intlmessageformat", + "lib": { + "entryFile": "src/index.ts" + }, + "allowedNonPeerDependencies": [ + "@formatjs/intl" + ] +} diff --git a/libs/transloco-intlmessageformat/package.json b/libs/transloco-intlmessageformat/package.json new file mode 100644 index 000000000..fff2d7d69 --- /dev/null +++ b/libs/transloco-intlmessageformat/package.json @@ -0,0 +1,38 @@ +{ + "name": "@ngneat/transloco-intlmessageformat", + "version": "4.3.0", + "description": "Transpiler for Transloco that uses formatjs/intlmessageformat to compile translations using ICU syntax for handling pluralization and gender", + "publishConfig": { + "access": "public" + }, + "bugs": { + "url": "https://github.com/ngneat/transloco/issues" + }, + "homepage": "https://ngneat.github.io/transloco/docs/plugins/intlmessage-format", + "repository": { + "type": "git", + "url": "https://github.com/ngneat/transloco" + }, + "keywords": [ + "angular", + "angular 2", + "declension", + "i18n", + "icu", + "gender", + "intlmessageformat", + "transloco", + "pluralization", + "translate" + ], + "license": "MIT", + "peerDependencies": { + "@angular/core": ">=13.0.0", + "@ngneat/transloco": ">=4.2.0", + "rxjs": ">=6.0.0" + }, + "dependencies": { + "@formatjs/intl": "2.3.4", + "tslib": "^2.2.0" + } +} diff --git a/libs/transloco-intlmessageformat/project.json b/libs/transloco-intlmessageformat/project.json new file mode 100644 index 000000000..f63f5bcb7 --- /dev/null +++ b/libs/transloco-intlmessageformat/project.json @@ -0,0 +1,46 @@ +{ + "projectType": "library", + "sourceRoot": "libs/transloco-intlmessageformat/src", + "prefix": "transloco-nx-shell", + "targets": { + "build": { + "executor": "@nrwl/angular:package", + "outputs": ["dist/libs/transloco-intlmessageformat"], + "options": { + "updateBuildableProjectDepsInPackageJson": false, + "project": "libs/transloco-intlmessageformat/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "libs/transloco-intlmessageformat/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "libs/transloco-intlmessageformat/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "libs/transloco-intlmessageformat/src/test-setup.ts", + "tsConfig": "libs/transloco-intlmessageformat/tsconfig.spec.json", + "karmaConfig": "libs/transloco-intlmessageformat/karma.conf.js" + } + }, + "lint": { + "executor": "@nrwl/linter:eslint", + "options": { + "lintFilePatterns": [ + "libs/transloco-intlmessageformat/src/**/*.ts", + "libs/transloco-intlmessageformat/src/**/*.html" + ] + }, + "outputs": ["{options.outputFile}"] + }, + "version": { + "executor": "@jscutlery/semver:version" + } + }, + "tags": [] +} diff --git a/libs/transloco-intlmessageformat/src/index.ts b/libs/transloco-intlmessageformat/src/index.ts new file mode 100644 index 000000000..923c78a35 --- /dev/null +++ b/libs/transloco-intlmessageformat/src/index.ts @@ -0,0 +1,6 @@ +export { + TRANSLOCO_INTL_MESSAGE_FORMAT_CONFIG, + IntlMessageFormatConfig, +} from './lib/intlmessageformat.config'; +export { TranslocoIntlMessageFormatModule } from './lib/intlmessageformat.module'; +export { IntlMessageFormatTranspiler } from './lib/intlmessageformat.transpiler'; diff --git a/libs/transloco-intlmessageformat/src/lib/intlmessageformat.config.ts b/libs/transloco-intlmessageformat/src/lib/intlmessageformat.config.ts new file mode 100644 index 000000000..6812c4ecd --- /dev/null +++ b/libs/transloco-intlmessageformat/src/lib/intlmessageformat.config.ts @@ -0,0 +1,17 @@ +import { InjectionToken } from '@angular/core'; + +import IntlMessageFormat from 'intl-messageformat'; +import { Formats } from 'intl-messageformat/src/formatters'; +import { Options } from 'intl-messageformat/src/core'; + +export const TRANSLOCO_INTL_MESSAGE_FORMAT_CONFIG = + new InjectionToken('TRANSLOCO_INTL_MESSAGE_FORMAT_CONFIG'); + +export type MFLocale = ConstructorParameters[1]; + +export interface IntlMessageFormatConfig { + locales?: MFLocale; + formats?: Partial + opts?: Options, + enableCache?: boolean; +} diff --git a/libs/transloco-intlmessageformat/src/lib/intlmessageformat.factory.ts b/libs/transloco-intlmessageformat/src/lib/intlmessageformat.factory.ts new file mode 100644 index 000000000..3da64b4b4 --- /dev/null +++ b/libs/transloco-intlmessageformat/src/lib/intlmessageformat.factory.ts @@ -0,0 +1,42 @@ +import { MFLocale } from './intlmessageformat.config'; + +import IntlMessageFormat from 'intl-messageformat'; +import { Formats, PrimitiveType } from 'intl-messageformat/src/formatters'; +import { Options } from 'intl-messageformat/src/core'; +import { MessageFormatElement } from '@formatjs/icu-messageformat-parser'; + +export type MFFactoryFn = (message: string | MessageFormatElement[], values?: Record) => string | string[] | undefined; + +export function defaultFactory( + locales: MFLocale, + formats?: Partial, + opts?: Options +): MFFactoryFn { + return (message: string | MessageFormatElement[], values?: Record) => { + return new IntlMessageFormat(message, locales, formats, opts).format(values); + } +} + +const cache = new Map(); + +export function cachedFactory( + locales: MFLocale, + formats?: Partial, + opts?: Options +): MFFactoryFn { + return (message: string | MessageFormatElement[], values?: Record) => { + const localeKey = `__${locales?.toString() || IntlMessageFormat.defaultLocale}__`; + + const cacheKey = `${localeKey}${values}`; + const cachedMsg = cache.get(cacheKey); + + if (cachedMsg) { + return cachedMsg; + } + + const msg = defaultFactory(locales, formats, opts)(message, values); + cache.set(cacheKey, msg); + + return msg; + } +} diff --git a/libs/transloco-intlmessageformat/src/lib/intlmessageformat.module.ts b/libs/transloco-intlmessageformat/src/lib/intlmessageformat.module.ts new file mode 100644 index 000000000..f76843ef0 --- /dev/null +++ b/libs/transloco-intlmessageformat/src/lib/intlmessageformat.module.ts @@ -0,0 +1,25 @@ +import { NgModule, ModuleWithProviders } from '@angular/core'; +import { TRANSLOCO_TRANSPILER } from '@ngneat/transloco'; +import { IntlMessageFormatTranspiler } from './intlmessageformat.transpiler'; +import { + TRANSLOCO_INTL_MESSAGE_FORMAT_CONFIG, + IntlMessageFormatConfig, +} from './intlmessageformat.config'; + +@NgModule() +export class TranslocoIntlMessageFormatModule { + static forRoot( + config?: IntlMessageFormatConfig + ): ModuleWithProviders { + return { + ngModule: TranslocoIntlMessageFormatModule, + providers: [ + {provide: TRANSLOCO_INTL_MESSAGE_FORMAT_CONFIG, useValue: config}, + { + provide: TRANSLOCO_TRANSPILER, + useClass: IntlMessageFormatTranspiler, + }, + ], + }; + } +} diff --git a/libs/transloco-intlmessageformat/src/lib/intlmessageformat.transpiler.spec.ts b/libs/transloco-intlmessageformat/src/lib/intlmessageformat.transpiler.spec.ts new file mode 100644 index 000000000..ad860fd04 --- /dev/null +++ b/libs/transloco-intlmessageformat/src/lib/intlmessageformat.transpiler.spec.ts @@ -0,0 +1,226 @@ +import { IntlMessageFormatTranspiler } from './intlmessageformat.transpiler'; +import { flatten, translocoConfig } from '@ngneat/transloco'; +import { IntlMessageFormatConfig } from './intlmessageformat.config'; + +describe('IntlMessageFormatTranspiler', () => { + describe('Cache enabled', () => { + const config = {}; + assertParser(config); + }); + + describe('Cache disabled', () => { + const config = {enableCache: false}; + assertParser(config); + }); + + it('should work with locales', () => { + const config = {locales: 'en-GB'}; + const parser = new IntlMessageFormatTranspiler(config); + const message = + '{count, plural, =0{No} one{A} other{Several}} {count, plural, one{word} other{words}}'; + + const result = parser.transpile(message, {count: 1}, {}, 'key'); + expect(result).toBe('A word'); + }); + + // it('should use passed-in formatters', () => { // todo: unsure if a custom formatter feat is provided in intmessageformat + // const formatters: { [key: string]: CustomFormatter } = { + // prop: >(v: T, lc: any, p: string | null) => + // v[p as keyof T], + // upcase: (v) => (v as string).toUpperCase(), + // }; + // const messages = { + // answer: 'Answer: {obj, prop, a}', + // describe: 'This is {upper, upcase}.', + // }; + // + // const parser = new IntlMessageFormatTranspiler({ + // opts: { + // formatters: formatters + // }, + // }); + // const upper = parser.transpile(messages.describe, {upper: 'big'}, {}, 'key'); + // expect(upper).toEqual('This is BIG.'); + // + // expect( + // parser.transpile(messages.answer, {obj: {q: 3, a: 42}}, {}, 'key') + // ).toBe('Answer: 42'); + // }); + + it('should switch locale in runtime', () => { + const config = {locales: 'en'}; + const parser = new IntlMessageFormatTranspiler(config); + const polishKey = + '{count, plural, =0 {none} one {# thing} few {# things} many {# things} other {# things}}'; + const params = {count: 2}; + + // expect(() => parser.transpile(polishKey, params, {}, 'key')).toThrowError(); // todo: parser itself disregard language + parser.onLangChanged('pl'); + expect(parser.transpile(polishKey, params, {}, 'key')).toBe('2 things'); + }); +}); + +function assertParser(config: IntlMessageFormatConfig) { + const parser = new IntlMessageFormatTranspiler(config); + const parserWithCustomInterpolation = new IntlMessageFormatTranspiler( + config, + translocoConfig({interpolation: ['<<<', '>>>']}) + ); + + it('should translate simple SELECT messageformat string from params when first param given', () => { + const parsed = parser.transpile( + 'The { gender, select, male {boy won his} female {girl won her} other {person won their}} race', + {gender: 'male'}, + {}, + 'key' + ); + expect(parsed).toEqual('The boy won his race'); + }); + + it('should translate simple SELECT messageformat string from params when second param given', () => { + const parsed = parser.transpile( + 'The { gender, select, male {boy won his} female {girl won her} other {person won their}} race', + {gender: 'female'}, + {}, + 'key' + ); + expect(parsed).toEqual('The girl won her race'); + }); + + it('should translate simple SELECT messageformat string from params when no param given', () => { + const parsed = parser.transpile( + 'The { gender, select, male {boy won his} female {girl won her} other {person won their}} race', + {gender: ''}, + {}, + 'key' + ); + expect(parsed).toEqual('The person won their race'); + }); + + it('should translate simple params and SELECT messageformat string from params when no param given', () => { + const parsed = parser.transpile( + 'The {{value}} { gender, select, male {boy won his} female {girl won her} other {person won their}} race', + {value: 'smart', gender: ''}, + {}, + 'key' + ); + expect(parsed).toEqual('The smart person won their race'); + }); + + it('should translate simple param and interpolate params inside messageformat string', () => { + const parsedMale = parser.transpile( + 'The {{ value }} { gender, select, male {boy named {{ name }} won his} female {girl named {{ name }} won her} other {person named {{ name }} won their}} race', + {value: 'smart', gender: 'male', name: 'Henkie'}, + {}, + 'key' + ); + expect(parsedMale).toEqual('The smart boy named Henkie won his race'); + }); + + it('should translate simple param and interpolate params inside messageformat string using custom interpolation markers', () => { + const parsedMale = parserWithCustomInterpolation.transpile( + 'The <<< value >>> { gender, select, male {boy named <<< name >>> won his} female {girl named <<< name >>> won her} other {person named <<< name >>> won their}} race', + {value: 'smart', gender: 'male', name: 'Henkie'}, + {}, + 'key' + ); + expect(parsedMale).toEqual('The smart boy named Henkie won his race'); + }); + + it('should translate simple string from params', () => { + const parsed = parser.transpile( + 'Hello {{ value }}', + {value: 'World'}, + {}, + 'key' + ); + expect(parsed).toEqual('Hello World'); + }); + + it('should translate simple string with multiple params', () => { + const parsed = parser.transpile( + 'Hello {{ from }} {{ name }}', + {name: 'Transloco', from: 'from'}, + {}, + 'key' + ); + expect(parsed).toEqual('Hello from Transloco'); + }); + + it('should translate simple string with a key from lang', () => { + const parsed = parser.transpile( + 'Hello {{ world }}', + {}, + {world: 'World'}, + 'key' + ); + expect(parsed).toEqual('Hello World'); + }); + + it('should translate simple string multiple keys from lang', () => { + const lang = flatten({ + withKeys: 'with keys', + from: 'from', + lang: 'lang', + nes: {ted: 'supporting nested values!'}, + }); + const parsed = parser.transpile( + 'Hello {{ withKeys }} {{ from }} {{ lang }} {{nes.ted}}', + {}, + lang, + 'key' + ); + expect(parsed).toEqual( + 'Hello with keys from lang supporting nested values!' + ); + }); + + it('should translate simple string with params and from lang', () => { + const parsed = parser.transpile( + 'Hello {{ from }} {{ name }}', + {name: 'Transloco'}, + {from: 'from'}, + 'key' + ); + expect(parsed).toEqual('Hello from Transloco'); + }); + + it('should return the given value when the value is falsy', () => { + expect(parser.transpile('', {}, {}, 'key')).toEqual(''); + expect(parser.transpile(null, {}, {}, 'key')).toEqual(null); + expect(parser.transpile(undefined, {}, {}, 'key')).toEqual(undefined); + }); + + it('should support params', () => { + const translations = { + nested: { + messageFormatWithParams: + 'Can replace {{value}} and also give parse messageformat: The {gender, select, male {boy won his} female {girl won her} other {person won their}} race - english', + people: '{count, plural, =1 {person} other {people}}', + moreNesting: { + projects: '{count, plural, =1 {project} other {projects}}', + }, + }, + }; + + expect( + parser.transpile( + translations.nested, + { + messageFormatWithParams: {value: 'Hey', gender: 'female'}, + people: {count: '1'}, + 'moreNesting.projects': {count: '1'}, + }, + {}, + 'key' + ) + ).toEqual({ + messageFormatWithParams: + 'Can replace Hey and also give parse messageformat: The girl won her race - english', + people: 'person', + moreNesting: { + projects: 'project', + }, + }); + }); +} diff --git a/libs/transloco-intlmessageformat/src/lib/intlmessageformat.transpiler.ts b/libs/transloco-intlmessageformat/src/lib/intlmessageformat.transpiler.ts new file mode 100644 index 000000000..38fab3616 --- /dev/null +++ b/libs/transloco-intlmessageformat/src/lib/intlmessageformat.transpiler.ts @@ -0,0 +1,71 @@ +import { Inject, Injectable, Optional } from '@angular/core'; +import { + DefaultTranspiler, + getValue, + HashMap, + isObject, + setValue, + Translation, + TRANSLOCO_CONFIG, + TranslocoConfig, +} from '@ngneat/transloco'; + +import { + IntlMessageFormatConfig, + MFLocale, + TRANSLOCO_INTL_MESSAGE_FORMAT_CONFIG, +} from './intlmessageformat.config'; +import { + cachedFactory, + defaultFactory, + MFFactoryFn, +} from './intlmessageformat.factory'; + +@Injectable() +export class IntlMessageFormatTranspiler extends DefaultTranspiler { + private config: IntlMessageFormatConfig; + + private mfFactory: MFFactoryFn; + + constructor( + @Inject(TRANSLOCO_INTL_MESSAGE_FORMAT_CONFIG) config: IntlMessageFormatConfig, + @Optional() @Inject(TRANSLOCO_CONFIG) userConfig?: TranslocoConfig + ) { + super(userConfig); + + this.config = config; + this.mfFactory = this.getMFFactory(config.locales); + } + + override transpile(value: any, params: HashMap = {}, translation: Translation, key: string): any { + if (!value) { + return value; + } + if (isObject(value) && params) { + Object.keys(params).forEach((p) => { + const v = getValue(value, p); + const getParams = getValue(params, p); + const transpiled = super.transpile(v, getParams, translation, key); + const message = this.mfFactory(transpiled, getParams); + value = setValue(value, p, message); + }); + } else if (!Array.isArray(value)) { + const transpiled = super.transpile(value, params, translation, key); + + return this.mfFactory(transpiled, params); + } + + return value; + } + + onLangChanged(lang: string) { + this.mfFactory = this.getMFFactory(lang); + } + + private getMFFactory(locales: string | string[] | undefined): MFFactoryFn { + return this.config.enableCache ? + cachedFactory(locales, this.config.formats, this.config.opts) : + defaultFactory(locales, this.config.formats, this.config.opts); + } + +} diff --git a/libs/transloco-intlmessageformat/src/test-setup.ts b/libs/transloco-intlmessageformat/src/test-setup.ts new file mode 100644 index 000000000..bd1454eb5 --- /dev/null +++ b/libs/transloco-intlmessageformat/src/test-setup.ts @@ -0,0 +1,24 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone'; + +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting(), { + teardown: { destroyAfterEach: false } +} +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/libs/transloco-intlmessageformat/tsconfig.json b/libs/transloco-intlmessageformat/tsconfig.json new file mode 100644 index 000000000..8eb311b86 --- /dev/null +++ b/libs/transloco-intlmessageformat/tsconfig.json @@ -0,0 +1,27 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.lib.prod.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "compilerOptions": { + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "angularCompilerOptions": { + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/libs/transloco-intlmessageformat/tsconfig.lib.json b/libs/transloco-intlmessageformat/tsconfig.lib.json new file mode 100644 index 000000000..bbcc12b1c --- /dev/null +++ b/libs/transloco-intlmessageformat/tsconfig.lib.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "target": "es2015", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [], + "lib": ["dom", "es2018"] + }, + "exclude": ["src/test-setup.ts", "**/*.spec.ts"], + "include": ["**/*.ts"] +} diff --git a/libs/transloco-intlmessageformat/tsconfig.lib.prod.json b/libs/transloco-intlmessageformat/tsconfig.lib.prod.json new file mode 100644 index 000000000..2a2faa884 --- /dev/null +++ b/libs/transloco-intlmessageformat/tsconfig.lib.prod.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/libs/transloco-intlmessageformat/tsconfig.spec.json b/libs/transloco-intlmessageformat/tsconfig.spec.json new file mode 100644 index 000000000..cd9307706 --- /dev/null +++ b/libs/transloco-intlmessageformat/tsconfig.spec.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "ES2015", + "types": ["jasmine", "node"] + }, + "files": ["src/test-setup.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] +} diff --git a/package-lock.json b/package-lock.json index 958d8b7d6..1a1a16058 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@angular/platform-browser": "13.3.10", "@angular/platform-browser-dynamic": "13.3.10", "@angular/router": "13.3.10", + "@formatjs/intl": "^2.3.4", "@messageformat/core": "3.0.0", "bootstrap": "5.1.0", "chalk": "4.1.2", @@ -3576,6 +3577,148 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "1.11.10", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.10.tgz", + "integrity": "sha512-v8nuQpx6pc0xzg4VMCXPWesFx8PxBysdF7q1CGEoet0X9nhbGPGNq0SC+D9g+Kh0pWWITidlEYsepLF7lb8Tqw==", + "license": "MIT", + "dependencies": { + "@formatjs/intl-localematcher": "0.2.30", + "tslib": "2.4.0" + } + }, + "node_modules/@formatjs/ecma402-abstract/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "license": "0BSD" + }, + "node_modules/@formatjs/fast-memoize": { + "version": "1.2.6", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/fast-memoize/-/fast-memoize-1.2.6.tgz", + "integrity": "sha512-9CWZ3+wCkClKHX+i5j+NyoBVqGf0pIskTo6Xl6ihGokYM2yqSSS68JIgeo+99UIHc+7vi9L3/SDSz/dWI9SNlA==", + "license": "MIT", + "dependencies": { + "tslib": "2.4.0" + } + }, + "node_modules/@formatjs/fast-memoize/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "license": "0BSD" + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.1.6", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.6.tgz", + "integrity": "sha512-f7jeuomhWzHIAMcH8hGyTdPrKml+yAKKtax5Tks56+5+nT7rdzCOyi/l/F5g0bN33PcnFB/eI9cW/CP0FNezig==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.10", + "@formatjs/icu-skeleton-parser": "1.3.12", + "tslib": "2.4.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "license": "0BSD" + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.3.12", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.12.tgz", + "integrity": "sha512-RHf5mi9dUaZIUteuWbK398FV1CkJOIezIubdiD+xEOPHb37ZvjXtwolCiCVVIWHDIeBBqxxAhnzdSFBS3CXfRg==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.10", + "tslib": "2.4.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "license": "0BSD" + }, + "node_modules/@formatjs/intl": { + "version": "2.3.4", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/intl/-/intl-2.3.4.tgz", + "integrity": "sha512-ehjbgPQ4bTnnpNuYcT5FrpEkGTwM2C6PJleGaMQiKZTleMcitNCRc5mfbkMZl4Tce5E3H95IUzWAfB6cf7OjjA==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.10", + "@formatjs/fast-memoize": "1.2.6", + "@formatjs/icu-messageformat-parser": "2.1.6", + "@formatjs/intl-displaynames": "6.1.1", + "@formatjs/intl-listformat": "7.1.1", + "intl-messageformat": "10.1.3", + "tslib": "2.4.0" + }, + "peerDependencies": { + "typescript": "^4.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@formatjs/intl-displaynames": { + "version": "6.1.1", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/intl-displaynames/-/intl-displaynames-6.1.1.tgz", + "integrity": "sha512-/fu6f+yMaGGaukf+BD5PHrI3HYhmBcpSnRWpgfuvTsRL6HUKWRHSdullDkU+1TaW4kg6EfEpmo4jDwVUpo/b3Q==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.10", + "@formatjs/intl-localematcher": "0.2.30", + "tslib": "2.4.0" + } + }, + "node_modules/@formatjs/intl-displaynames/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "license": "0BSD" + }, + "node_modules/@formatjs/intl-listformat": { + "version": "7.1.1", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/intl-listformat/-/intl-listformat-7.1.1.tgz", + "integrity": "sha512-XyHCi2USQItLIfhGL1JA6ITyvQc96G3LPGz5exHiuo8qBi5c/4G0ia/Wnx4ndtrW/Z58PBk0/azW+oRTxqkhWg==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.10", + "@formatjs/intl-localematcher": "0.2.30", + "tslib": "2.4.0" + } + }, + "node_modules/@formatjs/intl-listformat/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "license": "0BSD" + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.2.30", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/intl-localematcher/-/intl-localematcher-0.2.30.tgz", + "integrity": "sha512-No+D8Q8rlzEMfoKkJ1tk81aphZuAk7ZwY+Vkzbb1TOvlP67TM/YPxdf4JoiUV/Q2GRqdGhaLfgulqIf9ATKHTA==", + "license": "MIT", + "dependencies": { + "tslib": "2.4.0" + } + }, + "node_modules/@formatjs/intl-localematcher/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "license": "0BSD" + }, + "node_modules/@formatjs/intl/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "license": "0BSD" + }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -12756,6 +12899,24 @@ "node": ">=8.0.0" } }, + "node_modules/intl-messageformat": { + "version": "10.1.3", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/intl-messageformat/-/intl-messageformat-10.1.3.tgz", + "integrity": "sha512-olvdXBZITgfA/9ShzrjcsNidTXd/uGw3H8oWcjysw2lF8txF4MtO9nSWR3exPR6PhTtrrWl+BriucmsITI8Mmw==", + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.10", + "@formatjs/fast-memoize": "1.2.6", + "@formatjs/icu-messageformat-parser": "2.1.6", + "tslib": "2.4.0" + } + }, + "node_modules/intl-messageformat/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "license": "0BSD" + }, "node_modules/ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -21974,7 +22135,7 @@ "version": "4.6.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", - "dev": true, + "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -25376,6 +25537,140 @@ } } }, + "@formatjs/ecma402-abstract": { + "version": "1.11.10", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.10.tgz", + "integrity": "sha512-v8nuQpx6pc0xzg4VMCXPWesFx8PxBysdF7q1CGEoet0X9nhbGPGNq0SC+D9g+Kh0pWWITidlEYsepLF7lb8Tqw==", + "requires": { + "@formatjs/intl-localematcher": "0.2.30", + "tslib": "2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "@formatjs/fast-memoize": { + "version": "1.2.6", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/fast-memoize/-/fast-memoize-1.2.6.tgz", + "integrity": "sha512-9CWZ3+wCkClKHX+i5j+NyoBVqGf0pIskTo6Xl6ihGokYM2yqSSS68JIgeo+99UIHc+7vi9L3/SDSz/dWI9SNlA==", + "requires": { + "tslib": "2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "@formatjs/icu-messageformat-parser": { + "version": "2.1.6", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.6.tgz", + "integrity": "sha512-f7jeuomhWzHIAMcH8hGyTdPrKml+yAKKtax5Tks56+5+nT7rdzCOyi/l/F5g0bN33PcnFB/eI9cW/CP0FNezig==", + "requires": { + "@formatjs/ecma402-abstract": "1.11.10", + "@formatjs/icu-skeleton-parser": "1.3.12", + "tslib": "2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "@formatjs/icu-skeleton-parser": { + "version": "1.3.12", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.12.tgz", + "integrity": "sha512-RHf5mi9dUaZIUteuWbK398FV1CkJOIezIubdiD+xEOPHb37ZvjXtwolCiCVVIWHDIeBBqxxAhnzdSFBS3CXfRg==", + "requires": { + "@formatjs/ecma402-abstract": "1.11.10", + "tslib": "2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "@formatjs/intl": { + "version": "2.3.4", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/intl/-/intl-2.3.4.tgz", + "integrity": "sha512-ehjbgPQ4bTnnpNuYcT5FrpEkGTwM2C6PJleGaMQiKZTleMcitNCRc5mfbkMZl4Tce5E3H95IUzWAfB6cf7OjjA==", + "requires": { + "@formatjs/ecma402-abstract": "1.11.10", + "@formatjs/fast-memoize": "1.2.6", + "@formatjs/icu-messageformat-parser": "2.1.6", + "@formatjs/intl-displaynames": "6.1.1", + "@formatjs/intl-listformat": "7.1.1", + "intl-messageformat": "10.1.3", + "tslib": "2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "@formatjs/intl-displaynames": { + "version": "6.1.1", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/intl-displaynames/-/intl-displaynames-6.1.1.tgz", + "integrity": "sha512-/fu6f+yMaGGaukf+BD5PHrI3HYhmBcpSnRWpgfuvTsRL6HUKWRHSdullDkU+1TaW4kg6EfEpmo4jDwVUpo/b3Q==", + "requires": { + "@formatjs/ecma402-abstract": "1.11.10", + "@formatjs/intl-localematcher": "0.2.30", + "tslib": "2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "@formatjs/intl-listformat": { + "version": "7.1.1", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/intl-listformat/-/intl-listformat-7.1.1.tgz", + "integrity": "sha512-XyHCi2USQItLIfhGL1JA6ITyvQc96G3LPGz5exHiuo8qBi5c/4G0ia/Wnx4ndtrW/Z58PBk0/azW+oRTxqkhWg==", + "requires": { + "@formatjs/ecma402-abstract": "1.11.10", + "@formatjs/intl-localematcher": "0.2.30", + "tslib": "2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "@formatjs/intl-localematcher": { + "version": "0.2.30", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/@formatjs/intl-localematcher/-/intl-localematcher-0.2.30.tgz", + "integrity": "sha512-No+D8Q8rlzEMfoKkJ1tk81aphZuAk7ZwY+Vkzbb1TOvlP67TM/YPxdf4JoiUV/Q2GRqdGhaLfgulqIf9ATKHTA==", + "requires": { + "tslib": "2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, "@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -32312,6 +32607,24 @@ "through": "^2.3.6" } }, + "intl-messageformat": { + "version": "10.1.3", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/intl-messageformat/-/intl-messageformat-10.1.3.tgz", + "integrity": "sha512-olvdXBZITgfA/9ShzrjcsNidTXd/uGw3H8oWcjysw2lF8txF4MtO9nSWR3exPR6PhTtrrWl+BriucmsITI8Mmw==", + "requires": { + "@formatjs/ecma402-abstract": "1.11.10", + "@formatjs/fast-memoize": "1.2.6", + "@formatjs/icu-messageformat-parser": "2.1.6", + "tslib": "2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://sumba.isc.ejpd.admin.ch/nexus3/repository/npm-all/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -39161,7 +39474,7 @@ "version": "4.6.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", - "dev": true + "devOptional": true }, "typical": { "version": "4.0.0", diff --git a/package.json b/package.json index 39b3fcc6c..3b9904d0b 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "build:transloco": "nx run transloco:build && npm run build:schematics", "build:locale": "nx run transloco-locale:build", "build:messageformat": "nx run transloco-messageformat:build", + "build:intlmessageformat": "nx run transloco-intlmessageformat:build", "build:optimize": "nx run transloco-optimize:build", "build:persist-lang": "nx run transloco-persist-lang:build", "build:persist-translations": "nx run transloco-persist-translations:build", @@ -42,6 +43,7 @@ "@angular/platform-browser": "13.3.10", "@angular/platform-browser-dynamic": "13.3.10", "@angular/router": "13.3.10", + "@formatjs/intl": "^2.3.4", "@messageformat/core": "3.0.0", "bootstrap": "5.1.0", "chalk": "4.1.2", diff --git a/tsconfig.base.json b/tsconfig.base.json index 4b6462920..1eb0bd397 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -20,6 +20,9 @@ "@ngneat/transloco-messageformat": [ "libs/transloco-messageformat/src/index.ts" ], + "@ngneat/transloco-intlmessageformat": [ + "libs/transloco-intlmessageformat/src/index.ts" + ], "@ngneat/transloco-optimize": ["libs/transloco-optimize/src/index.ts"], "@ngneat/transloco-persist-lang": [ "libs/transloco-persist-lang/src/index.ts"