Internationalization and Localization¶
Introduction¶
Internationalization and localization are means of adapting software for non-native environments, especially for other nations and cultures.
Parts of an application which might need to be localized might include:
- Language
- Date/time format
- Formatting of numbers e.g. decimal points, positioning of separators, character used as separator
- Time zones (UTC in internationalized environments)
- Currency
- Weights and measures
The distinction between internationalization and localization is subtle but important. Internationalization is the adaptation of products for potential use virtually everywhere, while localization is the addition of special features for use in a specific locale.
For example, in terms of language used in software, internationalization is the process of marking up all strings that might need to be translated whilst localization is the process of producing translations for a particular locale.
Pylons provides built-in support to enable you to internationalize language but leaves you to handle any other aspects of internationalization which might be appropriate to your application.
Note
Internationalization is often abbreviated as I18N (or i18n or I18n) where the number 18 refers to the number of letters omitted. Localization is often abbreviated L10n or l10n in the same manner. These abbreviations also avoid picking one spelling (internationalisation vs. internationalization, etc.) over the other.
In order to represent characters from multiple languages, you will need to utilize Unicode. This document assumes you have read the Understanding Unicode.
By now you should have a good idea of what Unicode is, how to use it in Python and which areas of you application need to pay specific attention to decoding and encoding Unicode data.
This final section will look at the issue of making your application work with multiple languages.
Pylons uses the Python gettext module for internationalization. It is based off the GNU gettext API.
Getting Started¶
Everywhere in your code where you want strings to be available in different
languages you wrap them in the _()
function. There are also a number of
other translation functions which are documented in the API reference at
http://pylonshq.com/docs/module-pylons.i18n.translation.html
Note
The _()
function is a reference to the ugettext()
function. _()
is a convention for marking text to be translated and saves on keystrokes. ugettext()
is the Unicode version of gettext()
; it returns unicode strings.
In our example we want the string 'Hello'
to appear in three different
languages: English, French and Spanish. We also want to display the word
'Hello'
in the default language. We’ll then go on to use some plural words
too.
Lets call our project translate_demo
:
$ paster create -t pylons translate_demo
Now lets add a friendly controller that says hello:
$ cd translate_demo
$ paster controller hello
Edit controllers/hello.py
to make use of the _()
function everywhere
where the string Hello
appears:
import logging
from pylons.i18n import get_lang, set_lang
from translate_demo.lib.base import *
log = logging.getLogger(__name__)
class HelloController(BaseController):
def index(self):
response.write('Default: %s<br />' % _('Hello'))
for lang in ['fr','en','es']:
set_lang(lang)
response.write("%s: %s<br />" % (get_lang(), _('Hello')))
When writing wrapping strings in the gettext functions, it is important not to piece sentences together manually; certain languages might need to invert the grammars. Don’t do this:
# BAD!
msg = _("He told her ")
msg += _("not to go outside.")
but this is perfectly acceptable:
# GOOD
msg = _("He told her not to go outside")
The controller has now been internationalized, but it will raise a
LanguageError
until we have setup the alternative language catalogs.
GNU gettext use three types of files in the translation framework.
POT (Portable Object Template) files¶
The first step in the localization process. A program is used to search
through your project’s source code and pick out every string passed to one
of the translation functions, such as _()
. This list is put together in
a specially-formatted template file that will form the basis of all
translations. This is the .pot
file.
PO (Portable Object) files¶
The second step in the localization process. Using the POT file as a
template, the list of messages are translated and saved as a .po
file.
MO (Machine Object) files¶
The final step in the localization process. The PO file is run through a
program that turns it into an optimized machine-readable binary file, which
is the .mo
file. Compiling the translations to machine code makes the
localized program much faster in retrieving the translations while it is
running.
GNU gettext provides a suite of command line programs for extracting messages from source code and working with the associated gettext catalogs. The Babel project provides pure Python alternative versions of these tools. Unlike the GNU gettext tool xgettext, Babel supports extracting translatable strings from Python templating languages (currently Mako and Genshi).
Using Babel¶

