logo

How to manage i18n translation files for web applications

Most software developers know that keeping hardcoded strings in your code is bad form. For the most part of our working life, we pester our colleagues to extract stuff in variables, make strings constants, so on and so forth.

Text/translation file management became an interesting topic for me in the second year of my software development career. I was building apps that had a lot of repetitive text and I was frustrated because I couldn’t use the same approach I had with my code, that of extracting strings into constants. That’s when I learned what i18n is and I started diving into the topic. Turns out internationalization(i18n) for web apps is not that hard, if you’re willing to put some thought into it.

One of the first struggles I came across, was related to the management of those files. Because I worked almost exclusively with JavaScript, I mostly used JSON files to store my application texts. I’ve always picked libraries that work with JSON out of the box, to avoid the headaches of properties files — in the case of Java — or XML or other old or “exotic” file formats.

Either way, I invested a lot of time in experimenting with structure, since it can make or break the flexibility of your texts.

There are mainly two approaches to text management that seemed to work for me, and that I’ve used throughout the years, which I will briefly describe, next.

Per-page grouping

This was quite intuitive and it came up naturally. I didn’t have to do research for it. I just figured that if I group the texts based on the pages/areas of my web app they impact, everything would work fine.

In addition to the page-specific texts, I would also have a special “page” called common, where I would store the texts that are used throughout the application. This worked well, and still works well for web applications that don’t have a lot of texts “in common”.

I would then have properties, under these larger page categories, which would represent components, and they would nest everything a specific component would need. Everything under component would then be stored either under a key that represents the area of the component, or directly under the component name, using a unique identifier, in both cases.

Here are a couple of examples:

// home.json
{
	"header": {
		"logo": {
			"tagLine": "Hello Dolly!"
		}
	}
}

// or

// home.json
{
	"header": {
		"logoTagLine": "Hello Dolly!"
	}
}

I’d say this is the first type of text grouping you should use, especially if your application is rather small and there are not that many application texts/strings to manage.

The problem is that once shared texts start to get more and more frequent, this structure tends to become hard to use. This is because the common content model, property, key, whatever you want to call it, tends to start looking like a Utils class — everybody drops their crap in there.

Instead of actually thinking about where a text should land, if it appears in 2 places, it will be considered shared and dropped in there. This is where the next pattern comes in handy.

Category based grouping

The second way of grouping also came naturally. It is an evolution that builds upon the previous strategy and tries to get rid of its inflexibilities. The whole strategy revolves around the grouping of translations/texts by categories rather than the pages they appear on.

Now, category is a broad term so let me explain what it means in this case: It means by component kind.

So if with the previous structure, a title for a modal window would have been stored under page.modal.header.title, with the category-level grouping it would be stored under titles.modal.header. For a more eloquent example, let’s take our tagLine property from previously — home.header.logo.tagLine. You usually have your logo on all your pages. With the previous structure, you would have probably thrown it into the commons file. But with this type of grouping, you can store your tag line like this titles.logoTagLine.

{
	"header": {
		"logo": {
			"tagLine": "Hello Dolly!"
		}
	}
}

// vs.

{
	"titles": {
		"tagLine": "Hello Dolly!"
	}
}

See how simple it is? You can use this on every page and never worry that you either need to duplicate it or move it into commons so you can use it. It’s a title, for the logo, so you can use it wherever you need that text and it will not look awkward, or like belonging to a different page, if you use this structure.

I’ve seen this structure at work for a long time and it scales properly for all types of projects. One thing to keep in mind, though, is that you might have issues if your Product Owner is still figuring out the features of your application. In layman’s terms, if your app is new, and is subjected to a lot of change, you need to be very careful when using this structure.

Hybrid grouping

There is also a third strategy, which involves a mix between the two previous structures. I wouldn’t recommend you start with this one, but more likely than not, you will end up with it.

You should probably start with per-page grouping, since it’s the simplest one, and if your project is in its early days, it will give you the most structure to build your project up without refactoring your texts grouping every iteration.

Once you get the fundamentals down, try to migrate most of the duplicate properties you keep in any page-level translation file/object into category-based groups. You should also apply this ruthlessly to your shared texts file/object.

You will ultimately end up with a structure that contains page-specific translations and component/category specific translations. This way, all your button texts, your default “Click here!” texts and your alerts will be in one place and your individual, page-related texts will be in their respective place.

Conclusion

None of the above application text structure management solutions is lesser than the other. Each of them are suitable for a specific type of project, be it a mobile app, a web application or a desktop application, and it might even be suitable or unsuitable for specific industries or teams. Who knows?

For the time being, I’m not the one who invented them, they’ve been there all along. I just use them to scratch a personal itch, and found which one works best for the current state of the project I’m working on.

Resources

Here are a couple of resources to get you on your texts management way. A couple of platforms that provide text management as a service as well as some useful libraries if you’re working with libraries such as Vue.js or React.js.

P.S. If you need help building a kickass website or web application for your business, reach out and let’s talk about how we can put a static site generator to work, for you. You get performance, security and SEO, out of the box.

Photo credits: Romain Vignes on Unsplash

Copyright (c) 2023 Adrian Oprea. All rights reserved.