![]() |
Web Application Localization and Internationalization |
Soluling Desktop and Soluling Cloud can localize most web applications and pages. Compared to desktop or mobile applications, web development is much more diverse. There are dozens of technologies and frameworks for creating web applications, and there are several ways to use each of them. A typical web application contains markup files, script files, resource files, and data storage. The data storage can be a database, a REST API, or XML or JSON files. A markup file can contain embedded scripts, or it can use external script files. The scripts run either on the server (e.g., C#, PHP, Python, Ruby, Java, or Go) or on the client (JavaScript, TypeScript, or C# with Blazor).

All these items can contain strings that need to be localized. If your application is internationalized correctly, you only need to localize the resource files and, in some cases, the strings in the database. If it is not, you may need to localize the markup and script files as well.
Our web application sample, Sport, is a multilingual web application that consumes a multilingual REST API.
Web applications can have strings in several locations and formats, so there is no single way to localize them. A web application can use resource files just like a desktop application, but it can also store translations in databases, text files, or other storage. Localizing a large web application can be a major effort. Soluling supports the following methods.
Resource files |
This is the most popular method. You do not hardcode strings in the markup or script files. Instead, you use the resource files of your web framework. Every framework has an API or a markup syntax to get strings from the resource files.
Most localization tutorials and documentation use this method. Learn more about this method. |
Localized files |
Using resources works well, but it has a drawback: you can no longer hardcode strings in your markup or code files (except with Angular), which makes the files harder to edit and maintain. This is why Soluling supports another method, where you hardcode the strings in your markup and script files. Soluling reads your original files and creates a localized set of files for each language. The localized files have the same structure as the original files. Only the strings, images, and other localizable items have been translated. You maintain only the original files, and Soluling creates the localized files whenever you build. |
Combination of localized markup and resource files |
This combines the above two methods. You use localized markup files (e.g., Razor views), so you can hardcode the strings in the markup, but there is only one set of script files, where you use resource files. ASP.NET Core MVC and ASP.NET Framework support this. |
You can choose any of the methods. Soluling supports them all. If you want the same URL to serve all your languages, use resource files or a combination of localized markup and resource files. If each language can have its own URL (e.g., https://www.mysite.com/en, https://www.mysite.com/de, and https://www.mysite.com/fr), you can also use localized files. Resource files are much more popular than localized files, mostly because localized files need a localization tool that keeps all the localized markup, server code, and client code in sync. Soluling is such a tool.
| Pros | Cons | |
|---|---|---|
| Resource files |
|
|
| Localized files |
|
|
| Combination of localized markup and resource files |
|
|
If your web application uses a single, language-independent URL, the application has to determine the language. The following table shows the most common methods.
| Method | Description |
|---|---|
| Accept-Language | This is the most common method. A browser sends the This is the preferred method because users can change their language in the browser's language settings. |
| Geolocation | This is a less common method. The application uses the IP address of the user to determine the location and then the language. This method has two issues. First, it is not easy to determine the language if the region uses several languages. Second, the user cannot change the result. If you use this method, also provide a UI that lets users change the language. |
| URL | The URL contains the language, either as a path (e.g., https://www.myapp.com/de/) or as a parameter (e.g., https://www.myapp.com?lang=de). A language path is the best method for SEO. |
| Cookie | The application stores the active language in a cookie. This is most often combined with a UI where the user selects the language. The selected language is stored in a cookie, and it overrides the initial language detection. |
| User account property | This is like a cookie, but the language is a property of the user account and stored on the server. The advantage over a cookie is that the language is the same in all browsers and devices. The disadvantage is that the application knows the language only after the user has signed in. |
Whatever method you use, you can add a UI that lets users select the language. The selected language then overrides the initial language. Save the selection in a cookie, browser storage, or a user account property.
The method has implications for SEO (search engine optimization). Most web crawlers do not send the Accept-Language header, and they crawl from a specific country. For example, Google's crawlers are mostly in the USA, which makes geolocation useless too. If you do not use language-specific URLs, the crawlers see only the default language of your application, which is most often English.
If language-specific SEO is important to you, use a language-specific URL for each language, and add hreflang links that tell the search engines which URL contains which language. You get language-specific URLs with localized files, with language routes in your application, or by building language-specific versions of the application (Angular).
<link rel="alternate" hreflang="en" href="https://www.mysite.com/en/" /> <link rel="alternate" hreflang="de" href="https://www.mysite.com/de/" />
This is the most common way to localize web applications. You find the strings that need to be translated and replace the hardcoded strings with resource strings. This is done with the resource file format and the resource function of the platform. The function returns the string in the active language.
A typical markup file contains strings in three places: HTML elements, server-side scripts, and client-side scripts. Most often, a string is a part of an HTML element. For example, the following line shows a paragraph.
<p>Hello World</p>
The string is hardcoded, and the page always shows it. To use a resource, add Hello World to a resource file and replace the hardcoded string with a script that gets the resource string.
<p><?=GetResource("Hello World")?></p>
The above is not real code, but it shows the general pattern. In PHP, you use
<p><?=gettext("Hello World")?></p>
In ASP.NET Core views, you use
<p>@Localizer["Hello World"]</p>
In Blazor, you use
<p>@localizer["Hello World"]</p>
In ASP.NET Core and Blazor, you only wrap the string in a localizer call. You do not have to create and maintain the .resx files, because Soluling does it for you.
In JSP, you use
<p><%=resourceBundle.getString("Hello_World")%></p>
or the JSTL <fmt:message key="Hello_World"/> tag. The function and the syntax differ from platform to platform, but the method is very similar.
Some platforms use a markup syntax instead of a function call. For example, react-i18next uses
<p><Trans i18nKey="app.hello">Hello World</Trans></p>
In addition to the extra Trans element, the syntax needs the key of the resource string (i18nKey). React-Intl uses
<p><FormattedMessage id="app.hello" defaultMessage="Hello World" description="Hello text"/></p>
The optional description is a comment for the translator.
Angular uses another method: you add the i18n attribute to the elements you want to localize.
<p i18n>Hello World</p>
Angular's approach has two big advantages. First, the change to the template is minimal. Second, you do not create or maintain the resource file manually, because the ng extract-i18n command does it for you. These are the two issues that make the resource method harder to use:
If you can, select a platform that needs a minimal markup change and has an extraction tool. Angular is the best platform for these two requirements.
Some applications do not use resource files but store the translations in databases, text files, or JSON or XML files. Soluling can localize them too. Learn more about database, XML, JSON, and text localization.
You add your markup and script files to a Soluling project, for example, as an HTML, PHP, or Java EE project. Soluling creates localized versions of the files. You do not have to change your markup files. You may need to internationalize your scripts, for example, by using JavaScript's Intl API for dates and numbers. You get a set of files for each language, and Soluling keeps them in sync with the original files. Deploy each set to a language-specific URL.
In this method, you have only one application, but you do not use the resource API or markup in your views. Instead, you add the view files to a Soluling project, and Soluling creates localized view files. The application uses the localized views for each language, so it replaces the complete view when it runs in another language. The scripts use resource files. Very few platforms support this. See the table below.
You can localize resource files, single HTML files, and script files with Soluling Desktop, or upload them directly to Soluling Cloud and translate them in Translate. To localize a project file (e.g., .csproj) or a directory of files (e.g., an HTML, PHP, or Java EE project), create the project in Soluling Desktop and upload it to Soluling Cloud. The page of each technology describes the Desktop and Cloud processes. You need a Soluling account. See the available Cloud plans.
Soluling supports most of the popular web technologies.
| Technology | Description | Supports resources | Supports localized files | Supports localized markup |
|---|---|---|---|---|
| Angular |
Angular resource files (.xlf, .xmb, .arb, .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 | - |
| Go | go-i18n files (.json) |
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 resource files (.yml, .yaml) |
yes | yes | - |
| Svelte |
Svelte-i18n resource file (.json) |
yes | - | - |
| Vue |
Vue resource file (.json) |
yes | - | - |
For Django, Go, Python, and Ruby on Rails, localized files means the source code files (.py, .go, and .rb) that Soluling localizes as script files. Soluling does not localize Django or Rails (.erb) templates.
If you use some other web technology, you can most likely still use Soluling, because it probably supports the resource file format of the technology. To use the localized files or localized markup method, add the markup and script files to a Soluling project as separate sources.
Our complete web application sample, Sport, shows how to localize a web client and a server database, and how to implement a locale-aware REST API.
A web application can have localizable data in several files and formats: strings in markup elements, strings in scripts, and strings in databases. The following table lists the kinds of items you might need to localize. The text that needs to be localized is in bold.
| Items to translate | Sample | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Strings in resources | Each platform has its default resource format:
|
||||||||||||||||||||||||
| Strings in markup elements | <p>This is a sample.</p> |
||||||||||||||||||||||||
| Images in markup elements | <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 files | 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 a 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 an 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 a 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."
},
...
} |