reuse *.resx(AngularJS) translation files in hybrid AngularJS/Angular 5 application - angularjs

Hello I have AngularJS application which is using for internalization $translateProvider and WebResources.resx files :
angular.module('app')
.config(['$translateProvider', 'sysSettings', 'ngDialogProvider',
function($translateProvider, sysSettings, ngDialogProvider) {
ngDialogProvider.setDefaults({
closeByDocument: false
});
sysSettings.device = window['device'];
if (window['device'] && ktmvPreference && ktmvPreference.preference) {
sysSettings.webServiceURL = ktmvPreference.preference.webServiceURL;
sysSettings.reportServiceURL = ktmvPreference.preference.reportServiceURL;
sysSettings.onlineHelpURL = ktmvPreference.preference.onlineHelpURL;
}
$translateProvider.useSanitizeValueStrategy(null);
$translateProvider.useLocalStorage();
var savedLanguage = localStorage.language;
if (savedLanguage)
$translateProvider.fallbackLanguage([savedLanguage]);
else
$translateProvider.fallbackLanguage(['en', 'fr', 'es']);
var url = sysSettings.webServiceURL + 'api/GlobalResources';
$translateProvider.useUrlLoader(url);
$translateProvider.useMissingTranslationHandlerLog();
$translateProvider.useMissingTranslationHandler('ktmvTranslationFail');
}
]);
Now I am doing AngularJS/Angular5 Hybrid application. As mentioned in documentation Angular5 is using "i18n" for internationalization. "i18n" is using "*.xlf" files to keep translations.
So only way during AngularJS/Angular5 application keep both WebResources.resx and messages.xlf files with the same context ?
Is there any way to reuse WebResources.resx translation from AngularJS in AngularJS/Angular application?

