23.2. locale — 国际化服务

源代码: Lib/locale.py


locale 模块开通了 POSIX 本地化数据库和功能的访问。POSIX 本地化机制让程序员能够为应用程序处理某些本地化的问题,而不需要去了解运行软件的每个国家的全部文化特点。

locale 模块是在 _locale 模块的基础上实现的,而 _locale 则又用到了 ANSI C 语言实现的本地化功能。

locale 模块定义了以下异常和函数:

exception locale.Error

当传给 setlocale() 的 locale 无法识别时,会触发异常。

locale.setlocale(category, locale=None)

如果给定了 locale 而不是 Nonesetlocale() 会修改 category 的 locale 设置。可用的类别会在下面的数据描述中列出。locale 可以是一个字符串,也可以是两个字符串(语言代码和编码)组成的可迭代对象。若为可迭代对象,则会用地区别名引擎转换为一个地区名称。若为空字符串则指明采用用户的默认设置。如果 locale 设置修改失败,会触发 Error 异常。如果成功则返回新的 locale 设置。

如果省略 locale 或为 None,将返回 category 但当前设置。

setlocale() 在大多数系统上都不是线程安全的。应用程序通常会如下调用:

import locale
locale.setlocale(locale.LC_ALL, '')

这会把所有类别的 locale 都设为用户的默认设置(通常在 LANG 环境变量中指定)。如果后续 locale 没有改动,则使用多线程应该不会产生问题。

locale.localeconv()

以字典的形式返回本地约定的数据库。此字典具有以下字符串作为键:

类别

(Windows 注册表的)键

含义

LC_NUMERIC

'decimal_point'

小数点字符。

'grouping'

数字列表,指定 'thousands_sep' 应该出现的位置。 如果列表以 CHAR_MAX 结束,则不会作分组。如果列表以 0 结束,则重复使用最后的分组大小。

'thousands_sep'

组之间使用的字符。

LC_MONETARY

'int_curr_symbol'

国际货币符号。

'currency_symbol'

当地货币符号。

'p_cs_precedes/n_cs_precedes'

货币符号是否在值之前(对于正值或负值)。

'p_sep_by_space/n_sep_by_space'

货币符号是否通过空格与值分隔(对于正值或负值)。

'mon_decimal_point'

用于货币金额的小数点。

'frac_digits'

货币值的本地格式中使用的小数位数。

'int_frac_digits'

货币价值的国际格式中使用的小数位数。

'mon_thousands_sep'

用于货币值的组分隔符。

'mon_grouping'

相当于 'grouping' ,用于货币价值。

'positive_sign'

用于标注正货币价值的符号。

'negative_sign'

用于注释负货币价值的符号。

'p_sign_posn/n_sign_posn'

符号的位置(对于正值或负值),见下文。

可以将所有数值设置为 CHAR_MAX ,以指示此语言环境中未指定任何值。

下面给出了 'p_sign_posn''n_sign_posn' 的可能值。

解释

0

被括号括起来的货币和金额。

1

该标志应位于值和货币符号之前。

2

该标志应位于值和货币符号之后。

3

标志应该紧跟在值之前。

4

标志应该紧跟值项。

CHAR_MAX

此语言环境中未指定任何内容。

该函数将 LC_CTYPE 地区设为 LC_NUMERIC 地区,若地区不同且数字或货币字符为非 ASCII,则设置为 LC_MONETARY 地区。这个临时的改变会影响到其他线程。

在 3.6.5 版更改: 现在在某些情况下,该函数会将 LC_CTYPE 地区设为 LC_NUMERIC 地区。

locale.nl_langinfo(option)

以字符串形式返回一些地区相关的信息。本函数并非在所有系统都可用,而且可用的 option 在不同平台上也可能不同。可填的参数值为数值,在 locale 模块中提供了对应的符号常量。

nl_langinfo() 函数可接受以下值。大部分含义都取自 GNU C 库。

