Software localization

Angular Localization with In-Context Translation Editing

Learn how to add in-context translation editing to Angular applications with I18n support and make changes directly on your website.
Software localization blog category featured image | Phrase

There are lots of tools out there to add internationalization support for JavaScript applications, and in one of my previous articles I've covered libraries like jQuery.I18n and Polyglot. Angular, however, is a special case, so this framework needs a separate solution. One such tool is ngx-translate which has also been covered by one of our other blog posts relating to Angular L10n.

But what if I say that you may simplify your work even further and edit all the translations right on your website while immediately observing the changes? Sounds great, isn't it? This awesome feature is called in-context editing, and today I'm going to show how it can be introduced with the help of ngx-translate-phraseapp library. This solution integrates with Phrase service itself, loads previously set up translations for your project, and allows to tweak them as needed.

Why is the in-context editor a really convenient tool? Well, there are a bunch of reasons:

  • All changes are instantly reflected on the page. You don't need to switch back and forth between the editor and the browser
  • You can see how the translated text is going to look on your website with all the styles applied
  • Translated elements are highlighted with small markers, and you may click on them to edit the contents as needed
  • You can easily switch between locales and provide translation for different languages
  • All the changes can be saved by clicking a single button. The result will be saved into your Phrase project

So, as you see, with the in-context editor you get some nice features without any hassle, as this tool can be integrated into the Angular application in literally five minutes. So, let's proceed to the next section where we are going to create a very simple Angular application and add I18n support for it.

Bootstrapping The App

Go ahead and generate a skeleton for a new Angular project:

ng new incontext

Note that I'll be using Angular 5 for this demo, but in-context editor supports older versions as well (Angular 2 and above).

We are going to have a very simple component called "page", so create it now:

cd incontext

ng generate component page

Let's display an h2 header at the page/page.component.html file:

<h2>Home</h2>

Now we need to render the newly created component, so tweak the app.component.html file like this:

<h1>Welcome</h1>

<app-page></app-page>

All right, we have some data to work with, so next let's add internationalization support!

Adding I18n Support

Setting Everything Up

Before starting to hack with the in-context editor, we need a library to actually add internationalization support. ngx-translate-phraseapp is built on top of the ngx-translate, which is a powerful tool with rich functionality and a handful of third-party plugins. Install this library by running:

npm install @ngx-translate/core --save

Having the library itself is great, but we also need a way to load translation files somehow. It is up to the developer to decide what mechanism he would like to employ, and one of the simplest choices is http-loader solution that loads the files with HTTP calls:

npm install @ngx-translate/http-loader --save

Next, import all the necessary modules into the app.module.ts:

// other imports...

import {HttpClientModule, HttpClient} from '@angular/common/http';

import {TranslateModule, TranslateLoader, TranslateCompiler } from '@ngx-translate/core';

import {TranslateHttpLoader} from '@ngx-translate/http-loader';

After that, tweak the imports section in the following way:

// imports...

@NgModule({

  declarations: [

    AppComponent,

    PageComponent

  ],

  imports: [

    BrowserModule,

    HttpClientModule,

    TranslateModule.forRoot({ // <--- add this code piece

      loader: {

        provide: TranslateLoader,

        useFactory: HttpLoaderFactory,

        deps: [HttpClient]

      }

    })

  ],

  providers: [],

  bootstrap: [AppComponent]

})

Here we are utilizing a custom factory for our HTTP loader, therefore define this factory too:

// imports...

export function HttpLoaderFactory(http: HttpClient) {

  return new TranslateHttpLoader(http, "/assets/i18n/", ".json");

}