Maybe it will be usefull for someone...
To be able to reuse */resx files in my AngularJS/Angular internalization I started to use ngx-translate library.
This is how I implemented it :
I created custom-translate-loader.ts
import { Injectable } from '#angular/core';
import { TranslateLoader } from '#ngx-translate/core';
import { Observable } from 'rxjs/Observable';
import {HttpClient} from "#angular/common/http";
#Injectable()
export class CustomTranslateLoader implements TranslateLoader {
constructor(private http: HttpClient) {}
getTranslation(lang: string): Observable<any>{
var apiAddress = "http://localhost:26264/api/GlobalResources/?lang=" + lang;
return Observable.create(observer => {
this.http.get(apiAddress, ).subscribe(res => {
observer.next(res);
observer.complete();
},
error => {
console.log("cannot retrieve Global Resources");
}
);
});
}
}
then in my app.module.ts I imported
import {TranslateModule, TranslateLoader} from '#ngx-translate/core';
import {HttpClient, HttpClientModule} from '#angular/common/http';
import {CustomTranslateLoader} from "./common/loader/custom-translate-loader";
and in my NgModule i injected TranslateModule :
#NgModule({
imports: [
BrowserModule,
UpgradeModule,
FormsModule,
routingModule,
HttpClientModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: CustomTranslateLoader,
deps: [HttpClient]
}
})
],
declarations: [
AppComponent,
SignInComponent,
ActivationComponent
],
providers: [authServiceProvider,
commonSvcProvider,
BackgroundImageFactoryProvider,
LanguageSvcProvider
// { provide: UrlHandlingStrategy, useClass: CustomHandlingStrategy }
],
bootstrap: [AppComponent]
})
After this in my components (sign-in.components.ts for example) i am able to set up the language:
import {TranslateService} from "#ngx-translate/core";
export class SignInComponent implements OnInit{
constructor(
private translate: TranslateService) {
translate.setDefaultLang('en');
}

Related

Using ngrx-data how to configure the app to fetch data of specific entities from specific urls

If we follow ngrx-data example and look at the Entity DataService, we can fetch the Hero data that we have in-memory (hard-coded) without any configuration. The default will work the same as if we configured:
const defaultDataServiceConfig: DefaultDataServiceConfig = {
root: 'api', // or a running server url, e.g: 'http://localhost:4000/api'
timeout: 3000, // request timeout
}
and in e.g: EntityStoreModule
#NgModule({
providers: [{ provide: DefaultDataServiceConfig, useValue: defaultDataServiceConfig }]
})
Question:
How will we configure our app to fetch data for entity "Heros" from the default source:
root: 'api'
and data for entity "Villans" from a URL:
root: 'http://localhost:4000/villans'
and data for other entities from their (other/various) respective URLs ...?
After reviewing the docs specifically:
Custom EntityDataService and
Replace the HttpUrlGenerator
I came up with this solution. Anyone feel free to comment.
Define/review your data types - entity metadata - entity names;
Create mapping to plurals for non-default plural entity names (default is: name + 's');
For entities with the non-default root URL create a mapping of entity names to specific URL;
File: ../entity-metadata.ts
// Step 1:
const entityMetadata: EntityMetadataMap = {
Hero: {},
Villan: {},
Creature: {},
DataA01: {}
// etc.
}
// Step 2:
const pluralNames = {
Hero: 'heroes',
DataA01: 'data-a01'
}
export const entityConfig = {
entityMetadata,
pluralNames
};
// Step 3:
export const rootUrls = {
// Hero: - not needed here, data comes from default root
Villan: 'http://localhost:4001',
Creature: 'http://localhost:4001',
DataA01: 'http://remoteserver.net:80/publicdata',
}
Replace the HttpUrlGenerator (doc) with your own URL generator (DynamicHttpUrlGenerator)
File: ../http-dyn-url-generator.ts
import { Injectable } from '#angular/core';
import {
DefaultHttpUrlGenerator,
HttpResourceUrls,
normalizeRoot,
Pluralizer,
DefaultPluralizer,
} from '#ngrx/data';
import { rootUrls } from '../data/ngrx-data/db01-entity-metadata';
#Injectable()
export class DynamicHttpUrlGenerator extends DefaultHttpUrlGenerator {
constructor(private aPluralizer: Pluralizer = new DefaultPluralizer(undefined)) {
super(aPluralizer);
}
protected getResourceUrls(entityName: string, root: string): HttpResourceUrls {
let resourceUrls = this.knownHttpResourceUrls[entityName];
if ( ! resourceUrls) {
// rootUrls contains
// mapping of individual ngrx data entities
// to the root URLs of their respective data sources.
// It contains only entities which do not have
// the default root URL.
if (rootUrls.hasOwnProperty(entityName)) {
root = rootUrls[entityName];
}
const nRoot = normalizeRoot(root);
const url = `${nRoot}/${this.aPluralizer.pluralize(entityName)}/`.toLowerCase();
// remove after testing
console.log('-- entityName: ' + entityName + ', URL: ' + url)
resourceUrls = {
entityResourceUrl: url,
collectionResourceUrl: url
};
this.registerHttpResourceUrls({ [entityName]: resourceUrls });
}
return resourceUrls;
}
}
For each of your data entity create a custom EntityDataService
HeroDataService
VillanDataService
CreatureDataService
DataA01DataService
etc.
(doc and code is here) - the code example is under
// store/entity/hero-data-service.ts
Register your DynamicHttpUrlGenerator and your custom EntityDataServices in your app's module, in my case:
File: ../ngrx-data-store.module.ts
(in a simple app, directly in file: app.module.ts)
#NgModule({
imports: [ ... ],
providers: [ { provide: HttpUrlGenerator, useClass: DynamicHttpUrlGenerator },
HeroDataService,
VillanDataService,
CreatureDataService,
DataA01DataService
]
})
Use your custom EntityDataServices in your components for each given entity the same way as all standard or default EntityDataServices to fetch data. The data will be pulled from the respective URLs you set in the const: rootUrls.
Don't forget to get your URLs' data server(s) configured and started.
A few important considerations:
on your server you may need to enable CORS handling. E.g: on nestjs use:
app.enableCors();
if your client app uses: Angular in-memory-web-api you need to enable access to remote server as follows:
File: ../in-mem-data.module.ts (or as you named it)
import { NgModule } from '#angular/core';
import { HttpClientModule } from '#angular/common/http';
import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemDataService } from '../../services/data/in-mem-data/in-mem-data.service';
#NgModule({
imports: [
HttpClientModule,
HttpClientInMemoryWebApiModule.forRoot(InMemDataService, {
passThruUnknownUrl: true // <--- IMPORTANT for remote data access
}),
]
})
export class InMemDataModule {}

Can't resolve all parameters for