locale.CODESET

获取一个字符串,代表所选地区采用的字符编码名称。

locale.D_T_FMT

获取一个字符串,可用作 time.strftime() 的格式串,以便以地区特定格式表示日期和时间。

locale.D_FMT

获取一个字符串,可用作 time.strftime() 的格式串,以便以地区特定格式表示日期。

locale.T_FMT

获取一个字符串,可用作 time.strftime() 的格式串,以便以地区特定格式表示时间。

locale.T_FMT_AMPM

获取一个字符串,可用作 time.strftime() 的格式串,以便以 am/pm 的格式表示时间。

DAY_1 ... DAY_7

获取一周中第 n 天的名称。

注解

这里遵循美国惯例,即 DAY_1 是星期天,而不是国际惯例(ISO 8601),即星期一是一周的第一天。

ABDAY_1 ... ABDAY_7

获取一周中第 n 天的缩写名称。

MON_1 ... MON_12

获取第 n 个月的名称。

ABMON_1 ... ABMON_12

获取第 n 个月的缩写名称。

locale.RADIXCHAR

获取小数点字符(小数点、小数逗号等)。

locale.THOUSEP

获取千位数(三位数一组)的分隔符。

locale.YESEXPR

获取一个可供 regex 函数使用的正则表达式,用于识别需要回答是或否的问题的肯定回答。

注解

该表达式的语法适用于 C 库的 regex() 函数,可能与 re 中的语法不一样。

locale.NOEXPR

获取一个可供 regex(3) 函数使用的正则表达式,用于识别需要回答是或否的问题的否定回答。

locale.CRNCYSTR

获取货币符号,如果符号应位于数字之前,则在其前面加上“-”;如果符号应位于数字之后,则前面加“+”;如果符号应取代小数点字符,则前面加“.”。

locale.ERA

获取一个字符串,代表当前地区使用的纪元。

大多数地区都没有定义该值。定义了该值的一个案例日本。日本传统的日期表示方法中,包含了当时天皇统治朝代的名称。

通常没有必要直接使用该值。在格式串中指定 E 符号,会让 time.strftime() 函数启用此信息。返回字符串的格式并没有定义,因此不得假定各个系统都能理解。

locale.ERA_D_T_FMT

获取一个字符串,可用作 time.strftime() 的格式串,以便以地区特定格式表示带纪元的日期和时间。

locale.ERA_D_FMT

获取一个字符串,可用作 time.strftime() 的格式串,以便以地区特定格式表示带纪元的日期。

locale.ERA_T_FMT

获取一个字符串,可用作 time.strftime() 的格式串,以便以地区特定格式表示带纪元的时间。

locale.ALT_DIGITS

获取 0 到 99 的表示法,最多不超过 100 个值。

locale.getdefaultlocale([envvars])

尝试确定默认的地区设置,并以 (language code, encoding) 元组的形式返回。

根据 POSIX 的规范,未调用 setlocale(LC_ALL, '') 的程序采用可移植的 'C' 区域设置运行。 调用 setlocale(LC_ALL, '') 则可采用 LANG 变量定义的默认区域。 由于不想干扰当前的区域设置,因此就以上述方式进行了模拟。

为了维持与其他平台的兼容性,不仅需要检测 LANG 变量,还需要检测 envvars 参数给出的变量列表。首先发现的定义将被采用。 envvars 默认为 GNU gettext 采用的搜索路径;必须包含 'LANG' 变量。 GNU gettext 的搜索路径依次包含了 'LC_ALL''LC_CTYPE''LANG''LANGUAGE'

除了 'C' 之外,语言代码对应 RFC 1766 标准。如果 语言代码编码 不能确定,可为 None

locale.getlocale(category=LC_CTYPE)

以列表的形式返回指定地区类别的当前设置,结果包括 语言代码编码category 可以是 LC_* 之一, LC_ALL 除外。默认为 LC_CTYPE

