Migrating internationalization files
During my Ph.D. migration project, I considered the migration of several GUI aspects:
These elements are the main ones. When perfectly considered, you can migrate the front-end of any application. But, we are missing some other stuff 😄 For example, how do you migrate i18N files?
In this post, I'll present how to build a simple migration tool to migrate I18N files from
.properties (used by Java) to
.json format (used by Angular).
First, let's see our source and target.
As a source, I have several
.properties files, including I18N for a Java project.
Each file has a set of key/value and comments.
For example, the
EditerMessages_fr.properties is as follow:
And it's Arabic version
As a target, I need only one JSON file per language. Thus, the file for the french translation looks like this:
And the Arabic version:
To perform the transformation from the
.properties file to
json, we will use MDE.
The approach is divided into three main steps:
- Designing a meta-model representing internationalization
- Creating an importer of properties files
- Creating a JSON exporter
I18N files are simple. They consist of a set of key/values. Each value is associated with a language. And each file can be associated with a namespace.
For example, in the introduction example, the namespace of all entries is "EditerMessages".
I designed a meta-model to represent all those concepts:
Once the meta-model is designed, we must create an importer that takes
.properties files as input and produces a model.
To produce a model, I first look for a
.properties parser without much success.
Thus, I decided to create my own parser.
Given a correctly formatted file, the parser provides me the I18N entries.
Then, by iterating on this collection, I build an I18N model.
To implement the parser, I used the PetitParser2 project. This project aims to ease the creation of new parsers.
First, I downloaded the last version of Moose, and I installed PetitParser using the command provided in the repository Readme:
In my Moose Image, I created a new parser.
To do so, I extended the
Then, I defined the parsing rules. Using PetitParser2, each rule corresponds to a method.
start is the entry point.
pairs parses the entries of the
The first part of this method (before
==>) corresponds to the rule parsed.
The second part (after
==>), to the production.
The first part tries to parse one or several
Then, it parses one
pair followed by a list of
This parser is clearly not perfect and would require some improvement. Nevertheless, it does work for our context.
The second part produces a collection (i.e. a list) of the
Building the I18N model
Now that we can parse one file, we can build a I18N model.
To do so, we will first parse every
For each file, we extract the
language and the
namespace based on the file name.
EditerMessages_fr.properties is the file for the
fr language and the
Then, for each file entry, we instantiate an entry in our model inside the namespace and with the correct language attached.
After performing the import, we get a model with, for each namespace, several entries. Each entry has a key and several values. Each value is attached to the language.
To perform the JSON export, I used the NeoJSON project. NeoJSON allows one to create a custom encoder.
For the export, we first select a language. Then, we build a dictionary with all the namespaces:
To export a namespace (i.e., a
CS18NNamespace), I define a custom encoder:
The custom encoder consists on converting a
Namespace into a dictionary of entries with the entries keys and their values in the selected language.
Perform the migration
Once my importer and exporter are designed, I can perform the migration.
To do so, I use a little script.
It creates a model of I18N, imports several
.properties file entries in the model, and exports the Arabic entries in a JSON file.
The meta-model, importer, and exporter are freely available in GitHub.