I am working on ionic application. I want to add multi-language support for the same using language .json files. So I googled it and found few examples for loading files using "angular static file loader plugin", but it loads all the language files at once.
My question is, can we load user selected language file only to avoid extra time for loading other language files. Can anybody please let me know how can I achieve it ?? or loading all files at a time is better approach ?? or is there any better implementation I can do ??
Thank you.
My question is, can we load user selected language file only to avoid extra time for loading other language files.
Yes.
Can anybody please let me know how can I achieve it ?? or loading all files at a time is better approach ?? or is there any better implementation I can do ??
Use angular-translate and angular-translate-loader-url
in your app.config()
$translateProvider.useUrlLoader('/translate');
$translateProvider.preferredLanguage('en_US');
This will be an equivalent of request /translate?lang=en_US to get the specific language (default) when your app initial.
Later when you want to change to another language:
// Example in one of your controller
$translate.use('fr_FR');
This will trigger a request /translate?lang=fr_FR to fetch another translation file
I have created JSON files of language as "en.json" in my project.. and I want to use that file.. so is it possible by using above code?
For JSON files, as mentioned in your question angular-translate-loader-static-files Will do the trick (I am not sure why you have all file loaded in once, because it supposed to be lazy loading)
$translateProvider.useStaticFilesLoader({
prefix: '',
suffix: '.json'
});
$translateProvider.preferredLanguage('en');
This will load en.json.
To lazy load another translation file.
$translate.uses('fr');
This will load fr.json
Best way to change language Globally is to use pipes and send the language parameter as an argument.
This would automatically change the Language across the components where the language pipe is utilized.
The following example can be used to supple multiple language at a time and can be used to change Language dynamically on a single click
// for example: **language.pipe.ts**
import { Pipe, PipeTransform, OnInit, OnChanges } from '#angular/core';
import { LanguageService } from '../services/language.service';
#Pipe({
name: 'language'
})
export class LanguagePipe implements PipeTransform {
constructor(
public lang: LanguageService
) { }
transform(value: string, args?: any): any {
return this.lang.getLang(value);
}
}
// **language.service.ts**
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
#Injectable()
export class LanguageService {
selectedLanguage = 'ch';
segmentsNames: any = {};
constantSegmentNames: any = {};
language = {
undefined: { 'en': '', 'ch': '' },
null: { 'en': '', 'ch': '' },
'': { 'en': '', 'ch': '' },
'hello': { 'en': 'Hello', 'ch': '你好' },
'world': { 'en': 'World', 'ch': '世界' }
};
constructor(private _http: HttpClient) { }
getLang(value: string, args?: any): any {
if (this.language[value]) {
return this.language[value][this.selectedLanguage];
}
return value;
}
/**
* #function that is used to toggle the selected language among 'en' and 'ch'
*/
changeLanguage() {
if (this.selectedLanguage === 'en') {
this.selectedLanguage = 'ch';
} else {
this.selectedLanguage = 'en';
}
}
}
// **Use Language Pipe in HTML AS**
<strong>{{'hello' | language:lang.selectedLanguage}}{{'world' | language:lang.selectedLanguage}}</strong>
PS: Don't forget to import the pipe & service in all the components where you want to use this functionality
Conslusion: you can write your own logic to fetch the appropriate Language.json file based on user selected language and use it in the service above mentioned
Related
I am a newbie on Svelte and in coding in general. I'd prefer to learn SvelteKit (Svelte#Next) rather than sapper since that seems to be where Svelte is heading.
For my personal project, I need to support dynamic routing based on url slugs. How do I do that in SvelteKit? For example, if I have /blog directory and need to pull content based on its "id", how would I do that?
The part that I am having difficulty with is accessing the URL slug parameter.
Thanks in advance.
you can create a file with the [brackets] : touch src/routes/blog/[slug].svelte
And paste the following code
<script>
import { page } from '$app/stores';
</script>
{$page.params.slug}
Then navigate to your app http://localhost:3000/blog/123
You should see your result
In order to create content for the http://localhost:3000/blog page, you can modify src/routes/blog/index.svelte
As of SvelteKit 1.0 the path should be a directory in brackets, e.g. for /blog/<slug> you will add the following:
src/routes/blog/[slug]
|_ +page.js
|_ +page.svelte
Then in src/routes/blog/[slug]/+page.js you can add something like
export const load = ({ params }) => {
return {
slug: params.slug
}
}
which will return it as a data property to +page.svelte, so you can write something like:
<script>
export let data;
</script>
<h1>{data.slug}</h1>
Reference: https://kit.svelte.dev/docs/routing
Caveat - the info in my reply probably may not be valid as SvelteKit matures, but from experiments I have done thus far, this works:
Parameter based routing is similar to the sveltejs/sapper-template. You should learn how Sapper does it first. Lets say I have a route blog with a single param slug (/blog/page-1 & /blog/page-2)
Create a route component in routes/blog named [slug].svelte
Copy the content from the sveltejs/sapper-template example.
Rename the preload function to load with a single parameter such as ctx
Alter the return object to append your slug property to props
export async function load(ctx) {
let slug = ctx.page.params.slug
return { props: { slug }}
}
If your blog has multiple params for the slug (/blog/2021/01/29/this-is-a-slug), you can remove [slug].svelte and create a file name [...data].svelte and change your load method to:
export async function load(ctx) {
let [year, month, day, slug] = ctx.page.params.data;
return { props: { data: { year, month, day, slug }}}
}
Don't forget to define your data property as an object. Here's a typescript example:
<script lang="ts">
export let data: { slug: string, year: number, month: number, day: number };
</script>
From there use the values as {data.slug}, etc
Happy hacking
I also had some issues with the Typescript import so here is a complete Typescript example.
Structure:
src/routes/coins/[coin_name]
|_ +page.ts
|_ +page.svelte
+page.ts:
import type { PageLoad } from './$types';
export const load: PageLoad = ({ params }) => {
return {
name: params.coin_name
}
}
export interface CoinPage{
name: string
}
+page.svelte and the use of the data:
<script lang="ts">
import type { CoinPage } from "./+page";
export let data:CoinPage;
</script>
<h1>{data.name}</h1>
I have a difficult case which was organized from an old angularjs and angular8, besides it's was also limited in the extensive refactoring to resolve in code of micronization.And the code of angularjs cannot be changed.
In the end I choose the library ngx-planet that is closest to my situation, but i got this error
Issue:
When I then local run it, I get this error message.
I have tested this way of writing under angularjs and angular8 code without planet library, it can work, but after using planet, the aforementioned error occurred.
After searching, it was found that the reasons for this error message are known as the following 6 types:
Barrel index
Circularity dependency
Forgot to enable polyfills import'core-js/es6/reflect'
Injectable decorator incorrect usage (EX: missing # or capital & lower case error etc...)
Tsconfig does not configure emitDecoratorMetadata
Decorate parameter type use any in your constructor
The first 5 have been excluded, I suspect it is the last, because of this Configuring Dependency Injection in Angular
But I am confused, whether a certain configuration of planet causes parameter type to fail?
Code Structure:
1. There is a common service exported from angularjs
(File name: angular1-root-module.js)
(function () {
angular.module('angular1', [
'angular1.export-service'
]);
angular.module('angular1.export-service', []);
angular.module('angular1.export-service').factory('Angular1ExportService', Angular1ExportService);
Angular1ExportService.$inject = [];
function Angular1ExportService() {
function outPutString() {
return 'I from Angular1 export service string';
}
return {
outPutAngular1String: outPutString,
};
}
})();
2. Inject into the class named Angular1InjectorService through the factory provider and depend on angularjs's $injector
export function Angular1InjectorServiceFactory(injector: any) {
return new Angular1InjectorService(injector);
}
export const Angular1InjectorServiceProvider = {
provide: Angular1InjectorService,
useFactory: Angular1InjectorServiceFactory,
deps: ['$injector']
};
#Injectable()
export class Angular1InjectorService {
// I think probably this injector of type is any cause
constructor(private angular1Injector: any) {
}
getService(serviceName: String) {
return this.angular1Injector.get(serviceName);
}
}
3. Then inject into the common AppBaseService
#Injectable()
export class AppBaseService {
readonly angular1InjectorService: Angular1InjectorService;
readonly testService: any;
constructor(readonly injector: Injector) {
this.angular1InjectorService = this.injector.get(Angular1InjectorService);
this.testService = this.angular1InjectorService.getService('Angular1ExportService');
}
testGetAngular1String() {
console.log('app base service is work!');
return this.testService.outPutAngular1String();
}
}
4. Then the service of the sub app inherits AppBaseService, and obtains the method that exists in angularjs
export class App1RootService extends AppBaseService {
constructor(readonly injector: Injector) {
super(injector);
}
GetLogAngular1String() {
console.log('app1 root service is work!');
return this.testGetAngular1String();
}
}
5. Portal root planet config
this.planet.registerApps([
{
name: 'app1',
hostParent: '#app-host-container',
routerPathPrefix: '/app1',
selector: 'app1-root-container',
resourcePathPrefix: '/static/app1',
preload: settings.app1.preload,
switchMode: settings.app1.switchMode,
loadSerial: true,
manifest: '/static/app1/manifest.json',
scripts: [
'main.js'
],
styles: [
],
}
]);
6. Sub app1 main config
defineApplication('app1', (portalApp: PlanetPortalApplication) => {
return platformBrowserDynamic([
{
provide: PlanetPortalApplication,
useValue: portalApp
},
{
provide: AppRootContext,
useValue: portalApp.data.appRootContext
}
])
.bootstrapModule(App1RootModule)
.then(appModule => {
return appModule;
})
.catch(error => {
console.error(error);
return null;
});
});
Issue related resources:
EXCEPTION: Can't resolve all parameters
Uncaught Error: Can't resolve all parameters for
After upgrade Angular to v8: Can't resolve all parameters for Component:
Intact issue code:
Stackblitz
Github
I have not found an answer, and already have the official github open issue, but hope to get more help
Thanks.
I've created a class decorator to read the permission for the angular component.
decorator.ts
function permissions(object: { [key: 'read' | 'write' | 'update' | 'delete']: string }[]) {
return (ctor: Function) => {
console.log(JSON.stringify(object));
}
}
components.ts
// employee.component.ts
#permissions([{ read: 'read-unique-id' }])
#Component({
selector: 'app-employee',
templateUrl: './app-employee.component.html',
styleUrls: ['./app-employee.component.css']
})
class Employee {
constructor() { }
}
// employee-details.component.ts
#permissions([{ read: 'read-unique-id' }, { write: 'write-unique-id' }])
#Component({
selector: 'app-employee-details',
templateUrl: './app-employee-details.component.html',
styleUrls: ['./app-employee-details.component.css']
})
class EmployeeDetails {
constructor() { }
}
I should be creating a file by reading the class name along with the permission details from decorator during compilation. Just a command to generate the below file.
Example: Permissions.ts
class Permissions {
static EMPLOYEE_READ = 'read-unique-id';
static EMPLOYEE_DETAILS_READ = 'read-unique-id';
static EMPLOYEE_DETAILS_WRITE = 'write-unique-id';
}
I believe I should create a Node JS app to read all the files and check for #permissions decorator and generate the above file. Is that correct?
If so, Can someone help me to achieve that. Read all the component.ts file and get the permissions details or is there any other method to achieve the same.
Update: I should read permission details from component.ts through decorator and generate Permissions.ts with help of Node JS app.
A more simple and type-safe way is to move in opposite direction and use a set of constants instead of strings, e.g. with enum:
enum Permissions {
EMPLOYEE_READ = 'read-unique-id';
...
}
...
#permissions([{ read: Permissions.EMPLOYEE_READ }, ...}])
A module that contains constants can be reused in backend application as well.
I have the Tour of Heroes app running, but I want to extend it to make ajax calls.
I have a WebAPI service that serves up the data (CORS enabled) and have proven it w/ a silly little non Angular client using JQuery $.post and $GetJson ... All was going well...
Here is my hero-details.component.ts file
(happy to include any others that may help...)
import {Component , Input, OnInit } from '#angular/core';
import { ActivatedRoute, Params } from '#angular/router';
import { Location } from '#angular/common';
import { HttpModule } from '#angular/http';
import 'rxjs/add/operator/switchMap';
import { Hero } from './hero';
import { HeroService } from './hero.service';
#Component({
selector: 'hero-detail',
templateUrl: './hero-detail.component.html',
styleUrls : ['./hero-detail.component.css']
})
export class HeroDetailComponent { // implements OnInit {
#Input() hero: Hero;
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
submitted = false;
constructor(
private heroService: HeroService,
private route: ActivatedRoute,
private location: Location,
$http //**--LINE OF INTEREST #2**
) { }
ngOnInit(): void {
this.route.params
.switchMap((params: Params) => this.heroService.getHero(+params['id']))
}
save(): void {
this.heroService.update(this.hero)
.then(() => this.goBack());
}
goBack(): void {
this.location.back();
}
onSubmit() { this.submitted = true; }
callService( ) {
var uri = 'http://localhost:61212/api/heros';
//**// LINE OF INTEREST #1**
$http({
method: 'GET',
url: uri
}).then(function () { alert('success'); }, function () { alert('fail');});
};
}
If I try to compile I get
TS2304: Cannot find '$http'
I can comment the $HTTP call (Line of Interest #1 ) and it compiles, it runs and i do enter the function and hit a breakpoint where i declare and assign the variable "uri". So I am reasonably sure I have the problem isolated.
So I believe, based on hours of googling, that I need to DI the $http object into this component
But when I pass $http into the constructor (LINE OF INTEREST #2) I get the following error when I try to compile
TS7006 Parameter '$http' implicitly has an 'any' type
I have googled this so much Larry and Sergy have asked me to knock it off.
What I have found is $http being passed into controllers, maybe Im missing something, but I can not seem to translate those articles into something that works for this.
1) Am I right that injecting the $http object is what needs to be done
2) What is the syntax?
when I was googling , i was just googling angular and most the articles were for angular1. Thats why I was seeing answers that involved controllers, etc.
angular2 is much different. If you are trying to get off the ground, try searching angular2 instead. at least the articles you run across will be relevant.
if you are using visual studio.. here is a nice link to get you started...
https://jonhilton.net/2016/12/01/fast-track-your-angular-2-and-net-core-web-app-development/
How can I make basic initialization of my data in app. For example if user logged in and press F5 I need to request current user data from server before all queries starts like get user order etc. In Angular 1 we have .run() directive for this case. How can I solve this problem?
There are several ways to do that:
You could execute some requests before bootstrapping your Angular2 application. Such first requests could rely what you save into the local / session storage.
var injector = Injector.resolveAndCreate([HTTP_PROVIDERS]);
var http = injector.get(Http);
http.get('/userdetails').map(res => res.json())
.subscribe(data => {
bootstrap(AppComponent, [
HTTP_PROVIDERS
provide('userDetails', { useValue: data })
]);
});
See this question for more details:
How to bootstrap an Angular 2 application asynchronously
You could extend the HTTP request to transparently get these data when requests are actually executed. This would be a lazy approach.
#Injectable()
export class CustomHttp extends Http {
constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, userDetailsService: UserDetailsService) {
super(backend, defaultOptions);
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
console.log('request...');
return this.userDetailsService.getUserDetails().flatMap((userDetails) => {
return super.request(url, options);
});
}
get(url: string, options?: RequestOptionsArgs): Observable<Response> {
console.log('get...');
return this.userDetailsService.getUserDetails().flatMap((userDetails) => {
return super.get(url, options);
});
}
}
implement the UserDetailsDetails this way:
export class UserDetailsService {
constructor(private http:Http) {
}
getUserDetails() {
if (this.userDetails) {
return Observable.of(this.userDetails);
} else {
return this.http.get(...)
.map(...)
.do(data => {
this.userDetails = data;
// Store in local storage or session storage
});
}
}
and register this CustomHttp class this way:
bootstrap(AppComponent, [HTTP_PROVIDERS,
UserDetailsService,
new Provider(Http, {
useFactory: (backend: XHRBackend,
defaultOptions: RequestOptions,
userDetailsService: UserDetailsService) => new CustomHttp(backend, defaultOptions, userDetailsService),
deps: [XHRBackend, RequestOptions, UserDetailsService]
})
]);
See these questions for more details:
Angular 2 - How to get Observable.throw globally
Cache custom component content in ionic 2
Things could also be done at the level of the router outlet if you use routing. It's possible to implement a custom router-outlet that checks security / user details when a route is activated. I think that it's a little further from your need...
See this question for more details:
Angular 2 Cancelling Route Navigation on UnAuthenticate
You could fetch the current user data before you call Angular2's bootstrap(...)
You could also fire an event (using an Observable for example) to notify other that the logged-in user is now known and initiate further requests only after this event was received.