除了 'C' 之外,语言代码对应 RFC 1766 标准。如果 语言代码编码 不能确定,可为 None

locale.getpreferredencoding(do_setlocale=True)

Return the encoding used for text data, according to user preferences. User preferences are expressed differently on different systems, and might not be available programmatically on some systems, so this function only returns a guess.

某些系统必须调用 setlocale() 才能获取用户偏好,所以本函数不是线程安全的。如果不需要或不希望调用 setlocale,do_setlocale 应设为 False

locale.normalize(localename)

为给定的区域名称返回标准代码。返回的区域代码已经格式化,可供 setlocale() 使用。 如果标准化操作失败,则返回原名称。

如果给出的编码无法识别,则本函数默认采用区域代码的默认编码,这正类似于 setlocale()

locale.resetlocale(category=LC_ALL)

category 的区域设为默认值。

默认设置通过调用 getdefaultlocale() 确定。category 默认为 LC_ALL

locale.strcoll(string1, string2)

根据当前的 LC_COLLATE 设置,对两个字符串进行比较。与其他比较函数一样,根据 string1 位于 string2 之前、之后或是相同,返回负值、、正值或者 0

locale.strxfrm(string)

将字符串转换为可用于本地化比较的字符串。例如 strxfrm(s1) < strxfrm(s2) 相当于 strcoll(s1, s2) < 0。在重复比较同一个字符串时,可能会用到本函数,比如整理字符串列表时。

locale.format(format, val, grouping=False, monetary=False)

根据当前的 LC_NUMERIC 设置,对数字 val 进行格式化。格式将遵循 % 运算符的约定。浮点值的小数点会按需修改。若 grouping 为 True,则还会考虑分组。

monetary 为 True,则会用到货币千位分隔符和分组字符串。

Please note that this function will only work for exactly one %char specifier. For whole format strings, use format_string().

locale.format_string(format, val, grouping=False)

格式化符的处理类似 format % val ,但会考虑到当前的区域设置。

locale.currency(val, symbol=True, grouping=False, international=False)

根据当前的 LC_MONETARY 设置,对数字 val 进行格式化。

如果 symbol 为 True(默认值),则返回的字符串将包含货币符号。如果 grouping 为 True(非默认值),则会进行分组。如果 international 为 True(非默认值),将采用国际货币符号。

请注意,本函数对区域 “C” 无效,所以必须先通过 setlocale() 设置一个区域。

locale.str(float)

对浮点数进行格式化,格式要求与内置函数 str(float) 相同,但会考虑小数点。

locale.delocalize(string)

根据 LC_NUMERIC 的设置,将字符串转换为格式化后的数字字符串。

3.5 新版功能.

locale.atof(string)

根据 LC_NUMERIC 的设置,将字符串转换为浮点数。

locale.atoi(string)

按照 LC_NUMERIC 的约定,将字符串转换为整数。

locale.LC_CTYPE

字符型函数的区域类别。根据该类别的设置,模块 string 中处理大小写的函数会改变操作方式。

locale.LC_COLLATE

字符串排序会用到的区域类别。 将会影响 locale 模块的 strcoll()strxfrm() 函数。

locale.LC_TIME

格式化时间时会用到的区域类别。 time.strftime() 函数会参考这些约定。

locale.LC_MONETARY

格式化货币值时会用到的区域类别。可用值可由 localeconv() 函数获取。

locale.LC_MESSAGES

显示消息时用到的区域类别。目前 Python 不支持应用定制的本地化消息。 由操作系统显示的消息,比如由 os.strerror() 返回的消息可能会受到该类别的影响。

locale.LC_NUMERIC

格式化数字时用到的区域类别。 locale 模块的 format()atoi()atof()str() 函数会受到该类别的影响。其他所有数字格式化操作不受影响。

locale.LC_ALL

