How to – Build your own Angular translation service – Part 1

Intro

This will be a first in a series of posts in which I will build a translation service for Angular from the ground up.

I want to point out up front that I know there are multiple angular translation libraries out there, like for instance angular-translate and angular-gettext, which are directly available for use. So, if you are looking for something to just plug into your application, that might be the way to go.

I’m going to explore the implementation of this myself. Which features would I like to have in my translation service? How can I accomplish them? I might end up with an alternative translation library. But it will not be as ‘feature-complete’ as the aforementioned libraries. Which is ultimately fine by me. I’m doing this for the experience.

If you’ve read some of my previous blogposts, you’ll know that I’m a big fan of Typescript. So naturally, I will be building this service with Typescript as well.

This will become a multi-part series, as there is too much information to drop into one post. I don’t have a number of parts in my head yet. I’ll figure it out as I go. For every part that I publish, the full source code will be made available in my GitHub repository.

All code is provided “as is”.

Part 1

In this first part, I will centralize all fixed texts in one location in the application. This way we can easily change text later on in the project without having to hunt down the text in html or Typescript code. This will also help reusing text like for instance standard error messages.

There will not yet be an actual translation option in this first part. I’m recreating the actual process of creating an application where in the earlier phase, translations were not on the table. Later on it became a requirement and that’s when I expanded from all text in one location and one language to one location and multiple languages.

Setting up an angular project

I’m assuming you all know how to set up an Angular project, so I’m not getting into the details of that. I  used a simple company template which gives me the following structure:

howto-ngresoursec-part1-01

In this project there is some text on the components html and in their controllers. Let me show you the home component:

  • Controller
    private activate(): void {
    	const self = this;
    
    	//Test Toasts
    	self.$timeout(() => {
    		self.toastSvc.toastError('Hello World!')
    	}, 0, true);
    	self.$timeout(() => {
    		self.toastSvc.toastInfo('Hello World!');
    	}, 1000, true);
    	self.$timeout(() => {
    		self.toastSvc.toastSuccess('Hello World!');
    	}, 2000, true);
    	self.$timeout(() => {
    		self.toastSvc.toastWarning('Hello World!');
    	}, 3000, true);
    	self.$timeout(() => {
    		self.toastSvc.toastCustom({
    			className: 'info',
    			content: '<h1>Hello World!</h1>',
    		});
    	}, 4000, true);
    }
    
  • View (html)
    <div class="panel panel-default">
        <div class="panel-heading">
            <span>Home Title</span>
        </div>
        <div class="panel-body">
            <div class="row">
                <div class="col-lg-12">
                    <h1>Hello World!</h1>
                </div>
            </div>
        </div>
    </div>
    

You can see that I used the same text Hello World! multiple times. If I want to change this now, it would require me to change each instance.

Centralizing text

I want to centralize all the text I put in my application into one location. Not one file, mind you, but one location. To accomplish that, I create a subfolder called resources inside the app folder. Inside this folder, I recreate the folder structure of the app.

howto-ngresoursec-part1-02

I create a resource file for every component, for common error messages, … In short, anything you can think of that is plain text that needs to be shown somehow.

The resource file for my homecomponent looks like this:

module DeBiese.NgResources.Part1.Resources {
    export class Home {
        static title: string = 'Home Title';
        static helloWorld: string = 'Hello World!';
    }
}

Using this in my controllers is straight forward. Just import a reference to the Home class in the Resources module.

import HomeMessages = DeBiese.NgResources.Part1.Resources.Home;

This gives me direct access to all the strings.

private activate(): void {
	const self = this;

	//Test Toasts
	self.$timeout(() => {
		self.toastSvc.toastError(HomeMessages.helloWorld)
	}, 0, true);
	self.$timeout(() => {
		self.toastSvc.toastInfo(HomeMessages.helloWorld);
	}, 1000, true);
	self.$timeout(() => {
		self.toastSvc.toastSuccess(HomeMessages.helloWorld);
	}, 2000, true);
	self.$timeout(() => {
		self.toastSvc.toastWarning(HomeMessages.helloWorld);
	}, 3000, true);
	self.$timeout(() => {
		self.toastSvc.toastCustom({
			className: 'info',
			content: `<h1>${HomeMessages.helloWorld}</h1>`,
		});
	}, 4000, true);
}

How do I use these strings in my html? When I import Home (the resource class) into my HomeController, I can use this in my controller because of how Typescript works. It knows that it will transpile the static string into a javascript string that’s accessible at runtime. But the import does not make this available on my view.

In order to make the static strings available in my view, I have to declare a public property on my controller and set it equal to my resource class.

homeResources: HomeMessages = HomeMessages;

Now I can access the strings in my html.

<div class="panel panel-default">
    <div class="panel-heading">
        <span>{{::vm.homeResources.title}}</span>
    </div>
    <div class="panel-body">
        <div class="row">
            <div class="col-lg-12">
                <h1>{{::vm.homeResources.helloWorld}}</h1>
            </div>
        </div>
    </div>
</div>

I’m using one-way binding, {{:: …}}, because I’m using static string values to bind to. And that’s it. I now have a consistent way of grouping all my text in one location and I know how to use this in my controllers, or any other code for that matter, and in the html.

Summary

  • Resource folder
    • Recreate component structure
    • Resource file for each component and common resources
  • Import where you want to use it in code
  • Declare variable in your controller and assign the resource class to it as value for use in your html view

Closing word

In this part I was looking for a way to centralize all my static text so that it would become easier to manage. In Part 2 I will expand on this to introduce translations.

The full code base of this little test project can be found on GitHub.

Feel free to comment down below!

 

Ruben Biesemans

Ruben Biesemans

Analyst Developer @ Spikes

Advertisements

4 responses to “How to – Build your own Angular translation service – Part 1

    • My goal is to load the translations from json files. Not from a database. But the service I’m building will allow for adding translations to it at runtime, so in theory, it will be possible.

      Like

  1. Pingback: How to – Build your own Angular translation service – Part 2 | Spikes Apps·

  2. Pingback: How to – Build your own Angular translation service – Part 3 | Spikes Apps·

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s