Our translation files will have .json extension (that's the only file type that HTTP loader supports for now) and will be stored under the assets/i18n directory.

Performing Translations

Initial setup is done. Next, import the TranslationService in the AppComponent:

// other imports...

import { TranslateService } from '@ngx-translate/core';

Having added this, you may control which locale should be set by default. I'll stick with English in this demo:

// imports...

@Component({

  selector: 'app-root',

  templateUrl: './app.component.html',

  styleUrls: ['./app.component.css']

})

export class AppComponent {

  constructor(translate: TranslateService) { // <---

    translate.use('en');

  }

}

Now let's localize the title in the app.component.html file:

<h1 [translate]="'global_title'"></h1>

<app-page></app-page>

There are other ways of performing translations, but we aren't going to discuss them here. To learn more, you may check our Angular Localization And Internationalization article.

Let's also perform the same steps for the PageComponent:

// other imports

import { TranslateService } from '@ngx-translate/core';

Lastly, page.component.html template:

<h2 [translate]="'page_title'"></h2>

Before proceeding to the next section, we need to create a translation file. Place in under the assets/i18n directory and give it a name of en.json:

{

  "global_title": "Welcome!",

  "page_title": "Home"

}

That's it! In order to boot the application and open it in the browser, run:

ng serve --open

In-Context Editor

All in all, you may be comfortable with editing translation files by hand with your favorite text editor, but that's not always convenient. If you have a large project with a bunch of supported locales, things may get complex rather quickly. This is because you have to keep all the translation keys in order, make sure they don't collide, and also that translations are provided for all the languages. That's why Phrase is here to assist you!

This service allows to easily work with translation files, find all the missing keys, add new locales based on the existing ones, and even request translations to be done by professionals. On top of that, there is a new In-Context editor that allows you to manipulate translations right on your website. You'll instantly see the result, while the changes will be saved to your Phrase project! So, that's a really cool feature and, what's more, it can be introduced in a couple of minutes — no need to do any complex coding.

Getting Started

In order to get started with the in-context editing, you'll need a Phrase account. If you don't have one, grab your free trial here and follow the instructions provided by the initial setup wizard (you'll have to enter some details about the project and upload translation file that we have created in the previous section). For demonstration purposes, I've initialized my project with both English and Russian locales, but you may choose other languages of course.

After you are done, a project dashboard will open. Here you'll need to click the "More" link and choose "Project Settings" from the dropdown menu. A new popup will appear, where you should choose the "API" section. This section contains only one field which "Project ID". We'll require this ID in order to setup in-context editing, so copy it and close the popup.

Next, install the ngx-translate-phraseapp library:

npm install ngx-translate-phraseapp --save

This library requires very little setup. One thing is to provide the compiler attribute for the TranslateModule in the app.module.ts file:

  imports: [

    BrowserModule,

    HttpClientModule,

    TranslateModule.forRoot({

      loader: {

        provide: TranslateLoader,

        useFactory: HttpLoaderFactory,

        deps: [HttpClient]

      },

      compiler: { // <---

        provide: TranslateCompiler,

        useClass: PhraseAppCompiler

      }

    })

For this to be working, the compiler itself has to be imported at the top of the file:

// other imports...

import { PhraseAppCompiler } from 'ngx-translate-phraseapp'
The last thing to do is initialize the in-context editor itself. For example, we can do this inside the AppComponent:
export class AppComponent {

  constructor(translate: TranslateService) {

    translate.use('en');

    let config = {  // <---

      projectId: 'YOUR_PROJECT_ID_HERE',

      phraseEnabled: true,

      prefix: "{{__",

      suffix: "__}}",

      fullReparse: true

    };

    initializePhraseAppEditor(config);

  }

}

Note that you have to provide your project ID inside the config object. Also, don't forget to import the necessary modules:

// other imports...

import { initializePhraseAppEditor, PhraseAppCompiler} from 'ngx-translate-phraseapp'

We are done! Boot the server again and let's see what goodies the in-context editor has to offer.

In Action

After opening the http://localhost:4200 page, you'll see a popup asking you to login with your PhraseApp account. After logging in, you'll notice that the page is looking quite differently now: there are small markers next to the headers, and there is also a new panel to the bottom. It means that the in-context editor is working fine!

In-Context Editor | Phrase

So, what do we see here?

  • The small points (under the red arrow) mark the translated elements. After you click on one of these points, the contents of the chosen translation will be displayed at the bottom panel. You are free to modify the contents as needed and save the changes by pressing "Save Translation" — this will store the new data under your Phrase project.
  • Under the blue arrow, you can see all available translation keys and their values. Here you may also choose a key to work with.
  • The green arrows point to the small drop-down allowing to switch the language. After you choose a new locale, all translations will be reloaded automatically.

As you see, the editor is very simple to use, yet it is very convenient as you can make the changes and immediately observe the result. There is one important thing to note, however: when you enable the in-context editor, all translations will be loaded from your Phrase project. This means that the JSON files under the  assets/i18n folder are effectively ignored, so keep that in mind!

After you have finished editing translations and disabled the in-context editor, don't forget to download the new version of the JSON files. This is as simple as going to the project's dashboard, switching to the "Locales" tab, and pressing the "Download" button for the desired language. Alternatively, you check the boxes for all the required languages and press "Export" button. This way, you'll download all the files in one go. After that, replace the old versions of the JSON files with new ones.

Conclusion

In this article, we have taken a look at localizing Angular applications with the help of Phrase's in-context editor. You have learned how to integrate ngx-translate support, provide simple translations, and setup the in-context editor itself. Summing up, this editor is not a complex tool but still it is very handy, especially if your site has lots of translated blocks. Therefore, I would really recommend using In-Context editor for all the developers that have to deal with I18n in their day-to-day work.

That's all for today folks. As always, I thank you for staying with me and happy coding!