App Engine and Internationalization
December 2017: Please note that this post has not been updated for a while and there could be differences in terms of commands, screenshots and problems in running the code.
The most famous statement that is sent to the output when you are trying to learn a programming language is “Hello World”.
Take a look at the screenshot below:
What am I trying to convey here ? Well, I got asked a few times how we can have internationalization support in App Engine applications. My standard answer typically is that, it has nothing to do with App Engine and it has everything to do with using the right Java constructs and a correct encoding of the data to ensure that you get the internationalization right.
Keeping that in mind, we are going to look at an App Engine application where we will tackle one part of the Internationalization (i18n) puzzle : language. We will store our data in a couple of languages : English and Hindi. And we shall write a web service to retrieve the data and ensure that the correct language encoded data is returned.
Sounds good? Let’s move forward.
Prerequisites
- Basic understanding of Java Web Development, which includes Servlets, JSP, WAR file structure, etc.
- You have a working development environment for Google App Engine. This includes the Google Eclipse plugin. The code for persisting the signature uses JDO (Java Data Objects).
- The Web Service is REST like and returns JSON encoded data. You do not need to be an expert in that but need to know what REST like / JSON data is about. We are using GSON, a Java library to convert your Java objects to JSON format.
What this Episode covers
- Demonstrates saving and retrieving data in multiple languages in an App Engine application.
- It demonstrates that via a simple Tips application that gives you multi-lingual tips in areas like Electricity Safety, Home Safety, etc. Two languages are supported : English and Hindi.
Please note that focus is on demonstrating the functionality and not on building out all validations and checks.
My Development Environment
- Eclipse Juno
- Google Eclipse plugin with App Engine SDK 1.8.8
You may have another version of Eclipse and older versions of SDK. I believe it will work fine and you need not have the latest version of the App Engine SDK for this to work.
Multi-language Support in Action
Let us check out the application in action first. This will help to understand the code much better.
The application is hosted for you at http://multilingualtips.appspot.com/
Visit the above link. It should bring up the screen shown below:
The App on its own is not doing much. We have simply loaded a bunch of tips in two areas : Electricity Safety and Home Safety. And for each of the these areas, we have multiple tips that are available in two languages : English and Hindi.
If you click the Home Safety Tips link (REST Service url is : http://multilingualtips.appspot.com/TipsService?tipCode=TC02) it will invoke a REST like web service, passing the tip code for the Home Safety and it will provide a JSON response of the tips , as given below:
Notice that both the languages are supported and correctly encoded characters are displayed in the browser.
In case you provide a url like http://multilingualtips.appspot.com/TipsService i.e. without any tipCode parameter, then it will provide the tips for both the areas.
Please pardon the translation in Hindi. I used good old Google Translate and there could be errors there.
Sounds good? Let’s get on with the code.
Download Full Source Code
I suggest that you begin with a full download of the project source code.
Go ahead & download the code from : https://github.com/rominirani/AppEngineMultiLingualTips
This is an Eclipse project that you can import directly. For the sake of reducing the code size, I have removed the App Engine SDK Jars from the WEB-INF\lib folder. So depending on the version of your App Engine SDK in the Eclipse development environment on your machine, please link to the appropriate App Engine SDK that you have for the project to build successfully. I have included the gson.jar in the WEB-INF\lib directory though.
If you are successful with importing the project into your Eclipse setup, the project directory should look something like this:
Entity Mode, DAO and Service Classes
Let us first look at the App Engine Entity side of things. What we are trying to model here are a set of Tips in different areas like Home Safety, Electricity Safety and so on.
Our main and only entity is going to be called Tips and it is modeled as follows:
- tipID : This is the auto generated Key. We will leave that to App Engine.
- tipCode : This is a unique way to identify the area or subject. For e.g. TC01, TC03,etc. This will be a way to filter the tips by code in the Web Service. It is a String field.
- tipTitle : This is the title in English. It is a String field. E.g. Home Safety.
- tipTitleHindi : This is the title in Hindi. It is a String field. E.g. गृह सुरक्षा
- tips : This is a List object of tips in the English language. Each item in the list is a String.
- tipsHindi : This is a List object of tips in the Hindi language. Each item in hte list is a String.
I am sure there are multiple ways to model it and the above modeling won’t be the best if you are supporting a lot more languages, but I am only trying to demonstrate the multi-language support here as quickly as possible.
The source code for our entity class Tips is listed below:
To work with the entity class, we are going to write a DAO (TipsDAO.java) with some utility methods for:
- getTips() : This method gets all the tips in the data store. This method will be called internally when we invoke the /TipsService endpoint without any parameters.
- add (…) : This method is used to add a tip to the datastore. All the required attributes of the Tips.java entity class need to be provided i.e. tip code, tip title, tip title Hindi, etc.
- getTips(tipCode): This methos gets all the tips for a particular tipCode. This method will be called internally when we invoke the /TipsService?tipCode=<somevalue>.
and other methods. The DAO Class uses Java Data Objects. The code is straight forward to understand as given below:
Finally, we have the Service class (TipsService.java). This is the Java Servlet that will expose a HTTP GET method. This simply takes the request parameters and retrieves the tips data. It will generate a JSON formatted response as the output.
The key thing to note is lines 24 & 25, where the correct character encoding is provided.
res.setCharacterEncoding(“UTF-8”);
res.setContentType(“text/json; charset=UTF-8”);
Loading the Tips
This is an important part of the puzzle. You want to make sure of the following 2 points:
- Your language data needs to be properly encoded. UTF-8 is a safe format to encode your language specific files in.
- Once the data files are correctly encoded, you should read the data correctly prior to populating it in the App Engine datastore.
The approach that we will be taking is to provide Text files that contain the tips in the respective languages and provide them as static files in the WEB-INF\sampleData folder.
So in the WEB-INF\sampleData folder, I have the following 4 files : 2 language files (English and Hindi) for each subject:
- electricitysafety.txt
- electricitysafety_hindi.txt
- homesafety.txt
- homesafety_hindi.txt
Now, once I have deployed the application to App Engine, these files are present in the WEB-INF\sampleData folder. Prior to making the Web Service available to all, I load the data via a separate servlet : LoadTipsService.
The source code for the LoadTipsService is shown below:
Let us look at the key points:
- For loading Electricity Safety Tips, I invoke the LoadTipsService via the following URL : http://multilingualtips.appspot.com/LoadTipsService?tipCode=TC01&tipTitle=Electricity Safety&tipTitleHindi=विद्युत सुरक्षा&tipFile=electricitysafety for Electricity Safety
- For loading Home Safety Tips, I invoke the LoadTipsService via the following URL: http://multilingualtips.appspot.com/LoadTipsService?tipCode=TC02&tipTitle=Home Safety&tipTitleHindi=गृह सुरक्षा&tipFile=homesafety
- Lines 19–22 are simply extracting out the attributes required for the Tips entity class that we saw earlier.
- Then it simply invokes the loadData method of the LoadTips utility class.
The LoadTips utility class is shown below:
This class is important. The main points to look out are:
- It loads both the English text file and Hindi text file in a sequence.
- Notice that while using the InputStreamReader, we are provided the UTF-8 encoding in the constructor. This is important.
- The rest of the code is straight forward. It simply reads each line of the file, which is a Tip, puts them in a list.
- Finally, it clears up the current tips for the Tip Code entity and invokes the add method of the TipsDAO class.
App Engine Administration Console
If you access the App Engine Admin Console for your application and navigate to the Data Store, you will notice that it supports multiple language displays quite well. This is unlike the local dev server, which does not support it if you navigate via the _ah/admin url.
Hope you liked this App Engine episode. Don’t wait anymore to get that multi-language support in your applications.
Till the next time, stay tuned and give me feedback. If you run into issues, do drop a note, I will do my best to get it working for you.