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

源代码： Lib/locale.py

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

`locale` 模块是在 `_locale` 模块之上实现的，后者又会在可能的情况下使用 ANSI C 语言区域实现。

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

exception locale.Error

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

locale.setlocale(category, locale=None)

  如果给定了 locale 而不是 `None`，`setlocale()` 会为 category 修改语言区域设置。 可用的类别在下面的数据描述中列出。 locale 可以是一个 字符串，或是一个表示语言代码和编码格式的字符串对。 空字符串表示用户的默认设置。 如果语言区域修改失败，会引发 `Error` 异常。 如果成功，则返回新的语言区域设置。

  如果 locale 是一个元组，则会通过区域设置别名引擎将其转换为区域设置名称。其中语言代码的格式与 区域设置名称 相同，但不包含编码信息和以 @ 开头的修饰符。语言代码和编码都可以为 `None`。

  如果省略 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 的格式表示时间。

  locale.DAY_1
  locale.DAY_2
  locale.DAY_3
  locale.DAY_4
  locale.DAY_5
  locale.DAY_6
  locale.DAY_7

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

    备注

    这里遵循美国惯例，即 `DAY_1` 是星期天，而不是国际惯例（ISO 8601），即星期一是一周的第一天。

  locale.ABDAY_1
  locale.ABDAY_2
  locale.ABDAY_3
  locale.ABDAY_4
  locale.ABDAY_5
  locale.ABDAY_6
  locale.ABDAY_7

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

  locale.MON_1
  locale.MON_2
  locale.MON_3
  locale.MON_4
  locale.MON_5
  locale.MON_6
  locale.MON_7
  locale.MON_8
  locale.MON_9
  locale.MON_10
  locale.MON_11
  locale.MON_12

    获取第 n 个月的名称。

  locale.ABMON_1
  locale.ABMON_2
  locale.ABMON_3
  locale.ABMON_4
  locale.ABMON_5
  locale.ABMON_6
  locale.ABMON_7
  locale.ABMON_8
  locale.ABMON_9
  locale.ABMON_10
  locale.ABMON_11
  locale.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()` 函数使用此信息。 被返回字符串的格式是在 The Open Group Base Specifications Issue 8, paragraph 7.3.5.2 LC_TIME C-Language Access 中指明的。

  locale.ERA_D_T_FMT

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

  locale.ERA_D_FMT

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

  locale.ERA_T_FMT

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

  locale.ALT_DIGITS

    获取一个由至多 100 个以分号分隔的用于通过特定语言区域专属的方式表示数值 0 到 99 的符号名称组成的字符串。 在大多数语言区域中这都是一个空字符串。

  如果语言区域不同并且结果字符串为非 ASCII 的则该函数会临时性地将 `LC_CTYPE` 语言区域设为决定所请求值 (`LC_TIME`, `LC_NUMERIC`, `LC_MONETARY` or `LC_MESSAGES`) 的类别的语言区域。 这个临时性修改会影响其他的线程。

  在 3.14 版本发生变更: 现在该函数在某些情况下会临时性地设置 `LC_CTYPE` 语言区域。

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'`。

  语言代码的格式与 区域设置名称 相同，但不包含编码和 `@` 修饰符。如果无法确定其值，语言代码和编码可以为 `None`。"C" 区域设置表示为 `(None, None)`。

  Deprecated since version 3.11, will be removed in version 3.15.

locale.getlocale(category=LC_CTYPE)

  返回指定区域设置类别的当前设置，结果以包含语言代码和编码格式的元组形式呈现。其中 category 可以是除 `LC_ALL` 外的任意 `LC_*` 常量值，默认使用 `LC_CTYPE`。

  语言代码的格式与 区域设置名称 相同，但不包含编码和 `@` 修饰符。如果无法确定其值，语言代码和编码可以为 `None`。"C" 区域设置表示为 `(None, None)`。

locale.getpreferredencoding(do_setlocale=True)

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

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

  在 Android 上或者如果启用了 Python UTF-8 模式，则将始终返回 `'utf-8'`，locale encoding 和 do_setlocale 参数将被忽略。

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

  在 3.7 版本发生变更: 目前在 Android 上或者如果启用了 Python UTF-8 模式 此函数将总是返回 `"utf-8"`。

locale.getencoding()

  获取当前的 locale encoding:

  - 在 Android 和 VxWorks 上，将返回 `"utf-8"`。

  - 在 Unix 上，将返回当前, return the encoding of the current `LC_CTYPE` 语言区域的编码格式。 如果 `nl_langinfo(CODESET)` 返回空字符串则将返回 `"utf-8"`: 举例来说，如果当前 LC_CTYPE 语言区域不受支持的时候。

  - 在 Windows 上，返回 ANSI 代码页。

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

  此函数类似于 `getpreferredencoding(False)`，区别是此函数会忽略 Python UTF-8 模式。

  Added in version 3.11.