To use Babel, you must first install it via easy_install. Run the command:
$ easy_install Babel
Pylons (as of 0.9.6) includes some sane defaults for Babel’s distutils commands in the setup.cfg file.
It also includes an extraction method mapping in the setup.py file. It is commented out by default, to avoid distutils warning about it being an unrecognized option when Babel is not installed. These lines should be uncommented before proceeding with the rest of this walk through:
message_extractors = {'translate_demo': [
('**.py', 'python', None),
('templates/**.mako', 'mako', None),
('public/**', 'ignore', None)]},
We’ll use Babel to extract messages to a .pot
file in your project’s
i18n
directory. First, the directory needs to be created. Don’t forget to
add it to your revision control system if one is in use:
$ cd translate_demo
$ mkdir translate_demo/i18n
$ svn add translate_demo/i18n
Next we can extract all messages from the project with the following command:
$ python setup.py extract_messages
running extract_messages
extracting messages from translate_demo/__init__.py
extracting messages from translate_demo/websetup.py
...
extracting messages from translate_demo/tests/functional/test_hello.py
writing PO template file to translate_demo/i18n/translate_demo.pot
This will create a .pot
file in the i18n
directory that looks something
like this:
# Translations template for translate_demo.
# Copyright (C) 2007 ORGANIZATION
# This file is distributed under the same license as the translate_demo project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2007.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: translate_demo 0.0.0\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2007-08-02 18:01-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9dev-r215\n"
#: translate_demo/controllers/hello.py:10 translate_demo/controllers/hello.py:13
msgid "Hello"
msgstr ""
The .pot
details that appear here can be customized via the
extract_messages
configuration in your project’s setup.cfg
(See the
Babel Command-Line Interface Documentation for all
configuration options).
Next, we’ll initialize a catalog (.po
file) for the Spanish language:
$ python setup.py init_catalog -l es
running init_catalog
creating catalog 'translate_demo/i18n/es/LC_MESSAGES/translate_demo.po' based on
'translate_demo/i18n/translate_demo.pot'
Then we can edit the last line of the new Spanish .po
file to add a
translation of "Hello"
:
msgid "Hello"
msgstr "¡Hola!"
Finally, to utilize these translations in our application, we need to compile
the .po
file to a .mo
file:
$ python setup.py compile_catalog
running compile_catalog
1 of 1 messages (100%) translated in 'translate_demo/i18n/es/LC_MESSAGES/translate_demo.po'
compiling catalog 'translate_demo/i18n/es/LC_MESSAGES/translate_demo.po' to
'translate_demo/i18n/es/LC_MESSAGES/translate_demo.mo'
We can also use the update_catalog
command to merge new messages from the
.pot
to the .po
files. For example, if we later added the following
line of code to the end of HelloController’s index method:
response.write('Goodbye: %s' % _('Goodbye'))
We’d then need to re-extract the messages from the project, then run the
update_catalog
command:
$ python setup.py extract_messages
running extract_messages
extracting messages from translate_demo/__init__.py
extracting messages from translate_demo/websetup.py
...
extracting messages from translate_demo/tests/functional/test_hello.py
writing PO template file to translate_demo/i18n/translate_demo.pot
$ python setup.py update_catalog
running update_catalog
updating catalog 'translate_demo/i18n/es/LC_MESSAGES/translate_demo.po' based on
'translate_demo/i18n/translate_demo.pot'
We’d then edit our catalog to add a translation for “Goodbye”, and recompile
the .po
file as we did above.
For more information, see the Babel documentation and the GNU Gettext Manual.
Back To Work¶
Next we’ll need to repeat the process of creating a .mo
file for the en
and fr
locales:
$ python setup.py init_catalog -l en
running init_catalog
creating catalog 'translate_demo/i18n/en/LC_MESSAGES/translate_demo.po' based on
'translate_demo/i18n/translate_demo.pot'
$ python setup.py init_catalog -l fr
running init_catalog
creating catalog 'translate_demo/i18n/fr/LC_MESSAGES/translate_demo.po' based on
'translate_demo/i18n/translate_demo.pot'
Modify the last line of the fr
catalog to look like this:
#: translate_demo/controllers/hello.py:10 translate_demo/controllers/hello.py:13
msgid "Hello"
msgstr "Bonjour"
Since our original messages are already in English, the en
catalog can stay
blank; gettext will fallback to the original.
Once you’ve edited these new .po
files and compiled them to .mo
files,
you’ll end up with an i18n
directory containing:
i18n/translate_demo.pot
i18n/en/LC_MESSAGES/translate_demo.po
i18n/en/LC_MESSAGES/translate_demo.mo
i18n/es/LC_MESSAGES/translate_demo.po
i18n/es/LC_MESSAGES/translate_demo.mo
i18n/fr/LC_MESSAGES/translate_demo.po
i18n/fr/LC_MESSAGES/translate_demo.mo
Testing the Application¶
Start the server with the following command:
$ paster serve --reload development.ini
Test your controller by visiting http://localhost:5000/hello. You should see the following output:
Default: Hello
fr: Bonjour
en: Hello
es: ¡Hola!
You can now set the language used in a controller on the fly.
For example this could be used to allow a user to set which language they wanted your application to work in. You could save the value to the session object:
session['lang'] = 'en'
session.save()
then on each controller call the language to be used could be read from the
session and set in your controller’s __before__()
method so that the pages
remained in the same language that was previously set:
def __before__(self):
if 'lang' in session:
set_lang(session['lang'])
Pylons also supports defining the default language to be used in the
configuration file. Set a lang
variable to the desired default language in
your development.ini
file, and Pylons will automatically call set_lang
with that language at the beginning of every request.
E.g. to set the default language to Spanish, you would add lang = es
to
your development.ini
:
[app:main]
use = egg:translate_demo
lang = es
If you are running the server with the --reload
option the server will
automatically restart if you change the development.ini
file. Otherwise
restart the server manually and the output would this time be as follows:
Default: ¡Hola!
fr: Bonjour
en: Hello
es: ¡Hola!
Fallback Languages¶
If your code calls _()
with a string that doesn’t exist at all in your
language catalog, the string passed to _()
is returned instead.
Modify the last line of the hello controller to look like this:
response.write("%s %s, %s" % (_('Hello'), _('World'), _('Hi!')))
Warning
Of course, in real life breaking up sentences in this way is very dangerous because some grammars might require the order of the words to be different.
If you run the example again the output will be:
Default: ¡Hola!
fr: Bonjour World!
en: Hello World!
es: ¡Hola! World!
This is because we never provided a translation for the string 'World!'
so
the string itself is used.
Pylons also provides a mechanism for fallback languages, so that you can specify other languages to be used if the word is omitted from the main language’s catalog.
In this example we choose fr
as the main language but es
as a fallback:
import logging
from pylons.i18n import set_lang
from translate_demo.lib.base import *
log = logging.getLogger(__name__)
class HelloController(BaseController):
def index(self):
set_lang(['fr', 'es'])
return "%s %s, %s" % (_('Hello'), _('World'), _('Hi!'))
If Hello
is in the fr
.mo
file as Bonjour
, World
is only in
es
as Mundo
and none of the catalogs contain Hi!
, you’ll get the
multilingual message: Bonjour Mundo, Hi!
. This is a combination of the
French, Spanish and original (English in this case, as defined in our source
code) words.
You can also add fallback languages after calling set_lang
via the
pylons.i18n.add_fallback
function. Translations will be tested in the order
you add them.
Note
Fallbacks are reset after calling set_lang(lang)
– that is, fallbacks
are associated with the currently selected language.
One case where using fallbacks in this way is particularly useful is when you
wish to display content based on the languages requested by the browser in the
HTTP_ACCEPT_LANGUAGE
header. Typically the browser may submit a number of
languages so it is useful to be add fallbacks in the order specified by the
browser so that you always try to display words in the language of preference
and search the other languages in order if a translation cannot be found. The
languages defined in the HTTP_ACCEPT_LANGUAGE
header are available in
Pylons as request.languages
and can be used like this:
for lang in request.languages:
add_fallback(lang)
Translations Within Templates¶
You can also use the _()
function within templates in exactly the same way
you do in code. For example, in a Mako template:
${_('Hello')}
would produce the string 'Hello'
in the language you had set.
Babel currently supports extracting gettext messages from Mako and Genshi templates. The Mako extractor also provides support for translator comments. Babel can be extended to extract messages from other sources via a custom extraction method plugin.
Pylons (as of 0.9.6) automatically configures a Babel extraction mapping for your Python source code and Mako templates. This is defined in your project’s setup.py file:
message_extractors = {'translate_demo': [
('**.py', 'python', None),
('templates/**.mako', 'mako', None),
('public/**', 'ignore', None)]},
For a project using Genshi instead of Mako, the Mako line might be replaced with:
('templates/**.html, 'genshi', None),
See Babel’s documentation on Message Extraction for more information.
Lazy Translations¶
Occasionally you might come across a situation when you need to translate a
string when it is accessed, not when the _()
or other functions are called.
Consider this example:
import logging
from pylons.i18n import get_lang, set_lang
from translate_demo.lib.base import *
log = logging.getLogger(__name__)
text = _('Hello')
class HelloController(BaseController):
def index(self):
response.write('Default: %s<br />' % _('Hello'))
for lang in ['fr','en','es']:
set_lang(lang)
response.write("%s: %s<br />" % (get_lang(), _('Hello')))
response.write('Text: %s<br />' % text)
If we run this we get the following output:
Default: Hello
['fr']: Bonjour
['en']: Good morning
['es']: Hola
Text: Hello
This is because the function _('Hello')
just after the imports is called
when the default language is en
so the variable text
gets the value of
the English translation even though when the string was used the default
language was Spanish.
The rule of thumb in these situations is to try to avoid using the translation functions in situations where they are not executed on each request. For situations where this isn’t possible, perhaps because you are working with legacy code or with a library which doesn’t support internationalization, you need to use lazy translations.
If we modify the above example so that the import statements and assignment to
text
look like this:
from pylons.i18n import get_lang, lazy_gettext, set_lang
from helloworld.lib.base import *
log = logging.getLogger(__name__)
text = lazy_gettext('Hello')
then we get the output we expected:
Default: Hello
['fr']: Bonjour
['en']: Good morning
['es']: Hola
Text: Hola
There are lazy versions of all the standard Pylons translation functions.
There is one drawback to be aware of when using the lazy translation functions:
they are not actually strings. This means that if our example had used the
following code it would have failed with an error cannot concatenate 'str'
and 'LazyString' objects
:
response.write('Text: ' + text + '<br />')
For this reason you should only use the lazy translations where absolutely
necessary and should always ensure they are converted to strings by calling
str()
or repr()
before they are used in operations with real strings.
Producing a Python Egg¶
Finally you can produce an egg of your project which includes the translation files like this:
$ python setup.py bdist_egg
The setup.py
automatically includes the .mo
language catalogs your
application needs so that your application can be distributed as an egg. This
is done with the following line in your setup.py
file:
package_data={'translate_demo': ['i18n/*/LC_MESSAGES/*.mo']},
Plural Forms¶
Pylons also provides the ungettext()
function. It’s designed for
internationalizing plural words, and can be used as follows:
ungettext('There is %(num)d file here', 'There are %(num)d files here',
n) % {'num': n}
Plural forms have a different type of entry in .pot
/.po
files, as
described in The Format of PO Files
in GNU Gettext’s Manual:
#: translate_demo/controllers/hello.py:12
#, python-format
msgid "There is %(num)d file here"
msgid_plural "There are %(num)d files here"
msgstr[0] ""
msgstr[1] ""
One thing to keep in mind is that other languages don’t have the same plural forms as English. While English only has 2 plural forms, singular and plural, Slovenian has 4! That means that you must use ugettext for proper pluralization. Specifically, the following will not work:
# BAD!
if n == 1:
msg = _("There was no dog.")
else:
msg = _("There were no dogs.")
Summary¶
This document only covers the basics of internationalizing and localizing a web application.
GNU Gettext is an extensive library, and the GNU Gettext Manual is highly recommended for more information.
Babel also provides support for interfacing to the CLDR (Common Locale Data Repository), providing access to various locale display names, localized number and date formatting, etc.
You should also be able to internationalize and then localize your application using Pylons’ support for GNU gettext.
Further Reading¶
http://en.wikipedia.org/wiki/Internationalization
Please feel free to report any mistakes to the Pylons mailing list or to the author. Any corrections or clarifications would be gratefully received.
Note
This is a work in progress. We hope the internationalization, localization and Unicode support in Pylons is now robust and flexible but we would appreciate hearing about any issues we have. Just drop a line to the pylons-discuss mailing list on Google Groups.
babel.core
– Babel core classes¶
babel¶
Integrated collection of utilities that assist in internationalizing and localizing applications.
This package is basically composed of two major parts:
- tools to build and work with
gettext
message catalogs- a Python interface to the CLDR (Common Locale Data Repository), providing access to various locale display names, localized number and date formatting, etc.
copyright: |
|
---|---|
license: | BSD, see LICENSE for more details. |
Module Contents¶
-
class
babel.
Locale
(language, territory=None, script=None, variant=None)¶ Representation of a specific locale.
>>> locale = Locale('en', 'US') >>> repr(locale) "Locale('en', territory='US')" >>> locale.display_name u'English (United States)'
A Locale object can also be instantiated from a raw locale string:
>>> locale = Locale.parse('en-US', sep='-') >>> repr(locale) "Locale('en', territory='US')"
Locale objects provide access to a collection of locale data, such as territory and language names, number and date format patterns, and more:
>>> locale.number_symbols['decimal'] u'.'
If a locale is requested for which no locale data is available, an UnknownLocaleError is raised:
>>> Locale.parse('en_XX') Traceback (most recent call last): ... UnknownLocaleError: unknown locale 'en_XX'
For more information see RFC 3066.
-
character_order
¶ The text direction for the language.
>>> Locale('de', 'DE').character_order 'left-to-right' >>> Locale('ar', 'SA').character_order 'right-to-left'
-
currencies
¶ Mapping of currency codes to translated currency names. This only returns the generic form of the currency name, not the count specific one. If an actual number is requested use the
babel.numbers.get_currency_name()
function.>>> Locale('en').currencies['COP'] u'Colombian Peso' >>> Locale('de', 'DE').currencies['COP'] u'Kolumbianischer Peso'
-
currency_formats
¶ Locale patterns for currency number formatting.
Note
The format of the value returned may change between Babel versions.
>>> Locale('en', 'US').currency_formats['standard'] <NumberPattern u'\xa4#,##0.00'> >>> Locale('en', 'US').currency_formats['accounting'] <NumberPattern u'\xa4#,##0.00'>
-
currency_symbols
¶ Mapping of currency codes to symbols.
>>> Locale('en', 'US').currency_symbols['USD'] u'$' >>> Locale('es', 'CO').currency_symbols['USD'] u'US$'
-
date_formats
¶ Locale patterns for date formatting.
Note
The format of the value returned may change between Babel versions.
>>> Locale('en', 'US').date_formats['short'] <DateTimePattern u'M/d/yy'> >>> Locale('fr', 'FR').date_formats['long'] <DateTimePattern u'd MMMM y'>
-
datetime_formats
¶ Locale patterns for datetime formatting.
Note
The format of the value returned may change between Babel versions.
>>> Locale('en').datetime_formats['full'] u"{1} 'at' {0}" >>> Locale('th').datetime_formats['medium'] u'{1} {0}'
-
datetime_skeletons
¶ Locale patterns for formatting parts of a datetime.
>>> Locale('en').datetime_skeletons['MEd'] <DateTimePattern u'E, M/d'> >>> Locale('fr').datetime_skeletons['MEd'] <DateTimePattern u'E dd/MM'> >>> Locale('fr').datetime_skeletons['H'] <DateTimePattern u"HH 'h'">
-
day_period_rules
¶ Day period rules for the locale. Used by get_period_id.
-
day_periods
¶ Locale display names for various day periods (not necessarily only AM/PM).
These are not meant to be used without the relevant day_period_rules.
-
days
¶ Locale display names for weekdays.
>>> Locale('de', 'DE').days['format']['wide'][3] u'Donnerstag'
-
decimal_formats
¶ Locale patterns for decimal number formatting.
Note
The format of the value returned may change between Babel versions.
>>> Locale('en', 'US').decimal_formats[None] <NumberPattern u'#,##0.###'>
-
classmethod
default
(category=None, aliases={'el': 'el_GR', 'fi': 'fi_FI', 'bg': 'bg_BG', 'uk': 'uk_UA', 'tr': 'tr_TR', 'ca': 'ca_ES', 'de': 'de_DE', 'fr': 'fr_FR', 'da': 'da_DK', 'fa': 'fa_IR', 'ar': 'ar_SY', 'mk': 'mk_MK', 'bs': 'bs_BA', 'cs': 'cs_CZ', 'et': 'et_EE', 'gl': 'gl_ES', 'id': 'id_ID', 'es': 'es_ES', 'he': 'he_IL', 'ru': 'ru_RU', 'nl': 'nl_NL', 'pt': 'pt_PT', 'nn': 'nn_NO', 'no': 'nb_NO', 'ko': 'ko_KR', 'sv': 'sv_SE', 'km': 'km_KH', 'ja': 'ja_JP', 'lv': 'lv_LV', 'lt': 'lt_LT', 'en': 'en_US', 'sk': 'sk_SK', 'th': 'th_TH', 'sl': 'sl_SI', 'it': 'it_IT', 'hu': 'hu_HU', 'ro': 'ro_RO', 'is': 'is_IS', 'pl': 'pl_PL'})¶ Return the system default locale for the specified category.
>>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES']: ... os.environ[name] = '' >>> os.environ['LANG'] = 'fr_FR.UTF-8' >>> Locale.default('LC_MESSAGES') Locale('fr', territory='FR')
The following fallbacks to the variable are always considered:
LANGUAGE
LC_ALL
LC_CTYPE
LANG
Parameters: - category – one of the
LC_XXX
environment variable names - aliases – a dictionary of aliases for locale identifiers
-
display_name
¶ The localized display name of the locale.
>>> Locale('en').display_name u'English' >>> Locale('en', 'US').display_name u'English (United States)' >>> Locale('sv').display_name u'svenska'
Type: unicode
-
english_name
¶ The english display name of the locale.
>>> Locale('de').english_name u'German' >>> Locale('de', 'DE').english_name u'German (Germany)'
Type: unicode
-
eras
¶ Locale display names for eras.
Note
The format of the value returned may change between Babel versions.
>>> Locale('en', 'US').eras['wide'][1] u'Anno Domini' >>> Locale('en', 'US').eras['abbreviated'][0] u'BC'
-
first_week_day
¶ The first day of a week, with 0 being Monday.
>>> Locale('de', 'DE').first_week_day 0 >>> Locale('en', 'US').first_week_day 6
-
get_display_name
(locale=None)¶ Return the display name of the locale using the given locale.
The display name will include the language, territory, script, and variant, if those are specified.
>>> Locale('zh', 'CN', script='Hans').get_display_name('en') u'Chinese (Simplified, China)'
Parameters: locale – the locale to use
-
get_language_name
(locale=None)¶ Return the language of this locale in the given locale.
>>> Locale('zh', 'CN', script='Hans').get_language_name('de') u'Chinesisch'
New in version 1.0.
Parameters: locale – the locale to use
-
get_script_name
(locale=None)¶ Return the script name in the given locale.
-
get_territory_name
(locale=None)¶ Return the territory name in the given locale.
-
interval_formats
¶ Locale patterns for interval formatting.
Note
The format of the value returned may change between Babel versions.
How to format date intervals in Finnish when the day is the smallest changing component:
>>> Locale('fi_FI').interval_formats['MEd']['d'] [u'E d. \u2013 ', u'E d.M.']
See also
The primary API to use this data is
babel.dates.format_interval()
.Return type: dict[str, dict[str, list[str]]]
-
language
= None¶ the language code
-
language_name
¶ The localized language name of the locale.
>>> Locale('en', 'US').language_name u'English'
-
languages
¶ Mapping of language codes to translated language names.
>>> Locale('de', 'DE').languages['ja'] u'Japanisch'
See ISO 639 for more information.
-
list_patterns
¶ Patterns for generating lists
Note
The format of the value returned may change between Babel versions.
>>> Locale('en').list_patterns['start'] u'{0}, {1}' >>> Locale('en').list_patterns['end'] u'{0}, and {1}' >>> Locale('en_GB').list_patterns['end'] u'{0} and {1}'
-
measurement_systems
¶ Localized names for various measurement systems.
>>> Locale('fr', 'FR').measurement_systems['US'] u'am\xe9ricain' >>> Locale('en', 'US').measurement_systems['US'] u'US'
-
meta_zones
¶ Locale display names for meta time zones.
Meta time zones are basically groups of different Olson time zones that have the same GMT offset and daylight savings time.
Note
The format of the value returned may change between Babel versions.
>>> Locale('en', 'US').meta_zones['Europe_Central']['long']['daylight'] u'Central European Summer Time'
New in version 0.9.
-
min_week_days
¶ The minimum number of days in a week so that the week is counted as the first week of a year or month.
>>> Locale('de', 'DE').min_week_days 4
-
months
¶ Locale display names for months.
>>> Locale('de', 'DE').months['format']['wide'][10] u'Oktober'
-
classmethod
negotiate
(preferred, available, sep='_', aliases={'el': 'el_GR', 'fi': 'fi_FI', 'bg': 'bg_BG', 'uk': 'uk_UA', 'tr': 'tr_TR', 'ca': 'ca_ES', 'de': 'de_DE', 'fr': 'fr_FR', 'da': 'da_DK', 'fa': 'fa_IR', 'ar': 'ar_SY', 'mk': 'mk_MK', 'bs': 'bs_BA', 'cs': 'cs_CZ', 'et': 'et_EE', 'gl': 'gl_ES', 'id': 'id_ID', 'es': 'es_ES', 'he': 'he_IL', 'ru': 'ru_RU', 'nl': 'nl_NL', 'pt': 'pt_PT', 'nn': 'nn_NO', 'no': 'nb_NO', 'ko': 'ko_KR', 'sv': 'sv_SE', 'km': 'km_KH', 'ja': 'ja_JP', 'lv': 'lv_LV', 'lt': 'lt_LT', 'en': 'en_US', 'sk': 'sk_SK', 'th': 'th_TH', 'sl': 'sl_SI', 'it': 'it_IT', 'hu': 'hu_HU', 'ro': 'ro_RO', 'is': 'is_IS', 'pl': 'pl_PL'})¶ Find the best match between available and requested locale strings.
>>> Locale.negotiate(['de_DE', 'en_US'], ['de_DE', 'de_AT']) Locale('de', territory='DE') >>> Locale.negotiate(['de_DE', 'en_US'], ['en', 'de']) Locale('de') >>> Locale.negotiate(['de_DE', 'de'], ['en_US'])
You can specify the character used in the locale identifiers to separate the differnet components. This separator is applied to both lists. Also, case is ignored in the comparison:
>>> Locale.negotiate(['de-DE', 'de'], ['en-us', 'de-de'], sep='-') Locale('de', territory='DE')
Parameters: - preferred – the list of locale identifers preferred by the user
- available – the list of locale identifiers available
- aliases – a dictionary of aliases for locale identifiers
-
number_symbols
¶ Symbols used in number formatting.
Note
The format of the value returned may change between Babel versions.
>>> Locale('fr', 'FR').number_symbols['decimal'] u','
-
ordinal_form
¶ Plural rules for the locale.
>>> Locale('en').ordinal_form(1) 'one' >>> Locale('en').ordinal_form(2) 'two' >>> Locale('en').ordinal_form(3) 'few' >>> Locale('fr').ordinal_form(2) 'other' >>> Locale('ru').ordinal_form(100) 'other'
-
classmethod
parse
(identifier, sep='_', resolve_likely_subtags=True)¶ Create a Locale instance for the given locale identifier.
>>> l = Locale.parse('de-DE', sep='-') >>> l.display_name u'Deutsch (Deutschland)'
If the identifier parameter is not a string, but actually a Locale object, that object is returned:
>>> Locale.parse(l) Locale('de', territory='DE')
This also can perform resolving of likely subtags which it does by default. This is for instance useful to figure out the most likely locale for a territory you can use
'und'
as the language tag:>>> Locale.parse('und_AT') Locale('de', territory='AT')
Parameters: - identifier – the locale identifier string
- sep – optional component separator
- resolve_likely_subtags – if this is specified then a locale will
have its likely subtag resolved if the
locale otherwise does not exist. For
instance
zh_TW
by itself is not a locale that exists but Babel can automatically expand it to the full form ofzh_hant_TW
. Note that this expansion is only taking place if no locale exists otherwise. For instance there is a localeen
that can exist by itself.
Raises: - ValueError – if the string does not appear to be a valid locale identifier
- UnknownLocaleError – if no locale data is available for the requested locale
-
percent_formats
¶ Locale patterns for percent number formatting.
Note
The format of the value returned may change between Babel versions.
>>> Locale('en', 'US').percent_formats[None] <NumberPattern u'#,##0%'>
-
periods
¶ Locale display names for day periods (AM/PM).
>>> Locale('en', 'US').periods['am'] u'AM'
-
plural_form
¶ Plural rules for the locale.
>>> Locale('en').plural_form(1) 'one' >>> Locale('en').plural_form(0) 'other' >>> Locale('fr').plural_form(0) 'one' >>> Locale('ru').plural_form(100) 'many'
-
quarters
¶ Locale display names for quarters.
>>> Locale('de', 'DE').quarters['format']['wide'][1] u'1. Quartal'
-
scientific_formats
¶ Locale patterns for scientific number formatting.
Note
The format of the value returned may change between Babel versions.
>>> Locale('en', 'US').scientific_formats[None] <NumberPattern u'#E0'>
-
script
= None¶ the script code
-
script_name
¶ The localized script name of the locale if available.
>>> Locale('sr', 'ME', script='Latn').script_name u'latinica'
-
scripts
¶ Mapping of script codes to translated script names.
>>> Locale('en', 'US').scripts['Hira'] u'Hiragana'
See ISO 15924 for more information.
-
territories
¶ Mapping of script codes to translated script names.
>>> Locale('es', 'CO').territories['DE'] u'Alemania'
See ISO 3166 for more information.
-
territory
= None¶ the territory (country or region) code
-
territory_name
¶ The localized territory name of the locale if available.
>>> Locale('de', 'DE').territory_name u'Deutschland'
-
text_direction
¶ The text direction for the language in CSS short-hand form.
>>> Locale('de', 'DE').text_direction 'ltr' >>> Locale('ar', 'SA').text_direction 'rtl'
-
time_formats
¶ Locale patterns for time formatting.
Note
The format of the value returned may change between Babel versions.
>>> Locale('en', 'US').time_formats['short'] <DateTimePattern u'h:mm a'> >>> Locale('fr', 'FR').time_formats['long'] <DateTimePattern u'HH:mm:ss z'>
-
time_zones
¶ Locale display names for time zones.
Note
The format of the value returned may change between Babel versions.
>>> Locale('en', 'US').time_zones['Europe/London']['long']['daylight'] u'British Summer Time' >>> Locale('en', 'US').time_zones['America/St_Johns']['city'] u'St. John\u2019s'
-
unit_display_names
¶ Display names for units of measurement.
See also
You may want to use
babel.units.get_unit_name()
instead.Note
The format of the value returned may change between Babel versions.
-
variant
= None¶ the variant code
-
variants
¶ Mapping of script codes to translated script names.
>>> Locale('de', 'DE').variants['1901'] u'Alte deutsche Rechtschreibung'
-
weekend_end
¶ The day the weekend ends, with 0 being Monday.
>>> Locale('de', 'DE').weekend_end 6
-
weekend_start
¶ The day the weekend starts, with 0 being Monday.
>>> Locale('de', 'DE').weekend_start 5
-
zone_formats
¶ Patterns related to the formatting of time zones.
Note
The format of the value returned may change between Babel versions.
>>> Locale('en', 'US').zone_formats['fallback'] u'%(1)s (%(0)s)' >>> Locale('pt', 'BR').zone_formats['region'] u'Hor\xe1rio %s'
New in version 0.9.
-
-
babel.
default_locale
(category=None, aliases={'el': 'el_GR', 'fi': 'fi_FI', 'bg': 'bg_BG', 'uk': 'uk_UA', 'tr': 'tr_TR', 'ca': 'ca_ES', 'de': 'de_DE', 'fr': 'fr_FR', 'da': 'da_DK', 'fa': 'fa_IR', 'ar': 'ar_SY', 'mk': 'mk_MK', 'bs': 'bs_BA', 'cs': 'cs_CZ', 'et': 'et_EE', 'gl': 'gl_ES', 'id': 'id_ID', 'es': 'es_ES', 'he': 'he_IL', 'ru': 'ru_RU', 'nl': 'nl_NL', 'pt': 'pt_PT', 'nn': 'nn_NO', 'no': 'nb_NO', 'ko': 'ko_KR', 'sv': 'sv_SE', 'km': 'km_KH', 'ja': 'ja_JP', 'lv': 'lv_LV', 'lt': 'lt_LT', 'en': 'en_US', 'sk': 'sk_SK', 'th': 'th_TH', 'sl': 'sl_SI', 'it': 'it_IT', 'hu': 'hu_HU', 'ro': 'ro_RO', 'is': 'is_IS', 'pl': 'pl_PL'})¶ Returns the system default locale for a given category, based on environment variables.
>>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE']: ... os.environ[name] = '' >>> os.environ['LANG'] = 'fr_FR.UTF-8' >>> default_locale('LC_MESSAGES') 'fr_FR'
The “C” or “POSIX” pseudo-locales are treated as aliases for the “en_US_POSIX” locale:
>>> os.environ['LC_MESSAGES'] = 'POSIX' >>> default_locale('LC_MESSAGES') 'en_US_POSIX'
The following fallbacks to the variable are always considered:
LANGUAGE
LC_ALL
LC_CTYPE
LANG
Parameters: - category – one of the
LC_XXX
environment variable names - aliases – a dictionary of aliases for locale identifiers
-
babel.
negotiate_locale
(preferred, available, sep='_', aliases={'el': 'el_GR', 'fi': 'fi_FI', 'bg': 'bg_BG', 'uk': 'uk_UA', 'tr': 'tr_TR', 'ca': 'ca_ES', 'de': 'de_DE', 'fr': 'fr_FR', 'da': 'da_DK', 'fa': 'fa_IR', 'ar': 'ar_SY', 'mk': 'mk_MK', 'bs': 'bs_BA', 'cs': 'cs_CZ', 'et': 'et_EE', 'gl': 'gl_ES', 'id': 'id_ID', 'es': 'es_ES', 'he': 'he_IL', 'ru': 'ru_RU', 'nl': 'nl_NL', 'pt': 'pt_PT', 'nn': 'nn_NO', 'no': 'nb_NO', 'ko': 'ko_KR', 'sv': 'sv_SE', 'km': 'km_KH', 'ja': 'ja_JP', 'lv': 'lv_LV', 'lt': 'lt_LT', 'en': 'en_US', 'sk': 'sk_SK', 'th': 'th_TH', 'sl': 'sl_SI', 'it': 'it_IT', 'hu': 'hu_HU', 'ro': 'ro_RO', 'is': 'is_IS', 'pl': 'pl_PL'})¶ Find the best match between available and requested locale strings.
>>> negotiate_locale(['de_DE', 'en_US'], ['de_DE', 'de_AT']) 'de_DE' >>> negotiate_locale(['de_DE', 'en_US'], ['en', 'de']) 'de'
Case is ignored by the algorithm, the result uses the case of the preferred locale identifier:
>>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at']) 'de_DE'
>>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at']) 'de_DE'
By default, some web browsers unfortunately do not include the territory in the locale identifier for many locales, and some don’t even allow the user to easily add the territory. So while you may prefer using qualified locale identifiers in your web-application, they would not normally match the language-only locale sent by such browsers. To workaround that, this function uses a default mapping of commonly used langauge-only locale identifiers to identifiers including the territory:
>>> negotiate_locale(['ja', 'en_US'], ['ja_JP', 'en_US']) 'ja_JP'
Some browsers even use an incorrect or outdated language code, such as “no” for Norwegian, where the correct locale identifier would actually be “nb_NO” (Bokmål) or “nn_NO” (Nynorsk). The aliases are intended to take care of such cases, too:
>>> negotiate_locale(['no', 'sv'], ['nb_NO', 'sv_SE']) 'nb_NO'
You can override this default mapping by passing a different aliases dictionary to this function, or you can bypass the behavior althogher by setting the aliases parameter to None.
Parameters: - preferred – the list of locale strings preferred by the user
- available – the list of locale strings available
- sep – character that separates the different parts of the locale strings
- aliases – a dictionary of aliases for locale identifiers
-
babel.
parse_locale
(identifier, sep='_')¶ Parse a locale identifier into a tuple of the form
(language, territory, script, variant)
.>>> parse_locale('zh_CN') ('zh', 'CN', None, None) >>> parse_locale('zh_Hans_CN') ('zh', 'CN', 'Hans', None)
The default component separator is “_”, but a different separator can be specified using the sep parameter:
>>> parse_locale('zh-CN', sep='-') ('zh', 'CN', None, None)
If the identifier cannot be parsed into a locale, a ValueError exception is raised:
>>> parse_locale('not_a_LOCALE_String') Traceback (most recent call last): ... ValueError: 'not_a_LOCALE_String' is not a valid locale identifier
Encoding information and locale modifiers are removed from the identifier:
>>> parse_locale('it_IT@euro') ('it', 'IT', None, None) >>> parse_locale('en_US.UTF-8') ('en', 'US', None, None) >>> parse_locale('de_DE.iso885915@euro') ('de', 'DE', None, None)
See RFC 4646 for more information.
Parameters: - identifier – the locale identifier string
- sep – character that separates the different components of the locale identifier
Raises: ValueError – if the string does not appear to be a valid locale identifier
babel.localedata
— Babel locale data¶
babel.localedata¶
Low-level locale data access.
note: | The Locale class, which uses this module under the hood, provides a more convenient interface for accessing the locale data. |
---|---|
copyright: |
|
license: | BSD, see LICENSE for more details. |
-
babel.localedata.
exists
(name)¶ Check whether locale data is available for the given locale.
Returns True if it exists, False otherwise.
Parameters: name – the locale identifier string
-
babel.localedata.
exists
(name) Check whether locale data is available for the given locale.
Returns True if it exists, False otherwise.
Parameters: name – the locale identifier string
babel.dates
– Babel date classes¶
babel.dates¶
Locale dependent formatting and parsing of dates and times.
The default locale for the functions in this module is determined by the following environment variables, in that order:
LC_TIME
,LC_ALL
, andLANG
copyright: |
|
---|---|
license: | BSD, see LICENSE for more details. |
Module Contents¶
-
class
babel.dates.
DateTimeFormat
(value, locale)¶ -
format_frac_seconds
(num)¶ Return fractional seconds.
Rounds the time’s microseconds to the precision given by the number of digits passed in.
-
format_weekday
(char='E', num=4)¶ Return weekday from parsed datetime according to format pattern.
>>> format = DateTimeFormat(date(2016, 2, 28), Locale.parse('en_US')) >>> format.format_weekday() u'Sunday'
- ‘E’: Day of week - Use one through three letters for the abbreviated day name, four for the full (wide) name,
- five for the narrow name, or six for the short name.
>>> format.format_weekday('E',2) u'Sun'
- ‘e’: Local day of week. Same as E except adds a numeric value that will depend on the local starting day of the
- week, using one or two letters. For this example, Monday is the first day of the week.
>>> format.format_weekday('e',2) '01'
- ‘c’: Stand-Alone local day of week - Use one letter for the local numeric value (same as ‘e’), three for the
- abbreviated day name, four for the full (wide) name, five for the narrow name, or six for the short name.
>>> format.format_weekday('c',1) '1'
Parameters: - char – pattern format character (‘e’,’E’,’c’)
- num – count of format character
-
get_week_number
(day_of_period, day_of_week=None)¶ Return the number of the week of a day within a period. This may be the week number in a year or the week number in a month.
Usually this will return a value equal to or greater than 1, but if the first week of the period is so short that it actually counts as the last week of the previous period, this function will return 0.
>>> format = DateTimeFormat(date(2006, 1, 8), Locale.parse('de_DE')) >>> format.get_week_number(6) 1
>>> format = DateTimeFormat(date(2006, 1, 8), Locale.parse('en_US')) >>> format.get_week_number(6) 2
Parameters: - day_of_period – the number of the day in the period (usually either the day of month or the day of year)
- day_of_week – the week day; if ommitted, the week day of the current date is assumed
-
-
class
babel.dates.
DateTimePattern
(pattern, format)¶
babel.numbers
– Babel number classes¶
babel.numbers¶
Locale dependent formatting and parsing of numeric data.
The default locale for the functions in this module is determined by the following environment variables, in that order:
LC_NUMERIC
,LC_ALL
, andLANG
copyright: |
|
---|---|
license: | BSD, see LICENSE for more details. |
Module Contents¶
-
class
babel.numbers.
NumberFormatError
¶ Exception raised when a string cannot be parsed into a number.
-
class
babel.numbers.
NumberPattern
(pattern, prefix, suffix, grouping, int_prec, frac_prec, exp_prec, exp_plus)¶
-
babel.numbers.
format_number
(number, locale='zh_CN')¶ Return the given number formatted for a specific locale.
>>> format_number(1099, locale='en_US') u'1,099' >>> format_number(1099, locale='de_DE') u'1.099'
Parameters: - number – the number to format
- locale – the Locale object or locale identifier
-
babel.numbers.
format_decimal
(number, format=None, locale='zh_CN')¶ Return the given decimal number formatted for a specific locale.
>>> format_decimal(1.2345, locale='en_US') u'1.234' >>> format_decimal(1.2346, locale='en_US') u'1.235' >>> format_decimal(-1.2346, locale='en_US') u'-1.235' >>> format_decimal(1.2345, locale='sv_SE') u'1,234' >>> format_decimal(1.2345, locale='de') u'1,234'
The appropriate thousands grouping and the decimal separator are used for each locale:
>>> format_decimal(12345.5, locale='en_US') u'12,345.5'
Parameters: - number – the number to format
- format –
- locale – the Locale object or locale identifier
-
babel.numbers.
format_percent
(number, format=None, locale='zh_CN')¶ Return formatted percent value for a specific locale.
>>> format_percent(0.34, locale='en_US') u'34%' >>> format_percent(25.1234, locale='en_US') u'2,512%' >>> format_percent(25.1234, locale='sv_SE') u'2\xa0512\xa0%'
The format pattern can also be specified explicitly:
>>> format_percent(25.1234, u'#,##0\u2030', locale='en_US') u'25,123\u2030'
Parameters: - number – the percent number to format
- format –
- locale – the Locale object or locale identifier
-
babel.numbers.
format_scientific
(number, format=None, locale='zh_CN')¶ Return value formatted in scientific notation for a specific locale.
>>> format_scientific(10000, locale='en_US') u'1E4'
The format pattern can also be specified explicitly:
>>> format_scientific(1234567, u'##0E00', locale='en_US') u'1.23E06'
Parameters: - number – the number to format
- format –
- locale – the Locale object or locale identifier
-
babel.numbers.
parse_number
(string, locale='zh_CN')¶ Parse localized number string into an integer.
>>> parse_number('1,099', locale='en_US') 1099 >>> parse_number('1.099', locale='de_DE') 1099
When the given string cannot be parsed, an exception is raised:
>>> parse_number('1.099,98', locale='de') Traceback (most recent call last): ... NumberFormatError: '1.099,98' is not a valid number
Parameters: - string – the string to parse
- locale – the Locale object or locale identifier
Returns: the parsed number
Raises: NumberFormatError – if the string can not be converted to a number
-
babel.numbers.
parse_decimal
(string, locale='zh_CN')¶ Parse localized decimal string into a decimal.
>>> parse_decimal('1,099.98', locale='en_US') Decimal('1099.98') >>> parse_decimal('1.099,98', locale='de') Decimal('1099.98')
When the given string cannot be parsed, an exception is raised:
>>> parse_decimal('2,109,998', locale='de') Traceback (most recent call last): ... NumberFormatError: '2,109,998' is not a valid decimal number
Parameters: - string – the string to parse
- locale – the Locale object or locale identifier
Raises: NumberFormatError – if the string can not be converted to a decimal number