Building an Electron App with Internationalization (i18n)

Electron is a modern framework that is suitable for building cross-platform desktop apps using common Web technologies we all know well like JavaScript, HTML, and CSS. The idea is simple as the application is Chromium and Node.js based so we can leverage the existing technologies without learning new paradigms. In this article, we will see step by step how to set up Internationalization (i18n) and Localization (l10n) in an Electron application and offer a more seamless experience for your users that choose to run it locally on their computer.

Building an Electron application is not much different from building a Single Page application with React or Angular. There are a few obvious differences as the app itself will run on the client host computer but the main design elements are the same. Adding i18n and l10n has a few tricky bits that we need to take care of. In this tutorial, we are going to create our own Electron application with fully i18n support both in the menu and in the content in a way that is efficient and scalable. We are going to use Electron + React for UI and i18next as the i18n provider.

For your convenience, you can also find the code in the Github repo.

Base Project Structure

Let’s start by creating a base project structure that will enable a convenient way to localize our application content. Later on, we are going to add a language menu both in the toolbar and in our content and will show how we can do it without sacrificing clarity.

1. Create an npm project and add the initial packages:

2. Create a main.js filed and add the base electron boilerplate code to instantiate the application window and the close handlers:

File: main.js

File: src/configs/app.config.js

We are just opening a window with some default dimensions and we attach some exit handlers for each OS. We also enable some developer tools that will help us when we develop our React Renderer process.

3. Update thepackage.json  to include starting scripts:

File: package.json

Now if you execute in the command line the following command:

It will open an empty window because we have no content to display. In order to display some content, we need to create a frontend application code that will be rendered in the Electron’s Renderer process. Let’s do that with the help of React.js.

React Frontend

Electron uses Chromium for displaying web pages, so we need a GUI for that. Let’s create a simple demo page to test the view:

1. Add React’s dependencies:

2. Create anindex.js  that will be used to bootstrap our React application. Since we are using react-scripts we need to place it in ansrc  folder:

File: src/index.js

File: src/index.css

3. Add a component that will like to display:

File: src/App.js

File: src/App.css

Let’s run our app and see what we have got:

 

 

Image 1: Voilà! Our first Electron Application

Now if you noticed, the menu of the application is preloaded with some default options that follow some OS guidelines for window layout. However, for our example, we would like to provide our own menu that will also include a drop-down of the available languages we support and the ability to change the language for the whole application. Let’s implement that in the next section.

Adding The Menu

We can add our own customized menu by utilizing the Menu API. We need to create 2 separate menu types. One for Mac computers and one for Windows and Linux.

1.  Start by creating a MenuFactoryService that will handle our Menu operations:

File: src/services/menuFactory.js

The above class just calls the associated methods of the Electron’s Menu API for each platform.

2. Create the menu functions for each platform:

File: src/menus/darwinMenu.js

File: src/menus/otherMenu.js

If you run the application again you will see our new menu:

Next, we are going to see how we can add our locale switcher in the menu and change language on demand.

Switching Locale from the Menu

We have built our own menu and now we would like to have a locale switcher menu for changing languages. We are going to use i18next that will help us manage the translations.

1. Add the i18next libraries to the project

2. Create a config object that will host our configuration options for the i18next framework

File: src/configs/i18next.config.js

3. Update theapp.config.js  to specify the list of supported locales

File: src/configs/app.config.js

Here we define our list of supported locales and the default locale. The namespace field will match the file names that the i18next library will seek in order to load our translations.

4. Create the locale folders but leave the files empty for now

Themissing files will be populated with entries that the i18next library has not found translations for that key yet so it’s handy for translators.

Now we can request our i18n object by just calling:

However, there is one caveat here. The i18n object has to initialize first before the first usage as it needs to apply the config we provided. Luckily for us, the i18next library exposes a list of events that dispatches on certain occasions. Out of the possible options we are interested in theonLoaded event that gets fired when we loaded resources. We can pair it up with theonLanguageChanged to build our translated menu.

1. Subscribe that event in order to load our initial translations properly.

File: main.js

2. Update themenuFactoryService  to accept the i18n config object

File: src/services/menuFactory.js

3. Update the darwin and the other menu functions to utilize thei18n.t  translator function:

File: src/menus/darwinMenu.js

File: src/menus/otherMenu.js

Pay particular attention to thelanguageMenu function where we build a radio menu with the list of available locales and how we attach the handler to change the language.

4. Run the application to populate themissing.json . That will create the following list of translations.

File: locales/en/translation.missing.json

5. Copy the contents of this file for each languagetranslation.json  files and provide translations

File: locales/el/translation.json

6. Finally, run the application and try to switch language from the menu. You can download the following video clip to see how it looks like.

Now that we have our locale aware menu lets try to make our rest of the application to switch language when we select it from the menu.

Changing locale in the Application Content

We have our little menu with the ability to change locale but we need to be able to update the main content as well. We need to include additional code for the renderer process in order to apply the translations in the content as well.

1. Update theindex.js  and themain.js  files to preload the initial translations on them. For that, we are going to use the ipcMain API to request the initial messages before we render the frontend application.

File: src/index/js

File main.js

2. Create the required files for the React.js Application

File: src/exportHelpers.js

File: src/configs/i18next.config.client.js

4. Update theApp.js  to include the translatable strings and provide the translations for all missing languages.

File: src/App.js

5. Run the Electron window and check to see that the content is translated correctly. However, there is a catch here. If you try to change the locale from the menu you will see that the content is not changed (it fallbacks to the translation keys instead). This happens because we have preloaded only one locale so far and we need the new language message catalog. Typically we would solve this using an i18next backend plugin but until now there is no plugin for Electron and we cannot use XHR.

Lucky for us there is a simple solution. We can utilize the webContents API to try to send from the main process the new message catalog when we change it from the menu. Then in the Renderer process, we can just call the addResourceBundle method and change locale. That way we can make sure we have all the correct translations on demand.

6. Add handlers formain.js  andindex.js  to load the translations on demand.

File: main.js

File: src/index.js

7. Provide the missing translations

File: locales/el/translation.json

File: locales/en/translation.json

8. Run the Application now and try to change the locale from the menu.

Check the following video for a small demo

Extra points

I leave as an exercise for the reader the ability to change the locale from within the application. You can add 2 buttons, one for each language and call thechangeLanguage  method. Make sure you request the message translations from the backend as well because you will stumble on the same issue as before.

Happy coding!

PhraseApp

PhraseApp supports many different languages and frameworks, including React.js and Node.js. It allows to easily import and export translations data and search for any missing translations, which is really convenient. On top of that, you can collaborate with translators as it is much better to have professionally done localization for your website. If you’d like to learn more about PhraseApp, refer to the Getting Started guide. You can also get a 14-days trial. So what are you waiting for?

Conclusion

Applications written in Electron have a better native feel compared to web versions and with the addition of i18n capabilities, you can expect to be more enjoyable for the users. In this tutorial, we’ve shown a few ways we can do that by developing a small application. This is by no means an exhaustive guide as every application has different needs and scope requirements. Please stay put for more detailed articles regarding this subject.

Building an Electron App with Internationalization (i18n)
5 (100%) 5 votes
Comments