diff --git a/package.json b/package.json
index 6445287de..1508dbd06 100644
--- a/package.json
+++ b/package.json
@@ -69,6 +69,7 @@
"@po-ui/style": "2.3.0",
"core-js": "3.6.4",
"custom-idle-queue": "2.1.2",
+ "deepmerge": "^4.2.2",
"http-status-codes": "^1.4.0",
"localforage": "1.4.0",
"lokijs": "1.5.8",
diff --git a/projects/ui/ng-package.json b/projects/ui/ng-package.json
index 7b99a596e..74df86e2c 100644
--- a/projects/ui/ng-package.json
+++ b/projects/ui/ng-package.json
@@ -2,7 +2,11 @@
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/ng-components",
"lib": {
- "entryFile": "./src/public-api.ts"
+ "entryFile": "./src/public-api.ts",
+ "umdModuleIds": {
+ "deepmerge": "deepmerge",
+ "uuid": "uuid"
+ }
},
- "whitelistedNonPeerDependencies": ["@po-ui/style", "@po-ui/ng-schematics"]
+ "whitelistedNonPeerDependencies": ["@po-ui/style", "@po-ui/ng-schematics", "deepmerge", "uuid"]
}
diff --git a/projects/ui/src/lib/services/po-i18n/index.ts b/projects/ui/src/lib/services/po-i18n/index.ts
index 90c9aee36..657185864 100644
--- a/projects/ui/src/lib/services/po-i18n/index.ts
+++ b/projects/ui/src/lib/services/po-i18n/index.ts
@@ -1,4 +1,5 @@
export * from './interfaces/po-i18n-config.interface';
+export * from './interfaces/po-i18n-config-context.interface';
export * from './interfaces/po-i18n-config-default.interface';
export * from './interfaces/po-i18n-literals.interface';
export * from './po-i18n.pipe';
diff --git a/projects/ui/src/lib/services/po-i18n/interfaces/po-i18n-config-context.interface.ts b/projects/ui/src/lib/services/po-i18n/interfaces/po-i18n-config-context.interface.ts
new file mode 100644
index 000000000..e8f5184c3
--- /dev/null
+++ b/projects/ui/src/lib/services/po-i18n/interfaces/po-i18n-config-context.interface.ts
@@ -0,0 +1,12 @@
+/**
+ * @description
+ *
+ *
+ *
+ * Interface para a configuração dos contextos do módulo `PoI18nModule`.
+ *
+ * @usedBy PoI18nModule
+ */
+export interface PoI18nConfigContext {
+ [name: string]: { [language: string]: { [literal: string]: string } } | { url: string };
+}
diff --git a/projects/ui/src/lib/services/po-i18n/interfaces/po-i18n-config.interface.ts b/projects/ui/src/lib/services/po-i18n/interfaces/po-i18n-config.interface.ts
index bda96e402..6b13490bc 100644
--- a/projects/ui/src/lib/services/po-i18n/interfaces/po-i18n-config.interface.ts
+++ b/projects/ui/src/lib/services/po-i18n/interfaces/po-i18n-config.interface.ts
@@ -1,3 +1,4 @@
+import { PoI18nConfigContext } from './po-i18n-config-context.interface';
import { PoI18nConfigDefault } from './po-i18n-config-default.interface';
/**
@@ -10,7 +11,9 @@ import { PoI18nConfigDefault } from './po-i18n-config-default.interface';
* @usedBy PoI18nModule
*/
export interface PoI18nConfig {
- /** Configurações padrões. */
+ /**
+ * Configurações padrões.
+ */
default?: PoI18nConfigDefault;
/**
@@ -20,30 +23,34 @@ export interface PoI18nConfig {
*
* Portanto podemos utilizar constantes, onde devemos informar o nome do contexto recebendo um objeto com os
* idiomas suportados e o arquivo de literais, por exemplo:
- * ```
- * import { generalEn } from './i18n/general-en';
- * import { generalPt } from './i18n/general-pt';
+ *
+ * ```typescript
+ * import { generalEn } from './i18n/general-en';
+ * import { generalPt } from './i18n/general-pt';
+ *
* ...
- * general: {
- * pt: generalPt,
- * en: generalEn
- * }
+ * general: {
+ * pt: generalPt,
+ * en: generalEn
+ * }
* ...
* ```
*
* E como informado, podemos utilizar a propriedade `url` que deve receber a URL do serviço que
* retorne as literais traduzidas, por exemplo:
- * ```
- * hcm: {
- * url: 'http://localhost:3000/api/translations/hcm/'
- * }
+ *
+ * ```typescript
+ * hcm: {
+ * url: 'http://localhost:3000/api/translations/hcm/'
+ * }
* ```
*
* Ao optar por utilizar um serviço, deverá ser definida a URL específica do contexto,
* como nos exemplos abaixo:
+ *
* ```
- * http://server:port/api/translations/crm
- * http://server:port/api/translations/general
+ * http://server:port/api/translations/crm
+ * http://server:port/api/translations/general
* ```
*
* Os idiomas e literais serão automaticamente buscados com parâmetros na própria URL:
@@ -53,9 +60,10 @@ export interface PoI18nConfig {
* serviço deve retornar todas as literais do idioma.
*
* Exemplos de requisição:
+ *
* ```
- * http://server:port/api/translations/crm?language=pt-br
- * http://server:port/api/translations/crm?language=pt-br&literals=add,remove,text
+ * http://server:port/api/translations/crm?language=pt-br
+ * http://server:port/api/translations/crm?language=pt-br&literals=add,remove,text
* ```
*
* > Sempre que o idioma solicitado não for encontrado, será buscado por `pt-br`.
@@ -63,18 +71,19 @@ export interface PoI18nConfig {
* Existe também a possibilidade de utilizar ambos, onde será feito a busca das literais nas constantes e depois efetua
* a busca no serviço, com isso as constantes podem servir como *backup* caso o serviço esteja indisponível, por exemplo:
*
- * ```
- * import { generalEn } from './i18n/general-en';
- * import { generalPt } from './i18n/general-pt';
+ * ```typescript
+ * import { generalEn } from './i18n/general-en';
+ * import { generalPt } from './i18n/general-pt';
+ *
* ...
- * general: {
- * pt: generalPt,
- * en: generalEn,
- * url: 'http://localhost:3000/api/translations/hcm/'
- * }
+ * general: {
+ * pt: generalPt,
+ * en: generalEn,
+ * url: 'http://localhost:3000/api/translations/hcm/'
+ * }
* ...
* ```
* > Caso a constante contenha alguma literal que o serviço não possua será utilizado a literal da constante.
*/
- contexts: object;
+ contexts: PoI18nConfigContext;
}
diff --git a/projects/ui/src/lib/services/po-i18n/po-i18n-base.service.spec.ts b/projects/ui/src/lib/services/po-i18n/po-i18n-base.service.spec.ts
index 2db7ca14d..1c9e9d4e1 100644
--- a/projects/ui/src/lib/services/po-i18n/po-i18n-base.service.spec.ts
+++ b/projects/ui/src/lib/services/po-i18n/po-i18n-base.service.spec.ts
@@ -1,13 +1,33 @@
-import { fakeAsync, TestBed, tick } from '@angular/core/testing';
-import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { HttpRequest } from '@angular/common/http';
-
+import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
+import { NgModule } from '@angular/core';
+import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import { of } from 'rxjs';
import * as utils from '../../utils/util';
-
import { PoI18nModule, PoI18nService } from '../po-i18n';
import { PoLanguageModule } from '../po-language';
+import { PoI18nConfig } from './interfaces/po-i18n-config.interface';
+
+const lazyConfig: PoI18nConfig = {
+ contexts: {
+ general: {
+ 'pt-br': {
+ insert: 'insert'
+ }
+ },
+ special: {
+ 'pt-br': {
+ delete: 'delete'
+ }
+ }
+ }
+};
+
+@NgModule({
+ imports: [PoI18nModule.forChild(lazyConfig)]
+})
+class LazyModule {}
describe('PoI18nService:', () => {
describe('without Service:', () => {
@@ -43,7 +63,7 @@ describe('PoI18nService:', () => {
beforeEach(() => {
TestBed.configureTestingModule({
- imports: [HttpClientTestingModule, PoLanguageModule, PoI18nModule.config(config)]
+ imports: [HttpClientTestingModule, LazyModule, PoLanguageModule, PoI18nModule.forRoot(config)]
});
service = TestBed.inject(PoI18nService);
@@ -117,6 +137,22 @@ describe('PoI18nService:', () => {
});
});
+ it('should return literal merged from context added in a "lazy module"', done => {
+ service.getLiterals({ context: 'general', language: 'pt-br' }).subscribe(literals => {
+ expect(literals['insert']).toBeTruthy();
+ expect(literals['insert']).toBe(lazyConfig.contexts['general']['pt-br']['insert']);
+ done();
+ });
+ });
+
+ it('should return literal from context added in a "lazy module"', done => {
+ service.getLiterals({ context: 'special', language: 'pt-br' }).subscribe(literals => {
+ expect(literals['delete']).toBeTruthy();
+ expect(literals['delete']).toBe(lazyConfig.contexts['special']['pt-br']['delete']);
+ done();
+ });
+ });
+
describe('Methods:', () => {
it('getLanguage: should call `languageService.getLanguage`.', () => {
const languageServiceSpy = spyOn(service['languageService'], 'getLanguage');
diff --git a/projects/ui/src/lib/services/po-i18n/po-i18n-base.service.ts b/projects/ui/src/lib/services/po-i18n/po-i18n-base.service.ts
index 1d36088b4..ded2d0aad 100644
--- a/projects/ui/src/lib/services/po-i18n/po-i18n-base.service.ts
+++ b/projects/ui/src/lib/services/po-i18n/po-i18n-base.service.ts
@@ -1,14 +1,12 @@
import { HttpClient } from '@angular/common/http';
import { Inject } from '@angular/core';
-
import { Observable } from 'rxjs';
import { isLanguage, reloadCurrentPage } from '../../utils/util';
import { PoLanguageService } from '../po-language/po-language.service';
-
-import { I18N_CONFIG } from './po-i18n-config-injection-token';
import { PoI18nConfig } from './interfaces/po-i18n-config.interface';
import { PoI18nLiterals } from './interfaces/po-i18n-literals.interface';
+import { I18N_CONFIG } from './po-i18n-config-injection-token';
/**
* @description
@@ -256,7 +254,7 @@ export class PoI18nBaseService {
const context = options['context'] ? options['context'] : this.contextDefault;
const literals: Array = options['literals'] ? options['literals'] : [];
- return new Observable(observer => {
+ return new Observable(observer => {
if (this.servicesContext[context]) {
// Faz o processo de busca de um contexto que contém serviço
this.getLiteralsFromContextService(language, context, literals, observer);
diff --git a/projects/ui/src/lib/services/po-i18n/po-i18n-config-injection-token.ts b/projects/ui/src/lib/services/po-i18n/po-i18n-config-injection-token.ts
index f0e5e57a9..8a64af3fa 100644
--- a/projects/ui/src/lib/services/po-i18n/po-i18n-config-injection-token.ts
+++ b/projects/ui/src/lib/services/po-i18n/po-i18n-config-injection-token.ts
@@ -2,4 +2,4 @@ import { InjectionToken } from '@angular/core';
import { PoI18nConfig } from './interfaces/po-i18n-config.interface';
-export const I18N_CONFIG = new InjectionToken('I18N_CONFIG');
+export const I18N_CONFIG = new InjectionToken>('I18N_CONFIG');
diff --git a/projects/ui/src/lib/services/po-i18n/po-i18n.module.ts b/projects/ui/src/lib/services/po-i18n/po-i18n.module.ts
index f8e74a02e..fe59e05cc 100644
--- a/projects/ui/src/lib/services/po-i18n/po-i18n.module.ts
+++ b/projects/ui/src/lib/services/po-i18n/po-i18n.module.ts
@@ -1,12 +1,11 @@
import { HttpClient, HttpClientModule } from '@angular/common/http';
-import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core';
+import { APP_INITIALIZER, ModuleWithProviders, NgModule, Provider } from '@angular/core';
+import { PoLanguageModule } from '../po-language/po-language.module';
import { PoLanguageService } from './../po-language/po-language.service';
-
-import { I18N_CONFIG } from './po-i18n-config-injection-token';
-import { returnPoI18nService, PoI18nService } from './po-i18n.service';
import { PoI18nConfig } from './interfaces/po-i18n-config.interface';
-import { PoLanguageModule } from '../po-language/po-language.module';
+import { I18N_CONFIG } from './po-i18n-config-injection-token';
+import { PoI18nService, returnPoI18nService } from './po-i18n.service';
/**
* @description
@@ -14,12 +13,15 @@ import { PoLanguageModule } from '../po-language/po-language.module';
* Módulo do serviço `PoI18nService` para controle de idiomas com PO.
*
* Para utilização do serviço de idiomas `PoI18nService`, deve-se importar este módulo mesmo já havendo importado
- * o módulo `PoModule`. Na importação deve ser invocado o método `config`, informando um objeto que deve implementar
+ * o módulo `PoModule`.
+ *
+ * Na importação deve ser invocado o método `config`, informando um objeto que deve implementar
* a interface [`PoI18nConfig`](documentation/po-i18n#poI18nConfig) para configuração.
*
*
* **Exemplo de configuração do módulo do i18n:**
- * ```
+ *
+ * ```typescript
* import { PoI18nConfig } from '@po-ui/ng-components';
*
* import { generalEn } from './i18n/general-en';
@@ -56,27 +58,30 @@ import { PoLanguageModule } from '../po-language/po-language.module';
* de um objeto. Exemplo:
*
* Arquivo general-pt.ts
- * ```
+ *
+ * ```typescript
* export const generalPt = {
- * add: 'Adicionar',
- * greeting: 'Prazer, {0} {1}',
- * people: '{0} Pessoas,
- * remove: 'Remover'
+ * add: 'Adicionar',
+ * greeting: 'Prazer, {0} {1}',
+ * people: '{0} Pessoas,
+ * remove: 'Remover'
* }
* ```
*
* Arquivo general-en.ts
- * ```
+ *
+ * ```typescript
* export const generalEn = {
- * add: 'Add',
- * greeting: 'Nice to meet you, {0} {1}',
- * people: '{0} People,
- * remove: 'Remove'
+ * add: 'Add',
+ * greeting: 'Nice to meet you, {0} {1}',
+ * people: '{0} People,
+ * remove: 'Remove'
* }
* ```
*
* **Exemplo de configuração de contextos usando constantes externas:**
- * ```
+ *
+ * ```typescript
* import { PoI18nConfig } from '@po-ui/ng-components';
*
* import { generalEn } from './i18n/general-en';
@@ -121,16 +126,20 @@ import { PoLanguageModule } from '../po-language/po-language.module';
* módulo utilizando a interface [`PoI18nConfig`](documentation/po-i18n#poI18nConfig):
*
* **Exemplo de padrões definidos:**
- * ```
+ *
+ * ```typescript
* const i18nConfig: PoI18nConfig = {
- * contexts: {
- * general: { }
- * },
* default: {
* language: 'pt-BR',
* context: 'general',
* cache: true
- * }
+ * },
+ * contexts: {
+ * general: {
+ * 'en-US': generalEs,
+ * 'pt-BR': generalPt
+ * }
+ * },
* }
* ```
*
@@ -141,8 +150,32 @@ import { PoLanguageModule } from '../po-language/po-language.module';
*
* **i18n com *Lazy loading***
*
- * Para aplicações que utilizem a abordagem de módulos com carregamento *lazy loading*, caso seja
- * definida outra configuração do `PoI18nModule`, deve-se atentar os seguintes detalhes:
+ * Para aplicações que utilizem a abordagem de módulos com carregamento *lazy loading*
+ * ou para módulos de bibliotecas que utilizam o PO, caso seja definida outra configuração
+ * do `PoI18nModule`, deve-se atentar os seguintes detalhes:
+ *
+ * - Utilize o método **`forChild`** ao invés do método `config` para definir os
+ * contextos e suas respectivas literais:
+ *
+ * ```typescript
+ * const i18nConfig: PoI18nConfig = {
+ * contexts: {
+ * myLib: {
+ * 'en-US': myLibEn,
+ * 'pt-BR': myLibPt
+ * }
+ * }
+ * };
+ *
+ * @NgModule({
+ * declarations: [],
+ * imports: [
+ * CommonModule,
+ * PoModule,
+ * PoI18nModule.forChild(i18nConfig)
+ * ]
+ * })
+ * ```
*
* - Caso existam literais comuns na aplicação, estas devem ser reimportadas;
* - Não defina outra *default language* para este módulo. Caso for definida, será sobreposta para
@@ -151,7 +184,6 @@ import { PoLanguageModule } from '../po-language/po-language.module';
* método [`setLanguage()`](documentation/po-i18n#setLanguage) disponibilizado pelo `PoI18nService`
* para definir a linguagem da aplicação e dos módulos com as linguagens diferentes.
*/
-
@NgModule({
imports: [HttpClientModule, PoLanguageModule]
})
@@ -160,27 +192,48 @@ export class PoI18nModule {
return {
ngModule: PoI18nModule,
providers: [
- {
- provide: I18N_CONFIG,
- useValue: config
- },
+ provideI18nConfig(config),
{
provide: APP_INITIALIZER,
useFactory: initializeLanguageDefault,
multi: true,
deps: [I18N_CONFIG, PoLanguageService]
- },
- {
- provide: PoI18nService,
- useFactory: returnPoI18nService,
- deps: [I18N_CONFIG, HttpClient, PoLanguageService]
}
]
};
}
+
+ static forRoot(config: PoI18nConfig): ModuleWithProviders {
+ return PoI18nModule.config(config);
+ }
+
+ static forChild(config: PoI18nConfig): ModuleWithProviders {
+ return {
+ ngModule: PoI18nModule,
+ providers: [provideI18nConfig(config)]
+ };
+ }
+}
+
+export function provideI18nConfig(config: PoI18nConfig): Array {
+ return [
+ {
+ provide: I18N_CONFIG,
+ useValue: config,
+ multi: true
+ },
+ {
+ provide: PoI18nService,
+ useFactory: returnPoI18nService,
+ deps: [I18N_CONFIG, HttpClient, PoLanguageService]
+ }
+ ];
}
-export function initializeLanguageDefault(config: PoI18nConfig, languageService: PoLanguageService) {
+export function initializeLanguageDefault(configs: Array, languageService: PoLanguageService) {
+ // Recupera a primeira configuração que possui "default".
+ const config = configs.find(c => c.default);
+
// tslint:disable-next-line:prefer-immediate-return
const setDefaultLanguage = () => {
if (config.default.language) {
diff --git a/projects/ui/src/lib/services/po-i18n/po-i18n.service.ts b/projects/ui/src/lib/services/po-i18n/po-i18n.service.ts
index b27a4a84f..d5fda8cb8 100644
--- a/projects/ui/src/lib/services/po-i18n/po-i18n.service.ts
+++ b/projects/ui/src/lib/services/po-i18n/po-i18n.service.ts
@@ -1,10 +1,10 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
+import { all as deepmergeAll } from 'deepmerge';
import { PoLanguageService } from './../po-language/po-language.service';
-
-import { PoI18nBaseService } from './po-i18n-base.service';
import { PoI18nConfig } from './interfaces/po-i18n-config.interface';
+import { PoI18nBaseService } from './po-i18n-base.service';
/**
* @docsExtends PoI18nBaseService
@@ -14,6 +14,10 @@ import { PoI18nConfig } from './interfaces/po-i18n-config.interface';
export class PoI18nService extends PoI18nBaseService {}
// Função usada para retornar instância para o módulo po-i18n.module
-export function returnPoI18nService(config: PoI18nConfig, http: HttpClient, languageService: PoLanguageService) {
- return new PoI18nService(config, http, languageService);
+export function returnPoI18nService(
+ configs: Array,
+ http: HttpClient,
+ languageService: PoLanguageService
+) {
+ return new PoI18nService(deepmergeAll(configs), http, languageService);
}