Website Internationalization (i18n): The Ultimate Guide
As a company with global ambitions, expanding into new markets is a vital step. An expansion will likely require a localized website that fits your target market. But before you can even translate your website’s content, you must first internationalize it.
2022-12-02
- What is internationalization (i18n)?
- Why should you localize your website?
- Is your website internationalized?
- Internationalization requirements.
- Internationalization requirements.
- Backend setup.
- Replace hard-coded strings.
- Generate translation files.
- Translate your strings.
- Add a language selector.
- Updating translatable strings.
- Add more locales to your website.

1.Add more locales to your website.
Internationalization is the process of preparing a product (usually software) to support different languages and regional standards. Without going through the internationalization process, your website’s structure makes it impossible to translate your content. In other words, it’s the groundwork of the localization process, with the ultimate goal of getting your website localized in as many languages as you deem fit.
2. Why should you localize your website?
By localizing your website, you adapt it to the cultural and linguistic preferences of your new customers. You can’t reasonably expect that a website designed for Chinese customers is going to be user-friendly to American customers. Not only is the language different, but the browsing habits of the two segments are substantially different and must be treated accordingly. It’s not based on our experience alone; in fact, consider the following statistics:
- 87% of consumers don’t buy anything from a website in another language.
- 65% of consumers prefer to read a website in their native language.
- Visitors stay twice as long on a localized website.
- 64% of buyers value localized content.
Among all the possible investments you can make, improving your customers’ user experience provides the highest returns. According to WebFX, every dollar invested in UX provided a $100 return. That’s an ROI of 9,900%!
But, before you can start to localize your website, it must be internationalized.
3. Is your website internationalized?
Before proceeding, we first need to know if your website is already internationalized. After all, your website may already be ready for the localization process, but you’re just not aware of it. Here are some key pointers that can guide you:
- If your website contains hard-coded strings (website strings/texts embedded inside the code like the example below), then it isn’t internationalized.
Design better.
Design Mobile UI faster and better with our product and produce
professional designs for your business
Available on Android and iOS.
Free for 3 months
Hard-coded strings
- It is not internationalized if it doesn’t support right-to-left languages, such as Arabic and Hebrew.
- It is not internationalized if it only supports one time zone, number, and currency format.
- It is not internationalized if it has no functionality to switch between languages/locales.
- It is not internationalized if it is not Unicode compliant.
Unicode Standard is a character coding system designed to support the worldwide processing, interchange, and display of the texts of diverse languages and technical disciplines of the world. Moreover, it supports historical and classical texts of many written languages. It also provides the solution for internationalization and the architecture to support localization.
Knowing all the above, let’s see how we can start internationalizing a website.
4. Internationalization requirements
Before we delve into the specific steps, you will need some basic tools to get this done. We used PyCharm IDE for this project, but it is not compulsory. We also used Python 3.10 for this demonstration, you can download it here. You can refer to this link for a detailed walkthrough of Python’s installation.
We will also use these two:
- Flask-Babel is a library that implements i18n and l10n support for Flask (Python) Web Applications.
- Flask is a lightweight web framework for Python.
Although coding skills aren’t an absolute requirement, they are definitely recommended. Otherwise, we encourage you to have a learner’s mindset since it will help you push through some challenging steps.
You may either build a sample website from scratch, use your existing website, or clone our GitHub repository and use it to follow the internationalization steps from this article.
To clone our repository, run this command.
Bash
git clone https://github.com/Transphere-Sunyu/i18n-python.git
5. Project configuration
First, create an i18n-python folder and the following three folders (inside it): static, locales, and templates, together with an app.py file in the root directory.
For UNIX/Linux operating system.
Plaintext
mkdir i18n-python && cd i18n-python
mkdir static locales templates && touch app.py
For Windows operating system.
Plaintext
mkdir i18n-python && cd i18n-python
mkdir static locales templates && type nul > app.py
Create a Virtual Environment where all the packages will be installed. This is automatically created if you are using Pycharm.
Shell
pip install virtualenv
python -m venv ./venv
Activate the Virtual Environment.
Shell
source venv/bin/activate
Run the command below in your terminal pointing to your project folder path to install Flask and Flask-Babel into the project.
Plaintext
pip3 install Flask_Babel Flask
Create a babel.cfg file to let Babel know where to look for translations and add the following.
Plaintext
[python: **.py]
[jinja2: **/templates/**.html]
The first two lines define the filename patterns for Python and Jinja2 template files, respectively. Jinja2 is an extensible templating engine that allows code similar to Python syntax to be used. It relies on data passed to it to generate the final document. The project folder structure should resemble the one below.
6. Backend setup
In your app.py, import the following modules at the top of the file.
Python
from flask import Flask, render_template, request, session
from flask_babel import Babel
import os
Add the following code to the same file.
Python
app = Flask(__name__)babel = Babel(app)app.config[‘BABEL_DEFAULT_LOCALE’] = ‘en’
app.config[‘LANGUAGES’] = {
‘en’: ‘English’,
‘zh’: ‘Chinese(Simplified)’,
‘ar’: ‘Arabic’
}
app.config[‘SECRET_KEY’] = ‘your secret key’
app.config[“BABEL_TRANSLATION_DIRECTORIES”] = os.path.abspath(‘locales/’)
# Make languages and current_languages variables
# accessible in all the templates
@app.context_processor
def inject_conf_var():
return dict(languages=app.config[‘LANGUAGES’],
current_language=session.get(‘lang’,
request.accept_languages.best_match(app.config[‘LANGUAGES’].keys())))
@babel.localeselector
def get_locale():
if request.args.get(‘lang’):
session[‘lang’] = request.args.get(‘lang’)
return session.get(‘lang’, request.accept_languages.best_match(app.config[‘LANGUAGES’].keys()))
@app.route(‘/’)
def index():
get_locale()
return render_template(‘index.html’)
if __name__ == ‘__main__’:
app.run()
Make sure to replace “BABEL_TRANSLATION_DIRECTORIES” with the path to your translation folder.
@app.context_processor basically makes the language and current_language variables available to every template in the form of a dictionary, as seen below in the web application.
JSON
{
‘languages’: {‘en’: ‘English’,
‘zh’: ‘Chinese(Simplified)’},
‘current_language’: ‘en’
}
7. Replace hard-coded strings
Wrap the strings (texts to be translated) in the HTML file in parentheses with the _() text marker to tell Flask-Babel which strings you want to translate, i.e., {{ _(‘HTML string!’) }}. Do this for all the strings, and the result will look like this:
HTML
{{ _(‘Design better.’) }}
{{ _(‘Design Mobile UI faster and better with our
product and produce professional designs for your
business’) }}
8. Generate translation files
Run the following commands below to extract the strings from the HTML file in the template folder.
Plaintext
pybabel extract -F babel.cfg -o messages.pot .
You should be able to see the following logs after running the command if you are using the code from our repository.
Bash
extracting messages from app.py
extracting messages from templates\index.html
The pybabel extract command reads the configuration file given in the -F option, then scans all the files in the directories that match the configured sources. By default, PyBabel looks for _() as a text marker. The -o option indicates the name of the output .pot file.
You should be able to see the following logs after running the command if you are using the code from our repository.
Bash
pybabel init -i messages.pot -d locales -l zh
The pybabel init command uses the messages.pot file and writes a new language catalog to the directory given in the -d option (locales) for the language specified (zh) in the -l option, and it generates a translation.po file as seen below.
Plaintext
#: templates/index.html:62 templates/next.html:62
msgid “Design better.”
msgstr “”#: templates/index.html:63 templates/next.html:63
msgid “”
“Design Mobile UI faster and better with our product and produce “
“professional designs for your business”
msgstr “”
msgid contains the base language strings, while msgstr contains the target language strings.
9. Translate your strings
Translation strings should be added to msgstr in the messages.po file and would resemble the snippet below.
Plaintext
#: templates/index.html:71 templates/next.html:71
msgid “Available on Android and iOS.”
msgstr “可在 Android 和 iOS 上使用。”#: templates/index.html:86 templates/next.html:86
msgid “Features”
msgstr “特点”
We will not add translation strings one by one because that is clearly time-consuming and inefficient.
We are going to use Trados Studio to translate our source strings to our target language. Feel free to pick an alternative Translation Management System. This step is pretty simple; create and set up a project and add your source file, which would be messages.po in our case.
Translate your strings, and once they are signed off/approved, export the target language file back to your locales folder, which would be locales/zh/LC_MESSAGES in our case.
Once all translations are done, the command below compiles the translation files in the locales folder to .mo files, which are the files that Flask-Babel will use to load the translations for the website.
10. Add a language selector.
Add a language selector for users to select their preferred language.
Add the following Bootstrap CDN code at the bottom of your body tag.
HTML
And add this one to the header tag.
HTML
And add this one to the header tag.
HTML
{% for language in languages.items() %}
-
{{ language[1] }}
{% endfor %}
The current_language and language variables are accessible in the HTML file due to the @app.context_processor decorator, which was mentioned above.
.items() method returns the languages as tuples in a list, and they are looped through to get the list of languages that are displayed as a dropdown list.
To view the website on your browser and switch between the languages, run the command below in the terminal.
Plaintext
flask run
11. Updating translatable strings
Suppose you want to add new text to your website’s pages. How would you go about it? You would just need to follow Step 7 in the HTML file.
Add a paragraph tag to your index.html with a new translatable string.
HTML
{{ _(‘Free for 3 months’) }}
Run the extract command to extract the translatable strings.
HTML
pybabel extract -F babel.cfg -o messages.pot .
Notice that the messages.pot file has been updated with the new translatable string.
Next, run the update command, which will update the message.po file.
HTML
pybabel update -i messages.pot -d locales
Translate the new string and finally run the compile command.
HTML
pybabel compile -d locales
12. Add more locales to your website
At this point, you should consider a language service provider to help you with the localization and translation of your strings/content. Since you’ve finalized the groundwork, you can hand the translation to professionals and update your locales folder with new locales.