# `locale` --- 国际化服务

源代码： Lib/locale.py

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

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

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

exception `locale.``Error`

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

`locale.``setlocale`(category, locale=None)

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

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

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

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

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

`locale.``localeconv`()

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

  类别 | 键 | 含意
  --- | --- | ---
  `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` ，以指示本 locale 中未指定任何值。

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

  值 | 说明
  --- | ---
  `0` | 被括号括起来的货币和金额。
  `1` | 该标志应位于值和货币符号之前。
  `2` | 该标志应位于值和货币符号之后。
  `3` | 标志应该紧跟在值之前。
  `4` | 标志应该紧跟在值之后。
  `CHAR_MAX` | 该地区未指定内容。

  此函数可临时性地将 `LC_CTYPE` 语言区域设为 `LC_NUMERIC` 语言区域或者如果语言区域不同且数字或货币字符串是非 ASCII 的则设为 `LC_MONETARY` 语言区域。 这个临时性地改变会影响到其他线程。

  在 3.7 版更改: 现在此函数在某些情况下会临时性地将 `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 函数使用的正则表达式，用于识别需要回答是或否的问题的肯定回答。

  `locale.``NOEXPR`

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

    注解

    `YESEXPR` 和 `NOEXPR` 中的正则表达式使用了适合来自 C 库的 `regex()` 函数的语法，它与 `re` 中使用的语法会有所不同。

  `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)

  根据用户的偏好，返回用于文本数据的 locale encoding。用户偏好在不同的系统上有不同的表达方式，而且在某些系统上可能无法以编程方式获取到，所以本函数只是返回猜测结果。

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

  在 Android 系统中，或者启用了 Python UTF-8 Mode，则一定会返回 `'UTF-8'`， locale encoding 和 do_setlocale 参数将被忽略。

  Python preinitialization 用于配置 LC_CTYPE 区域。还请参阅 filesystem encoding and error handler。

  在 3.7 版更改: 现在，本函数在 Android 上或启用 Python UTF-8 Mode 时，总会返回 `UTF-8`。

`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_string`(format, val, grouping=False, monetary=False)

  根据当前的 `LC_NUMERIC` 设置对数字 val 进行格式化。 此格式将遵循 `%` 运算符的约定。 对于浮点数值，会根据具体情况修改小数点。 如果 grouping 为 `True`，还会将分组纳入考虑。

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

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

  在 3.7 版更改: 增加了关键字参数 monetary 。

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

  请注意，本函数的工作原理与 `format_string()` 类似，但只认一种 `%char` 格式符。 比如 `'%f'` 和 `'%.0f'` 都是有效的格式符，但 `'%f KiB'` 则不是。

  若想用到全部的格式化串，请采用 `format_string()`。

  3.7 版后已移除: 请改用 `format_string()` 。

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

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

  如果 symbol 为真值则返回的字符串将包括货币符号，该参数默认为真值。 如果 grouping 为 `True` (非默认值)，则会对值进行分组。 如果 international 为 `True` (非默认值)，则会使用国际货币符号。

  注解

  此函数将不适用于 'C' 语言区域，所以你必须先通过 `setlocale()` 设置一个语言区域。

`locale.``str`(float)

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

`locale.``delocalize`(string)

  根据 `LC_NUMERIC` 的设置，将字符串转换为标准化的数字字符串。

  3.5 新版功能.

`locale.``localize`(string, grouping=False, monetary=False)

  根据 `LC_NUMERIC` 的设置，将标准化的数字字符串转换为格式化的字符串。

  3.10 新版功能.

`locale.``atof`(string, func=float)

  将一个字符串转换为数字，遵循 `LC_NUMERIC` 设置，通过在 string 上调用 `delocalize()` 的结果上调用 func 来实现。

`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()` 返回的消息可能会受到该类别的影响。

  这个值在不符合 POSIX 标准的操作系统上可能不可用，最主要是指 Windows。

`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

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

C 语言标准将区域定义为程序级别的属性，修改的代价可能相对较高。此外，有某些实现代码写得不好，频繁改变区域可能会导致内核崩溃。于是要想正确使用区域就变得有些痛苦。

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

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

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

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

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

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

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

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

## 访问消息目录

`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()`。对于这些应用程序，可能有必要绑定文本域，以便库可以准确找到其消息目录。