locale.normalize(localename)

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

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

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.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` 的设置，将字符串转换为标准化的数字字符串。

  Added in version 3.5.

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

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

  Added in version 3.10.

locale.atof(string, func=float)

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

locale.atoi(string)

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

locale.LC_CTYPE

  字符类型函数的语言区域类别。 最重要的是，该类别定义了文件编码格式，即如何将字节解读为 Unicode 码位点。 请参阅 PEP 538 和 PEP 540 了解如何将该变量自动强制转换为 `C.UTF-8` 以避免容器中的无效设置或通过远程 SSH 连接传递的不兼容设置所造成的问题。

  Python 在内部并不使用来自 `ctype.h` 的依赖于语言区域的字符转换函数。 相反，内部 `pyctype.h` 提供了不依赖于语言区域的等价物如 `Py_TOLOWER`。

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_string()`, `atoi()`, `atof()` 和 `str()` 等函数会受到该类别的影响。 其他所有数字格式化操作将不受影响。

locale.LC_ALL

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

locale.CHAR_MAX

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

示例：

    >>> import locale
    >>> loc = locale.getlocale()  # 获取当前语言区域
    # 使用德语的语言区域；在具体平台上名称可能不同
    >>> locale.setlocale(locale.LC_ALL, 'de_DE')
    >>> locale.strcoll('f\xe4n', 'foo')  # 比较一个包含变音的字符串
    >>> locale.setlocale(locale.LC_ALL, '')   # 使用用户首选的语言区域
    >>> locale.setlocale(locale.LC_ALL, 'C')  # 使用默认的语言区域 (C)
    >>> locale.setlocale(locale.LC_ALL, loc)  # 恢复已保存的语言区域

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

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

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

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

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

根据语言区域执行数字运算的唯一方式就是使用本模块所定义的特殊函数: `atof()`, `atoi()`, `format_string()`, `str()`。

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

## 区域设置名称

区域名称的格式取决于平台，且支持的区域设置集合可能因系统配置而异。

在 Posix 平台上，其格式通常为 [1]:

      language ["_" territory] ["." charset] ["@" modifier]

其中 language 是来自 ISO 639 的二或三字母语言代码，territory 是来自 ISO 3166 的二字母国家或地区代码，charset 是语言区域编码格式，而 modifier 是脚本名称、语言子标签、排序顺序标识符或其他语言区域修饰符（例如 "latin", "valencia", "stroke" 和 "euro"）。

在 Windows 系统上，支持多种格式。[2] [3] IETF BCP 47 标准的子集标签：

      language ["-" script] ["-" territory] ["." charset]
      language ["-" script] "-" territory "-" modifier

其中，language 和 territory 的含义与 POSIX 系统中的定义相同；script 是来自 ISO 15924 标准的四字母书写系统代码；而 modifier 可以是语言子标签、排序顺序标识符或自定义修饰符（例如：“valencia”、“stroke”或“x-python”）。系统同时支持连字符（`'-'`）和下划线（`'_'`）作为分隔符。对于 BCP 47 标签，仅允许使用 UTF-8 编码格式。

Windows 还支持以下格式的区域设置名称：

      language ["_" territory] ["." charset]

其中 language 和 territory 使用完整名称（如 "English" 和 "United States"），而 charset 可以是代码页编号（例如 "1252"）或 UTF-8。此格式仅支持下划线作为分隔符。

所有平台均支持 "C" 区域设置。

[1]

IEEE Std 1003.1-2024; 8.2 国际化变量

[2]

UCRT 区域名称、语言和国家/地区字符串

[3]

区域设置名称

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

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

当 Python 代码使用 `locale` 模块来修改语言区域时，这也会影响到嵌入的应用程序。 如果嵌入的应用程序不希望发生这种情况，它应当从 `config.c` 文件的内置模块表中移除 `_locale` 扩展模块（所有工作都是由它完成的），以确保 `_locale` 模块不能作为共享库来访问。

## 访问消息目录

locale.gettext(msg)

locale.dgettext(domain, msg)

locale.dcgettext(domain, msg, category)

locale.textdomain(domain)

locale.bindtextdomain(domain, dir)

locale.bind_textdomain_codeset(domain, codeset)

locale 模块在提供了 C 库的 gettext 接口的系统上对外公开该接口。 它由 `gettext()`, `dgettext()`, `dcgettext()`, `textdomain()`, `bindtextdomain()` 和 `bind_textdomain_codeset()` 等函数组成。 它们与 `gettext` 模块中的同名函数类似，但使用了 C 库的二进制格式来表示消息目录，并使用 C 库的搜索算法来查找消息目录。

Python 应用程序通常不需要唤起这些函数，而应当改用 `gettext`。 这条规则的一个已知例外是与附加 C 库相链接的应用程序，它们会在内部唤起 C 函数 `gettext` 或 `dcgettext`。 对于这些应用程序，可能有必要绑定文本域，以便库能够正确地找到它们的消息目录。