Correct implementation in angular 18.1
mzeromski opened this issue · 1 comments
So I spent some time doing a correct implementation in angular18.1, here you have my code, with some service implementation, copy paste and it works
Below you can fetch code from git, and see working example.
app/config/httpLoaderFactory.ts
all required features in one file
app/config/httpLoaderFactory.ts
import { HttpClient } from '@angular/common/http';
import { inject } from '@angular/core';
import { TranslateLoader, TranslateService } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { LanguageSwitchService } from '../core/language-switch/language-switch.service';
const httpLoaderFactory: (http: HttpClient) => TranslateHttpLoader = (http: HttpClient) =>
new TranslateHttpLoader(http, './assets/i18n/', '.json?v=v' + Math.random());
export const provideTranslation: () => {
loader: {
provide: typeof TranslateLoader;
useFactory: (http: HttpClient) => TranslateHttpLoader;
deps: [typeof HttpClient];
};
} = () => ({
loader: {
provide: TranslateLoader,
useFactory: httpLoaderFactory,
deps: [HttpClient],
},
});
export function initializeTranslation(): () => void {
const translateService: TranslateService = inject(TranslateService);
const languageSwitchService: LanguageSwitchService = inject(LanguageSwitchService);
return () => {
translateService.addLangs(LanguageSwitchService.availableLanguages);
translateService.setDefaultLang(LanguageSwitchService.defaultLanguage);
languageSwitchService.initLanguageFromLocalStorage();
};
}
main.js
then in main.js execute it (remove others stuff)
export const appConfig: ApplicationConfig = {
providers: [
...
importProvidersFrom([TranslateModule.forRoot(provideTranslation())]),
{
provide: APP_INITIALIZER,
useFactory: initializeTranslation,
multi: true,
deps: [TranslateService],
},
],
};
LanguageSwitchService
now add LanguageSwitchService
@Injectable({
providedIn: 'root',
})
export class LanguageSwitchService {
public static readonly availableLanguages: string[] = ['en', 'pl'];
public static readonly defaultLanguage: string = LanguageSwitchService.availableLanguages[0];
private translateService: TranslateService = inject(TranslateService);
public initLanguageFromLocalStorage(): void {
const languageFromStorage: string | null = localStorage.getItem('language');
if (
languageFromStorage &&
LanguageSwitchService.availableLanguages.includes(languageFromStorage)
) {
this.setLanguage(languageFromStorage);
}
}
public getCurrentLanguage(): string {
if (
this.translateService.currentLang &&
this.translateService.currentLang !== LanguageSwitchService.defaultLanguage
) {
return this.translateService.currentLang;
}
return LanguageSwitchService.defaultLanguage;
}
public setLanguage(languageId: string): void {
if (LanguageSwitchService.availableLanguages.includes(languageId)) {
this.translateService.use(languageId);
localStorage.setItem('language', languageId);
}
}
}
component
then add some component to handle switcher, here is example with primeng, key is to call
this.languageSwitchService.setLanguage("en");
export class LanguageSwitchComponent {
private languageSwitchService: LanguageSwitchService = inject(LanguageSwitchService);
private flagConverter: Record<string, string> = { en: 'gb' };
public readonly languages: MenuItem[] = LanguageSwitchService.availableLanguages.map(language => {
return {
label: `language-switch.${language}`,
id: language,
flag: this.flagConverter[language] ?? language,
};
});
public currentLanguage: MenuItem = this.languages.filter(
i => i.id === this.languageSwitchService.getCurrentLanguage()
)![0];
changeLanguage(): void {
this.languageSwitchService.setLanguage(this.currentLanguage.id!);
}
}
and html (quite complicated becouse Im using some flags
<p-dropdown
[options]="languages"
optionLabel="label"
styleClass="w-30"
[(ngModel)]="currentLanguage"
(onChange)="changeLanguage()">
<ng-template pTemplate="selectedItem">
<div class="align-items-center flex content-center gap-2" *ngIf="currentLanguage">
<div class="flex content-center">
<span
class="flag flag:{{
currentLanguage['flag']!.toUpperCase()
}} mt-1 rounded-lg scale-150 mr-1"></span>
</div>
<div>{{ currentLanguage.label! | translate }}</div>
</div>
</ng-template>
<ng-template let-language pTemplate="item">
<div class="align-items-center flex gap-2">
<span
class="flag flag:{{
language['flag']!.toUpperCase()
}} mt-1 rounded-lg scale-150 mr-1"></span>
<div>{{ language.label | translate }}</div>
</div>
</ng-template>
</p-dropdown>
Download code and example how it works
https://github.com/mzeromski/angular-starter (you can give a star ;)
https://angular-starter.com/starter
Thanks for providing this code.
I've updated our tutorial.
https://www.codeandweb.com/babeledit/tutorials/how-to-translate-your-angular-app-with-ngx-translate
I'll also update the ngx-translate documentation soon.