混合所有的区域设置。如果在区域改动时使用该标志,将尝试设置所有类别的区域参数。只要有任何一个类别设置失败,就不会修改任何类别。在使用此标志获取区域设置时,会返回一个代表所有类别设置的字符串。之后可用此字符串恢复设置。

locale.CHAR_MAX

一个符号常量, localeconv() 返回多个值时将会用到。

示例:

>>> import locale
>>> loc = locale.getlocale()  # get current locale
# use German locale; name might vary with platform
>>> locale.setlocale(locale.LC_ALL, 'de_DE')
>>> locale.strcoll('f\xe4n', 'foo')  # compare a string containing an umlaut
>>> locale.setlocale(locale.LC_ALL, '')   # use user's preferred locale
>>> locale.setlocale(locale.LC_ALL, 'C')  # use default (C) locale
>>> locale.setlocale(locale.LC_ALL, loc)  # restore saved locale

23.2.1. 背景、细节、提示、技巧和注意事项

The C standard defines the locale as a program-wide property that may be relatively expensive to change. On top of that, some implementation are broken in such a way that frequent locale changes may cause core dumps. This makes the locale somewhat painful to use correctly.

当程序第一次启动时,无论用户偏好定义成什么,区域值都是 C。不过有一个例外,就是在启动时修改 LC_CTYPE 类别,设置当前区域编码为用户偏好编码。程序必须调用 setlocale(LC_ALL, '') 明确表示用户偏好区域将设为其他类别。

若要从库程序中调用 setlocale() ,通常这不是个好主意,因为副作用是会影响整个程序。保存和恢复区域设置也几乎一样糟糕:不仅代价高昂,而且会影响到恢复之前运行的其他线程。

如果是要编写通用模块,需要有一种不受区域设置影响的操作方式(比如某些用到 time.strftime() 的格式),将不得不寻找一种不用标准库的方案。更好的办法是说服自己,可以采纳区域设置。只有在万不得已的情况下,才能用文档标注出模块与非 C 区域设置不兼容。

根据区域设置进行数字运算的唯一方法,就是采用本模块定义的函数:atof()atoi()format()str()

无法根据区域设置进行大小写转换和字符分类。对于(Unicode)文本字符串来说,这些操作都是根据字符值进行的;而对于字节符串来说,转换和分类则是根据字节的 ASCII 值进行的,高位被置位的字节(即非 ASCII 字节)永远不会被转换或被视作字母或空白符之类。

23.2.2. 针对扩展程序编写人员和嵌入Python 运行的程序

除了要查询当前区域,扩展模块不应去调用 setlocale()。但由于返回值只能用于恢复设置,所以也没什么用(也许只能用于确认是否为 C)。

当 Python 代码利用 locale 模块修改区域设置时,也会影响到嵌入 Python 运行的应用程序。如果嵌入运行的程序不希望发生这种情况,则应从 config.c 文件的内置模块表中删除 _locale 扩展模块(所有操作均是由它完成的),并确保 _locale 模块不能成为一个共享库。

23.2.3. 访问信息目录

locale.gettext(msg)
locale.dgettext(domain, msg)
locale.dcgettext(domain, msg, category)
locale.textdomain(domain)
locale.bindtextdomain(domain, dir)

在提供 gettext 接口的系统中,locale 模块暴露出了 C 库的接口。它由 gettext()dgettext()dcgettext()textdomain()bindtextdomain()bind_textdomain_codeset() 等函数组成。 他们与 gettext 模块中的同名函数类似,但采用了 C 库二进制格式的消息目录,以及 C 库的搜索算法来查找消息目录。

Python 应用程序通常不需要调用这些函数,而应改用 gettext。这条规则的一个已知例外,是与附加 C 库链接的应用程序,他们在内部调用了 gettext()dcgettext()。对于这些应用程序,可能有必要绑定文本域,以便库可以准确找到他们的信息目录。