
Phrase and beyond
Software localization
Python's locale module is part of the standard library for internationalization (i18n) and localization (l10n) in Python. The locale module allows developers to deal with certain cultural issues in their applications. The good news is that they need not know all the specifics of the location or language where the software is used. Let's explore in great detail the basic concept of Python's locale module.
Let's have a look at the nuts and bolts of Python's locale module.
Based on the official documentation, the locale module is implemented on top of the _locale module. It uses an ANSI C locale implementation if available. A normal application typically starts with the following code to set the locale:
import locale # use user's default settings locale.setlocale(locale.LC_ALL, '') # use current setting locale.setlocale(locale.LC_ALL, None)
The first parameter represents the locale category while the second parameter modifies the locale setting for the category. It will use the current setting for the category if the second parameter is not present or None. On the other hand, an empty string will use the user's default setting.
In the following example, the locale is set to German (de_DE).
# name might vary with operating system, refer to the notes below locale.setlocale(locale.LC_ALL, 'de_DE')
Most of the time, it uses the Language Code Identifier (LCID) Reference, as stated in the following link (replace the hyphen in the language tags with an underscore). For example, de-DE should be stated as de_DE. However, older OS versions might accept the locale in a different format, as shown below:
# using standard Language Code Identifier (LCID) Reference locale.setlocale(locale.LC_ALL , 'de_DE') # using ISO country code, alpha-3 locale.setlocale(locale.LC_ALL , 'deu_deu') # using language name locale.setlocale(locale.LC_ALL , 'German')
The recommended method is to test out the standard Language Code Identifier Reference first. If you encountered an error, the next step is to print out the full list of the available locales in your machine.
# for Windows users for lang in locale.windows_locale.values(): print(lang) # for other operating systems for lang in locale.locale_alias.values(): print(lang)
You can get the string for the existing locale with the following code:
# get current locale loc = locale.getlocale()
Calling the built-in localeconv() function will provide you with detailed information about the current locale. Run the following code to visualize it:
for key, value in locale.localeconv().items(): print("%s: %s" % (key, value))
Here is an example output for en_SG (English/Singapore):
Check out the official documentation for more information on the keys and their respective meaning.
The locale module provides two specialized functions to parse a string into a number, based on the current locale:
This is extremely useful for parsing a string that contains a comma or dot, as different locales interpret it differently. For example:
locale.atof('32,824')
On top of that, you can use the format_string() function to format a number according to your preferences. The following code snippet is based on the de_DE locale:
locale.format_string('%10.2f', 738213.78) # 738213,78 locale.format_string('%10.2f', 738213.78, grouping=True) # grouping is False by default # 738.213,78
You can set a grouping parameter for the format_string() function, which accepts a boolean.
Furthermore, you can utilize the built-in currency() function to format any input number. The end result comes with the currency symbol or text. Let us have a look at the following example for en_SG:
locale.currency(924531.78) # $924531.78 locale.currency(924531.78, grouping=True) # $924,531.78 locale.currency(924531.78, grouping=True, international=True) # SGD924,531.78
Apart from the number input, the currency() function also accepts three additional parameters:
Other than that, the datetime module helps in formatting date and time, based on the locale that you have set. The easiest way is to rely on the strftime() function. It converts an object to a string according to a given format. It can be a date, time, or datetime object. Let's have a look at the following list of common format codes
You can find the full list of format codes in the following link.
Simply define the format in a string, and use it as the input parameter when calling the strftime() function. Check out the following example displaying the current date and time.
now = datetime.datetime.now() format = "%A, %d %b %Y %H:%M:%S %Z" now.strftime(format) # Thursday, 23 July 2020 13:11:31
In addition, you can display just the date component for a specific RSVP event as follows:
registration_date = datetime.date(2020, 8, 15) format = "RSVP by %A, %d-%b-%Y" registration_date.strftime(format) # RSVP by Saturday, 15-Aug-2020
If a value is stored as a timestamp in your database, you can easily convert it to a datetime object:
submission_date = datetime.datetime.fromtimestamp(1595485143) format = "Submit before %A, %#I%p %d/%m/%Y" # check notes below submission_date.strftime(format) # Submit before Thursday, 2PM 23/07/2020
%I (capital i) represents a 12-hour clock as a zero-padded decimal number. You can remove the leading zero by adding a hyphen or pound sign based on the operating system of your machine. For example,
Besides, you can highlight the timezone as long as the datetime object contains the optimal timezone information. We call this an aware datetime object. In contrast, a naive datetime object does not contain enough information to unambiguously locate itself in relation to other datetime objects. You can easily identify if a datetime object is aware or naive by printing it out.
# naive datetime object, there is no timezone information at the end 2020-08-13 15:14:00.990397 # aware datetime object, using UTC as timezone 2020-08-13 07:14:00.990397+00:00 # aware datetime object, using UTC+6 as timezone 2020-08-13 13:14:00.990397+06:00
For your information, you can easily construct and define a timezone in a datetime object by using datetime.timezone. Let us have a look at the following example of creating instances of current datetime based on different timezones.
format = "Timezone: %H:%M:%S %Z" # naive datetime object now = datetime.datetime.now() now.strftime(format) # Timezone 15:24:29 # aware datetime object, using UTC as timezone now = datetime.datetime.now(tz=datetime.timezone.utc) now.strftime(format) # Timezone 07:24:29 UTC # aware datetime object, using UTC as timezone now = datetime.datetime.now(tz=datetime.timezone(datetime.timedelta(hours=6))) now.strftime(format) # Timezone 13:24:29 UTC+06:0
%Z will return an empty string, called by a naive datetime object.
Based on the official documentation, the locale module is a program-wide property according to the C standard definition. As a result, it is extremely expensive to change a locale in between.
Frequent locale changes may cause core dumps. That is why it is highly recommended to set it just once while initializing your application.
An extension module or library routine should never call the setlocale() function, since it will affect the entire program.
Apart from the format_string() function, the only way to perform numeric operations according to the locale is to use the special functions defined by this module:
In conclusion, the locale module is extremely useful for internationalizing and localizing Python applications. If you are looking for ways to streamline your i18n process, let Phrase do the heavy lifting. The most comprehensive localization solution on the market, the Phrase Localization Suite will equip you with everything you need to:
Finally, check out the following articles if you want to know even more about internationalization and localization in Python:
Last updated on September 25, 2022.