npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@soluling/angular

v14.0.2

Published

Runtime translation loading API for Angular

Downloads

737

Readme

Runtime Translation Loading for Angular

The standard Angular internationalization (I18N) and localization (L10N) is designed to produce one compiled application per language. This is quite restrictive because you have to compile for each language and then deploy each compilation result to a separate URL. The standard Angular internationalization has the means to load translations on runtime, but the Angular team has not fully implemented that feature. This API fills that gap. It is important to notice that this API works on the top of the Angular internationalization API, not replacing it.

Start by installing the Soluling library.

npm install @soluling/angular

The first thing you need to modify in your application is to make sure that the translations are loaded before any module is created. The right place for that is main.ts. The default code to initialize the modules is:

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.log(err));

Modify it as shown in the following code snippet.

import { loadTranslations } from '@angular/localize';
import { getTranslations } from '@soluling/angular';
import '@angular/localize/init';
...
getTranslations('assets/i18n').then(translations => 
{
  if (translations)
    loadTranslations(translations);

  import('./app/app.module').then(module => 
  {
    platformBrowserDynamic()
      .bootstrapModule(module.AppModule)
      .catch(err => console.error(err));
  });      
});

Here we first call getTranslations function that gets the translation file from the server. The function gets the resource file matching the current language of the browser. You can override the language by using the parameters, but the default behavior is to find a resource file matching the language of the browser. If the function finds any translations, then it loads them using loadTranslations. If no translation is found, no loading happens, and then the application uses the original strings.

The resource files are the standard Angular JSON resource files that contain key-value pairs.

{
  "locale": "en",
  "translations":
  {
    "1238358838717941284": "Sample",
    "3067469718492071419": "This is a sample"
  }
}

The reason the library uses JSON instead of XLIFF or XMB is that on runtime, we need only the key and the value. Everything else is unnecessary. XLIFF and XMB are a lot more verbose formats that cause larger file sizes. Also, they use XML that means slower parsing. Using JSON keeps the resource size smaller and has faster parsing time. Angular's extraction tool can extract JSON instead of XLIFF or XMB. The disadvantage of the JSON extraction is that comments and meanings are not extracted. The easiest way to create the JSON files is to use Soluling, but you can also create them yourself. The name of the resource file is <id>.json when id is IETF language tag (the same code passed in HTTP Accept-Language).

The next modification you need to do is to add locale support for the languages you plan to support. By default, Angular application contains support for English (United States). If you plan to support German and Japanese, you need to add the locale support for those languages. Add the following code into your app.module.ts.

import { registerLocaleData } from '@angular/common';

import de from '@angular/common/locales/de'; 
import ja from '@angular/common/locales/ja'; 

registerLocaleData(de, 'de'); 
registerLocaleData(ja, 'ja'); 

The above code will ensure that the compiled application contains the locale data also for German and Japanese besides English. All locale-dependent functions, such as date pipe, rely on the locale data.

The final modification is to add a code that specifies the active locale of the application. Angular uses the LOCALE_ID variable for that. By default, it is en-US. Let's add code to change that to match to the locale id of the resource we have loaded.

import { NgModule, LOCALE_ID } from '@angular/core';
import { LocaleService } from '@soluling/angular';
...
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [
    LocaleService, 
    { provide: LOCALE_ID, deps: [LocaleService], useFactory: (service: LocaleService) => service.localeId },
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

We use LocaleService service. It is a service that gives us the id of the loaded resource.

The final step is you place the runtime resource files into assets/i18n directory. Angular extract tool extracts the design time resource file (XLIFF, XMB or JSON). Soluling can localize all file formats created by Angular extract tool such as XLIFF 1.2, XLIFF 2.0 JSON, and XMB. However you need to use JSON when using the runtime localization. Angular extract tool extracts XLIFF and XMB from the source code (i.e., .html and .ts). However the JSON file is extracted from the compiled application (e.g., dist\*.js). In addition Angular CLI does not yet support JSON so you have to do the extraction without the CLI. First build your application.

ng build

Then add the following command to the package.json file un the "scripts" section.

{
  ...
  "scripts": {
    "i18nj": "node_modules/.bin/localize-extract -s dist/**/*.js -f json -o src/locale/messages.json",    
    ...      
  }
  ...
}

Then run the extractor to extract strings and to create the messages.json file.

npm run i18nj

Localize the messages.json file. Save the localized files with the name <id>.json where id is the language id. For example, the German file is de.json. We recommend using Soluling when creating localized files. You can download Soluling from here.

The localized JSON files are ready to be used in runtime location. Place the the localized JSON files into assets\i18n directory. Run the application.

ng serve -o

If you have the resource file matching your browser's language, the application appears in that language. If not, change the language of the browser and click refresh to see the application in the selected language.

Note! If you want to extract string from .ts file you need to use Angular 10.1 or later. The extract tools of Angular 9 and 10 do not extract strings from .ts files but only strings from templates.