The definition of internationalization varies from field to field, but here is a high-level working definition of the material for the W3C’s internationalization activities. Some people use other terms (such as globalization) to refer to the same concept.

Internationalization is the design and development of product, application, or document content that can be easily localized for a target audience of different cultures, regions, or languages. Internationalization is usually written in English as i18n, where 18 is the number of letters between I and n in an English word. [1]

This paper is mainly based on Java, aiming at language internationalization. Any software that faces the world will face the problem of multilingual internationalization. For Java Web applications, the internationalization function is to replace the data with a language that the user can recognize before it is presented to the user.

Use Spring’s own i18n (internationalization)

This part of the tutorial is easy, and can be found by searching the web. Here I will manually configure Spring i18n internationalization once to introduce it. Here are the Spring Boot version numbers I used.

1-1. Configure i18n in Properties or YML resource files

The author used a YML file, which can be converted to a Properties file format.

Basename: A comma-separated list of base names (essentially a fully qualified classpath location), each of which follows the ResourceBundle convention, with relaxed support for slash-based locations. If it does not contain a package qualifier (such as “org.myPackage”), it will be resolved from the classpath root directory.

cache-duration: Duration of loaded resource bundle file cache. If not set, the bundle will be permanently cached. If the duration suffix is not specified, seconds are used.

1-2. Add i18n folder under Resources folder and create the corresponding internationalization file

When the Spring container is started, it will load the resource file into the MessageSource based on the configured basename. How to load the resource file into the MessageSource will not be explained here.

The file configuration is shown in Figure 1-1.

Note:The red box is the configuration of i18n resource files, and the green box is the folder automatically generated by IDEA, which does not exist in fact, so just ignore it.



Figure 1-1 i18n resource file

1-3. Use i18n for internationalization in your code

This demonstrates a relatively simple manual parameter substitution, but there are better methods, such as parameter substitution when the response data is written to the stream.

1-4. Test Spring i18n

After starting the project, look at the data returned by calling the /test/console interface three times to set the language in the header: default, Chinese, and English.

The author used the HTTP Client for IDEA. Here are the request parameters:

Here are the response parameters:

1-5. Analyze the execution results

1-5-1. The response data of test default and test Chinese are the same, so we can determine the default Chinese environment used by the system. 1-5-2. When the getMessage() method is called, failing to pass the second argument is a no-argument substitution; Otherwise, vice versa. 1-5-3. When using a substitution with arguments, you can also add date, time and other parameters to the properties file, and Spring can automatically format the corresponding date and time.

1-6. Conclusion

This is just a brief demonstration of the capabilities of Spring i18n, which can meet the needs of some simple scenarios. If you need to extend it, there are several ideas.

1-6-1. If you are using a configuration center such as nacos, you need to go to the registry and manually pull the contents of the i18n properties file and load it into the application’s memory, or you can store a copy in the local user folder. 1-6-2. If you need some regular translation, you’ll need to write your own regular replacement expressions. 1-6-3. This example shows the replacement in controller, or better yet, in filter, or even when the response data is written to the stream. For example, if you specify a serialized class for an attribute of a response object (@JsonSerializer.class), then when the field is serialized, it will be serialized using TestJsonSerializer.class. In this class, we can make the substitutions we want.

Custom i18n

Spring i18n is useful, but not powerful enough for complex business requirements. Let’s say a user wants to add a language; Recursive substitution; Layouts can be customized, and when users add layout fields, they can set up different translations for people in different areas of the project or organization, and so on.

Extending i18n has been a necessity for a variety of reasons. So how do you scale?

The essence of internationalization is to replace a key with a value in a different language. There are a few key points in this sentence: key, substitution, language, value. Key, language and value are all nouns, representing specific data. Substitution is a verb that represents specific translation logic. Then we need to design and implement for these points.

2-1. Design data sheet

Idea: Find the corresponding value by a language and key. Table structure design is relatively simple, with a table for Key, Value and Language, as shown in Figure 2-1.



Figure 2-1 Internationalization table structure design

Each table only shows the primary key number field. In fact, there are some fields that are not shown, such as code and name, which can be designed according to your own style. If it is a multi-tenant system, data isolation can be achieved by adding the corresponding tenant ID after each table. 2-1-1. If the user adds a field that needs to be translated, add a data entry to the language key and add the same number of records to the language value as the language definition. 2-1-2. If the user adds a new language definition, add the same number of records to the language value as the language key. 2-1-3. The same applies to update and delete.

2-2. Data cache design

In a world-oriented application, the frequency of translation is very high, and with the passage of time, the translated data is bound to be more and more. If every response to the translation of data to query the database, it is bound to cause a waste of database performance and the performance of the application itself. For this kind of modification frequency is not high data, we can cache, with space for time.

Here we intend to adapt this translation scenario with a two-level cache design, one for Redis and two for application memory.

Step1: cache the used data from the database in Redis, and generate an update flag and put it in Redis. The application first checks if the Redis update flag is empty before retrieving the translation data. Step2: If it is empty, it means that Redis has not cached the translation data. The translation data will be pulled from the database to the memory and pushed to Redis. If it is not empty, it means that Redis has cached the translation data, and then compares the update flag of Redis with the update flag of application memory. Step3: If it is not consistent, it means that the translation data has been changed, and the translation data need to be pulled from Redis again and cached in the application memory; If they are consistent, the translation data has not changed and can be used directly in the application memory. Step4: Return the final translation data (key-value) to the component that implements the translation logic.

As shown in Figure 2-2.



Figure 2-2 Internationalization Two-level Cache Design

The code is shown below.

2-3. Embed the replacement logic into Spring’s filter or serialization

Here, I only demonstrate a simple key->value substitution, as for recursive substitution, regular substitution can be considered to add.

A. When A request comes in, it first needs to do some pre-processing.

B. Sets the locale of the current thread according to the requested language.

C. Update the language cache data of the current application memory.

D. Replace the response data by serialization when the response is returned.

The code is shown below.

2-4. Test custom i18n

After starting the project, look at the data returned by calling the test/custom-i18n interface three times to set the language in the header: default, Chinese, and English.

The author used the HTTP Client for IDEA. Here are the request parameters:

Here are the return parameters:

2-5. Analyze the execution results

2-5-1. The response data of test default and test Chinese are the same, so the Chinese environment used by default can be determined. 2-5-2. For attributes with @JsonSerialize(using = i18NJsonSerializer.class) annotation, the corresponding value will be automatically replaced according to the key. 2-5-3. If no value is found based on key, the original key will still be used.

2-6. Conclusion

This is just a brief demonstration of the functionality of custom i18n, but it already supports user-added languages, custom translated values, multi-machine deployment, etc. If you want to support regular substitution, recursive translation can also be extended by itself.

conclusion

There are two implementations of i18n that are demonstrated here. Which one you want to use is a matter of opinion. For convenience, out of the box, choose Spring i18n; Figure flexible, extensibility strong, then choose custom i18n. Naturally, there must be many plans that I have not thought of. I am looking forward to communicating with you.

In the future, LIGAAI will continue to share more technical articles. Please pay attention to Liga@sf. For more details, please click on our official website LIGAAI – Intelligent R&D Management Platform

[1] “Localization vs. the Internationalization”. The W3C author: the original rookie0peng links: https://www.jianshu.com/p/95e… All articles in this blog are CC BY-SA 4.0 unless otherwise stated. Please quote the source.