I am new with Angular. I am getting an error when I am trying to create a production build (ng build --prod). The error thrown is as follow
ERROR in Can't resolve all parameters for OpcionValor in C:/Users/Usuario/Documents/global_workspace/hcdu_proyect/HCDU_FRONT/HCDU/src/app/modulos/anamesis/anamnesis.module.ts: (?, ?)
.
ERROR in ./src/main.ts
Module not found: Error: Can't resolve './$$_gendir/app/app.module.ngfactory' in 'C:\Users\Usuario\Documents\global_workspace\hcdu_proyect\HCDU_FRONT\HCDU\src'
# ./src/main.ts 4:0-74
# multi ./src/main.ts
The file anamnesis.module.ts contains the following code:
import {NgModule} from '#angular/core';
import {CommonModule} from '#angular/common';
import {OpcionComboBox, OpcionComboBoxComplex} from '../interfaces/interfaces.module'
#NgModule({
imports: [
CommonModule,
],
declarations: []
})
export class OpcionValor implements OpcionComboBox {
constructor(private nombre: string, private valor: string) {
this.nombre = nombre;
this.valor = valor;
}
getEntityValor(): string {
return this.valor;
}
setEntityValor(valor: string) {
this.valor = valor;
}
}
export class OpcionValorObservacion extends OpcionValor implements OpcionComboBoxComplex {
observacion: string;
constructor(name: string, valor: string, observacion: string) {
super(name,valor);
this.observacion = observacion;
}
getEntityObservacion(): string {
return this.observacion;
}
setEntityObservacion(observacion: string) {
this.observacion = observacion;
}
}
export interface AnamnesisInterface {
getOpcionSeleccionadaPorNombre(nombre:string):OpcionValor;
setOpcionValorPorNombre(nombre:string, valor:string);
setOpcionValorObservacionPorNombre(nombre:string, valor:string, observacion:string);
}
I am not sure why the error is thrown if I do not have that error in dev environment. Please, somebody can help me to solve this error?
Your module is expecting two input parameters to its constructor, both of type string. Angular does not know how to construct it, most likely. I assume somewhere you have a top-level AppModule or some equivalent which looks similar to this:
#NgModule({
imports: [ OpcionValor ],
bootstrap: [ AppComponent ]
})
export class AppModule {
}
It needs to inject an OpcionValor module but can't because it doesn't know what to pass in for the constructor parameters.
I think you may need to do a little redesigning. Should nombre and valor really be members of OpcionValor, or do they belong on a Component? Should OpcionValor even be a module, or should it actually be a Component?
I had solved this issue by adding the class declaration regarding the ts file name.
The module files is called anamnesis.module.ts so I had to add the following class declaration:
export class AnamnesisModule { }
So, my module code is :
File name: anamnesis.module.ts
import {NgModule} from '#angular/core';
import {CommonModule} from '#angular/common';
import {OpcionComboBox, OpcionComboBoxComplex} from '../interfaces/interfaces.module'
#NgModule({
imports: [
CommonModule
],
declarations: []
})
**export class AnamnesisModule { }**
export class OpcionValor implements OpcionComboBox {
nombre: string;
valor: string;
constructor(nombre: string, valor?: string) {
this.nombre = nombre;
this.valor = valor;
}
..................
}
export class OpcionValorObservacion extends OpcionValor implements OpcionComboBoxComplex {
observacion: string;
constructor(name: string, valor?: string, observacion?: string) {
super(name,valor);
this.observacion = observacion;
}
.........
}
I am not sure why but it is working. I suppose there is a relation between the file name and the class declaration required.

TypeScript generics with Angular2 injector

I'm trying to use dependancy injection in angular using an injector. I want to me able to instantiate types at runtime depending on what this component is sent.
#Injectable()
export class ServiceInjectionManager {
private _injector: ReflectiveInjector;
constructor() {
this._injector = ReflectiveInjector.resolveAndCreate([
MockBackend,
BaseRequestOptions,
{
provide: Http,
useFactory: (backendInstance: MockBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backendInstance, defaultOptions);
},
deps: [MockBackend, BaseRequestOptions]
},
AppSettings,
HierarchyService
]);
}
public resolve<T extends HierarchyService>(type:any): T {
return this._injector.get(type);
}
}
I can't seem to find a way to pass a type. I have taken multiple approaches including:
public resolve<T extends HierarchyService>(T): T {
return this._injector.get(T);
}
It seems that generics in TypeScript are not the same as in .NET.

How to overcome the error when AOT-compilation 'Cannot determine the module for class'?

JIT-compilation is worked. But, I decided to compile application using the
AOT-compilation. And I get the following error:
Cannot determine the module for class ProfileComponent
Cannot determine the module for class ProfileComponent
Cannot determine the module for class ProfileRESTService
My application consists of single module. At the same time, it has a lot of components and services. These are described in a single #NgModule. Variable MODULES contains array components and services, there's no #NgModule, just a array classes, almost.
modules.ts
...
import {ProfileModule} from './profile/module';
export const MODULES = [
...
ProfileModule
];
profile/module.ts
...
import {ProfileComponent} from "./component/Profile/index";
import {ProfileRoute} from "./route/ProfileRoute/index";
import {ProfileRESTService} from "./service/ProfileRESTService";
export const ProfileModule = [
declarations: [
...
ProfileComponent
],
routes: [
...
ProfileRoute
],
providers: [
...
ProfileRESTService
]
]
app.module.ts
import {App} from './app.component';
import {routing} from "./app.routing";
import {MODULES} from "./module/modules";
let moduleDeclaration = {
declarations: [
App
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [
BrowserModule,
routing,
FormsModule,
ReactiveFormsModule,
HttpModule,
]
bootstrap: [App]
};
for (let module of MODULES) {
if (!!module['declarations'] && module['declarations'] instanceof Array) {
for (let item of module['declarations']) {
moduleDeclaration.declarations.push(item)
}
}
if('routes'){...}
if('providers'){...}
if('imports'){...}
}
#NgModule(moduleDeclaration)
export class AppModule {}
I suppose that when AOT compilation, analyzes the object that is passed in #NgModule, in my case, this object is not yet ready. It will be difficult to re-write the application describing each module as #NgModule. How can I solve the problem with the dynamic executable moduleDeclaration?

How to specify as the type angular.service?

I have TypeScript code:
// app.js
import * as angular from 'angular';
import { Deamon } from 'Deamon';
angular.module('app')
.service('deamon', DeamonClass);
// Deamon.ts
export class DeamonClass {
$inject = [
'$vk'
];
constructor(private $vk: any) {} // <- $vk is my another service VkClass
}
How do I specify the type from $vk? If I point as the type name of the class,
constructor(private $vk: VkClass) {}
then nothing does not compile.

Resources