Soluling home   Document home

Web Application Localization and Internationalization

Web Application Localization and Internationalization

Soluling localization tool and service can localize most web applications and pages. Compared to a desktop or mobile applications, web application development is much more diverse. There are dozens of different technologies and frameworks you can use to create web applications. There are also multiple ways you can use a single technology. A typical web application contains markup files, script files, resource files, and data storage. Data storage can be either a database, a rest API, an XML file, or a JSON file. Each markup file can contain embedded scripts, or it can use external script files. They can either be scripts that are run on the server-side (C#, Visual Basic, PHP, Ruby, Java) or scripts that are run on the client-side (JavaScript or C#).

Web items

All these items might contain strings that need to be localized. If your application is internationalized correctly, you need, in most cases, only to localize the resource files and sometimes strings in the database. If your application is not properly internationalized, you may need to localize the markup and script files as well.

We have written a sample web application that is multilingual and consumes a multilingual API.

Web applications can have strings in several locations and formats. All these diversity impacts to localization, and because of it, there is no single way to localize web applications. The web application can use resource files just like a desktop application, but they can also use databases, text files, and other storages to hold translations. It can be a major effort to localize a large web application. Fortunately, Soluling makes this a lot easier. Soluling supports several kinds of web application localization methods. They are:

Resource files

This is the most popular way to localize web applications. When using this method, you don't hardcode any strings to markup or script files. Instead, you use the resource files of your web development framework. All frameworks support some kind of API or markup syntax to access string resource files.

This method is used in most localization tutorials and documentations. Learn more about this method.

Localized files

Although using resources works perfectly, it faces a few problems. Most obvious is the fact that you no longer can hardcode any strings into your markup or code files (except when working with Angular). This makes editing and maintaining of your files more complicated. This is why Soluling supports an additional localization method where you can hardcode all strings into your markup and script files. Soluling reads the original files made by you and creates a localized set of files for each language. Localized files have exactly the same structure as your original files. Only strings, images, and other localizable items have been translated to the target language. You have to just maintain the original files, and whenever you deploy, Soluling will automatically create the localized files.

Learn more about this method.

Combination of localized markup and resource files

This is the combination of the above two methods. You use localized markup files (e.g., HTML templates) so you can hard code strings to the markup files, but there is only one set of script files where you have to use resources files. This is supported by some MVC based frameworks such as

Learn more about using localized files to localize web applications

Comparing methods

It is totally up to you what method you use. Soluling supports them all. If you want the same URL to serve all your languages, then you have to use resource files or a combination of localized markup and resource files. If you can have a different URL for each language (e.g., http://www.mysite.com/en, http://www.mysite.com/de, http://www.mysite.com/fr), then you can use the localized files method. Using resource files is much more popular than using localized files. The most obvious reason for this is that if you use localized files, you need a localization tool to keep all the localized files in sync, including markups, server-side code, and client-side code. There have been very few such tools. Fortunately, Soluling can localize such files.

  Pros Cons
Resource files
  • Commonly used method
  • Same URL can serve all languages
  • You have to remove all strings from markup and script files and replace them with resource string identifiers or calls to a resource function or at least mark the strings you want to localize
  • Localization of other data types but strings items (e.g images) is difficult
  • Your markup and script gets harder to read and maintain.
  • No SEO for localized content
Localized files
  • You can hard code script strings into all markup and script files
  • You can easily translate image, audio and video data
  • Faster on run time
  • Better for SEO
  • Each language need to have different URL

Combination of localized markup and resource files

  • You can hard code strings into all markup including the script data that is emabbbed into markup
  • Same URL serves all languages
  • Few platforms support this

Active language

If your web application uses a single language-independent URL (e.g., using resources or localized templates), you need to determine the language in the application. There are several methods to select the language. The following table shows the most commonly used methods.

Method Description
Accept-Language

This is the most commonly used method. A browser sends Accept-Language HTTP header with all HTTP requests. If you use server-side scripting, then the server can get resources in the language matching the Accept-Language value. If you use client-side scripting, then the Accept-Language can be ignored, and the application can query the browser language(s) using JavaScript.

This is the preferred method because the user can easily change her language by editing the browser's language settings.

Geolocation This is a less commonly used method. The idea is to use the IP address of the user to locate his/her location. Once located, then determine the language. This method faces two issues. The first is it might not be easy to determine the language if the region uses multiple languages. The second is the user has no way to change the outcome of the language detection. If this method is used, the application should also change a UI that lets the users change the language.
URL parameter This is also a less commonly used method. The URL can contain a parameter (e.g., https://www.myapp.com?lang=de) that specifies the active languages. However, it might be difficult for the user to enter the parameter correctly.
Cookie Your application can also issue a cookie that stores the active language. This is most commonly combines with a UI where the user can select the language. The selected language is then stored into a cookie to override the initial language detection.
User account property This is like using the cookie, but the language property is bound into the user account and stored on the server. The advantage of the cookie is that the value is cross-browser. The disadvantage is that this can only be used after the user has logged in.

No matter what method you use, you can always add UI that lets the user select the language. If selected, that language then overrides the initial language. You can save the selection into a cookie, browser storage, or user account property.

SEO

The method you use has implications for SEO (search engine optimization). Most web crawler crawls pages without passing the Accept-Language HTTP header. The location of the crawler is also located in a specific country. For example, Google's crawlers are based in the USA. That makes geolocation useless too. If you don't use a language-specific URL, the crawling happens in your application's default language that is most often English.

If language-specific SEO is important for you, use a language-specific URL. That means using localize files or compiling the application into language specific versions (Angular).

Using resources to localize web pages and applications

This is the most common way to localize web applications. The main idea is that you identify all those strings that need to be translated, and you replace the hardcoded strings with resource strings. This is typically done by using a platform-specific resource file format and by calling a get resource function of the platform. The function returns the right string matching the language that is currently selected.

A typical markup file contains strings in three element types: HTML elements, server-side scripts, and client-side scripts. Most often, a string is a part of the HTML element. For example, the following line shows a paragraph.

<p>Hello World</p>

The above string is hardcoded, and if you run the markup file, it always renders the above string. To use a resource element, add Hello World into a resource and replace the hardcoded strings with a script that gets the resource item.

<p><?=GetResource("Hello World")?></p>

Even above script looks like PHP it is not real PHP but it shows a generic pattern. In PHP you would use

<p><?=gettext("Hello World")?></p>

In ASP.NET you would use

<p><%=GetLocalResourceObject("Hello World")%></p> 

In Blazor you would use

<p>@localizer["Hello World"]</p>

Note that in ASP.NET and Blazor, you simply wrap the string with localizer call. When using Soluling, you do not have to create and maintain the .resx file because Soluling does it for you.

In JSP you would use

<p><%=resourceBundle.GetString("Hello_World")%></p> 

Even the get-resource function is different (gettext, GetLocalResourceObject, or GetString), and the markup syntax also differs (<%...%> or <?....?>) the method is very similar in all three platforms.

Some platforms do not uuse API call but a specific markup syntax that can be quite verbose. For example, React-i18next uses a syntax like this.

<p><Trans i18nKey=app.hello'>Hello World</Trans></p>

In addition to the extra markup (Trans element), the syntax also needs a resource file key (i18nKey attribute). This gets even more complex if you use React-Intl,

<p><FormattedHTMLMessage id="app.hello"
  defaultMessage="Hello World"
  description="Hello text"/></p>

Now you are required to add a description (e.g., comment).

Angular uses a different method where you just i18n attribute to all tag the elements you want to localize.

<p i18n>Hello World</p>

Angular's approach has two huge advantages: First, the impact on the template is minimal compared to the above methods. Second, you don't have to create or maintain the resource file manually, but Angular's i18n-extract tool will do that for you. This brings us to the two issues that make it harder to write applications when using the resource localize method.

  1. The first is that your markup gets more complex and more verbose. What used to be a plain string becomes a more complex API call or markup change. It will be harder to read the code and make any modifications. Some platforms use very verbose syntax in the string resource markup. Some such as Angular use very minimal.
  2. The second issue is the string extraction. You now have to move the string from the markup to the external resource file. Some platforms provide a tool for that. Such a tool is very important. Without a tool, you need to manually copy the string from the markup and add it to the resource file. In addition, if you modify the string you have to do that in the resource file. Many platforms provide an extraction tool. Use them.

If you can, select a platform that uses minimal markup change for the resource strings and has an extraction tool. By far, the best platform for these two requirements is Angular.

Some applications do not use resource files to store localized strings but use a home-brewed method that uses either databases, text files, JSON, or XML files to store translations. If you use such a method, you can easily use Soluling to localize your strings. Learn more about database, XML, JSON and text localization.

Using localized files to localize web pages and applications

Using this method, you add all your template and script files into a Soluling project. Soluling creates localized versions of the template and script files. You do not have to modify your template files at all. You might need to do the standard code enabling for your script files. This means start using JavaScript's Intl API for date and time formatting, etc. You end having multiple application projects that Soluling keeps in sync. You deploy each project into a language-specific URL.

Combination of localized markup and resource files

You only have one project in this method, but you do not use the resource API or markup in your templates. Instead, you add the template files into a Soluling project. Soluling then creates localized templates files. You configure your project to use the localized templates files. So your application overrides the complete template when run on a different language. Very few platforms support this method. See the following table what do.

Supported technologies

Soluling supports most of the popular web technologies. Supported technologies are:

Techno​logy Description Sup​ports resour​ces Sup​ports locali​zed files Sup​ports locali​zed markup
Angular Angular resource files (.xlf, .xmb,.json) yes - -
ASP.NET Core Web applications, services and APIs written in ASP.NET Core using Razor Pages, MVC or Web API (.resx, .aspx, .cshtml, .vbhtml, .csproj,.vbproj) yes yes yes (MVC)
ASP.NET Framework Web applications, services and APIs written in ASP.NET using Web Forms, Web Pages, MVC or Web API (.resx, .aspx, .cshtml, .vbhtml, .csproj, .vbproj) yes web site projects yes
Blazor Blazor applications (.csproj) yes - -
Django Django resource files (.po) yes yes yes
Go go-i18n files (.toml) yes yes -
HTML HTML files (.htm, .html) including HTML 5 - yes -
Java EE Java EE files (.jsp, .gsp, .properties) yes yes -
JavaScript and TypeScript JavaScript and TypeScript files (.js, .ts) yes yes -
Magento Magento translation files (.csv) yes - -
PHP PHP files (.php, .po) yes yes -
Python gettext/po files (.po and .pot) yes yes -
React React resource files (.json) yes - -
Ruby on Rails Rails files (.yml, .yaml, .erb) yes yes yes
Svelte Svelte-i18n resource file (.json) yes - -
Vue Vue resource file (.json) yes - -

If you use some other web technology, most likely, you can still use Soluling. It is likely that Soluling supports the resource file format of the technology. If you want to use localized files or localized markup method, then add all markup files and code/script files into a Soluling project as separate sources.

Our complete web application sample, Sports, shows how to localize a web client, a server database, and how to implement a locale-aware REST API

Items that needs to be localized in a web application

Web application can have localizable data in several files and formats. You need to localize strings in markup elements, strings in scripts and strings in databases. The following table contains a list of different item types you might need to localize. The text that need to be localized is marked in red typeface.

Items to translate Sample
Strings in resources Each platfrom has it default strings resource format:
Platform Resource format
Angular .xlf, .xmb, and .json
AngularJS .json
ASP.NET .resx
Blazor .resx
Django .po
Go .json, .yaml, and .toml
PHP .po
Java .properties
React .json
Ruby on Rails .yaml
Vue .json
Strings element in markup
<p>This is a sample.</p>
Images element in markup
<img src="Files.png" />
Server side scripts in markup
<?php echo "This is a sample"; ?> 
Client side scripts in markup
<script>
function process()
{
  document.getElementById("hoursLabel").innerHTML = "This is a sample";
}
</script>
Strings in script file
protected void calculateButton_Click(object sender, EventArgs e)
{
  if ((Distance <= 0) || (Speed <= 0))
  {
    resultLabel.Text = "You must enter a valid distance and a speed!";
  }
  else
  {
    double time = Distance / Speed;
    uint hours = (uint)time;
    uint minutes = (uint)Math.Round(60 * (time - hours));
    resultLabel.Text = "Driving time is";
    hoursLabel.Text = String.Format("{0} hours", hours);
    minutesLabel.Text = String.Format("{0} minutes", minutes);
  }
}
Text in database
[Id][Name ][FieldPlayers][Goalie][Origin ][Description]
0   Soccer  10            1       England  Soccer is a sport played between two teams of eleven players with a spherical ball
...
Text in XML data file
<?xml version="1.0" encoding="utf-8"?>
<sports>
  <sport id="soccer" name="Soccer" fieldplayers="10" goalie="1" origin="England">
    <description>Soccer is a sport played between two teams of eleven players with a spherical ball.</description>
  </sport>
  ...
</sports>
Text in JSON data file
{
  "soccer":
  {
    "id": "soccer",
    "name": "Soccer",
    "fieldplayers": 10,
    "goalie": true,
    "origin": "England",
    "description": "Soccer is a sport played between two teams of eleven players with a spherical ball."
  },
  ...
}