vue-i18n and my way of handling JSON language files for it in .NET


In a project I have been working on for some time now, we use vue-i18n plugin for handling internationalization on the site. By using the plugin, wherever you need a translated text you can simply place $t(‘placeholder-name’) in your Vue template html. For example:

<p> {{ $t('main.welcomeMessage') }} </p>

Until a few days ago, in our project, each language had a separate corresponding JSON file maintained and stored alongside the rest of the FrontEnd code. It was pretty handy. It was so, for developers, but not from the administrator’s perspective.
Therefore, the application had to have some more convenient way of updating any text on the site from within the admin dashboard of the site. Because, the requirement was to build a translations editor within the admin dashboard, I decided to store all the translation placeholders in the database as records corresponding to each language (i.e. ‘en’, ‘pl’, etc.) and then return them to the app in a form that is expected by the vue-i18n plugin. This meant, that the list of placeholders had to be transformed to a JSON file on retrieval.

Problem:
vue-i18n plugin expects a JSON file of the following format:

{
  "common": {
    "buttons": { "readMore": "Read more" },
    "tooltips": { "goToChat": "Click to chat with [personName]" }
  },
  "dataTable": {
    "noDataAvailableText": "No data available",
    "noSearchResults": "Could not find any matching data",
    "search": "Search..."
  }
}

The above translates to such placeholders along with translations:

common.buttons.readMore: 'Read more'
common.tooltips.goToChat: 'Click to chat with [personName]'
dataTable.noDataAvailableText: 'No data available'
dataTable.noSearchResults: 'Could not find any matching data'
dataTable.search: 'Search...'

That is what would be stored in the database and could be conveniently modified by the admin in the admin dashboard.
How could we transform it back to the expected JSON file format?
Of course, first thing that one does nowadays is googling it. No point in reinventing the wheel. I googled, I looked around and could not find a ready-made solution in the form of code;) Maybe it is too trivial? However, judging by questions people ask on the internet, nothing seems to be too trivial:) Eventually, with a clear conscience, I went and developed the solution myself.

Solution:
Solving the problem can be done recursively or iteratively. The latter can sometimes be a little more troublesome and tends to be more verbose. I approached it recursively. The risk of getting stack overflow will be negligable, given that we validate the input and levels of nesting is not going to be too deep.
How many levels of nesting do we have in the example? Up to 2 (two dots in the placeholder). In the JSON files, we used in our project, the max was 5. It was not 1000, so all good!

The algorithm:
Assumption 1: a node has a name and a value that can be either the placeholder’s value or another node
Assumption 2: each placeholder can be referred to as path and each path has levels indicated with a dot, e.g. level0.level1.level2.level3

1. Given the path and the path's value, split the path by dots into parts.
2. If there are no more parts then return the path's value.
   Otherwise: 
   a) create a node and call it with the part's name
   b) trim the first part (the current node's name) of the path and pass it (along with path's value) to another call that will take the steps from step 1
   c) get the result of the call and place it in the current node's value
   b) return the node

I represented the nodes as objects of type Dictionary<object, object>. I could, as well, create a separate type, but one has to find some balance and for this particular solution that is, anyway, very low level, the standard .NET type is enough. How do we translate the hierarchy built on dictionaries into JSON? It turns out to be straightforward with NewtonSoft.Json’s JsonConvert.SerializeObject method. It accepts any .NET object and turns it into JSON, with Dictionary types, we get exactly the result we need 🙂

The code is up on GitHub. If anyone wants to have a quick solution for a similar case, then go ahead, clone, do whatever you want with it 🙂

Summary
If you are developing a Vue.js app and need internalization support in it, then unless you haven’t already found anything, I am happy with vue-i18n plugin and can recommend you to try it out. It may turn out enough for your needs. Additionally, if you don’t want to rely on separate tools such as BabelEdit and, instead, you want to have your own way developed in .NET backend to provide JSON files to the plugin then you might want to have a look at the source code linked above – it might save you some time:)

Leave a Reply

Your email address will not be published.