为什么LC_MESSSAGES需要在macOS自制bash上导出才能生效?

用户名

在macOS上,从homebrew安装bash时,我注意到该设置LC_MESSAGES似乎对当前shell的语言环境设置有一定影响,但是直到LC_MESSAGES导出消息,消息才真正改变

取消设置LANGLC_MESSAGES,我得到了预期的英语错误消息:

bash-4.4$ unset LANG LC_MESSAGES
bash-4.4$ if :;  fi
bash: syntax error near unexpected token `fi'

设置LC_MESSAGES为不正确的值会产生以下错误setlocale

bash-4.4$ LC_MESSAGES=foo
bash: warning: setlocale: LC_MESSAGES: cannot change locale (foo): No such file or directory

所以当我定型的时候有些改变LC_MESSAGES但是将其设置为合理的值无效:

bash-4.4$ LC_MESSAGES=ja_JP.UTF-8
bash-4.4$ if :;  fi
bash: syntax error near unexpected token `fi'

直到我将其导出:

bash-4.4$ export LC_MESSAGES
bash-4.4$ if :;  fi
bash: 予期しないトークン `fi' 周辺に構文エラーがあります

(所有LANG这些似乎也都适用。)

Bash手册中有关Bash变量的部分没有说明LC_MESSAGESLANG必须导出(并且那里列出的大多数其他变量也不必导出)。

为什么是这样?

斯蒂芬·查泽拉斯(Stephane Chazelas)

没错,分配LC_*外壳变量确实会导致使用相应变量的值bash调用setlocale()相应类别的POSIX ,而无论是否导出它们。LANG,它要求setlocale(LC_ALL, thevalue)遵循setlocale(LC_*)再次对所有的LC_*变量。对于LANGUAGE,它什么也没做。

现在,bash是GNU项目的外壳。对于文本的本地化,它使用GNU gettext(也称为)libintl它甚至附带了其自己的版本,该版本与源捆绑在一起,bash如果使用调用configure脚本,则可以将其编译到其中--with-included-gettext

gettext在每个语言的数据库中查找消息翻译。LC_MESSAGES尽管可以被$LANGUAGE环境变量覆盖,但是由类别值确定的是哪种语言

根据gettext文档,对的上一次调用setlocale()应该是确定类别值的调用,但是存在一些复杂性:

对于多线程应用程序,当前没有标准的API,gettext可用于检索该值bash不是一个多线程应用程序,但是即使setlocale(category, NULL)返回的结果也是实现定义的,实际上并不总是可用的

因此在实践中,gettext仅setlocale()在作为GNU libc的一部分或在libc是GNU libc的系统上构建时才用于检索语言名称(就像在GNU系统上使用bash一起构建的那样--with-included-gettext),因为它知道它可以依赖它。

在其他系统上,它用于getenv()确定语言环境,而与setlocale()先前的调用方式无关,这就是为什么您看到这种行为的原因。

导出这些变量很容易。有人可能会争辩说,如果不出口它们,它们无论如何都不是环境的一部分。POSIX对此并不十分清楚。另一种看待它的方式不是由bash而是由第三方机制完成转换,因此就像执行其他命令时一样,我们需要使用环境变量在两个软件之间(此处bashgettext传递语言环境信息

现在,在GNU系统上,情况实际上变得更糟。

如上所示,gettext包含在GNU libc中。$LANGUAGE优先于$LC_MESSAGE$LANGUAGE不是POSIX语言环境API的一部分,这是它的扩展。

因此,在GNU系统上,gettext将用于setlocale(LC_MESSAGES, NULL)获取LC_MESSAGES类别的名称,因为LANGUAGE它始终使用getenv()LANGUAGE而不是语言环境类别。

问题在于,bash将环境本身作为变量处理的一部分进行管理,与libc的environ[]数组断开连接它确实有自己的getenv()查询环境,但是它gettext是作为libc的一部分构建的,并且bash是动态链接的,它从libc中dgettext()调用的getenv(),因为这是libc中的内部调用,而不是libc的内部调用bash,所以会自动查询该版本的环境。仅从启动时获取$LANGUAGEbash

因此,在GNU系统上,除非bash已静态链接或使用构建,否则无论是否导出变量,对于所生成的消息--with-included-gettext,对的任何更改都$LANGUAGE将被忽略bash在其他系统上,这很好(只要$LANGUAGE导出即可),因为gettext不是libc的一部分,因此它确实调用bashgetenv()

在Debian上:

$ LANGUAGE=fr bash -c 'LANGUAGE=es; eval fi'
bash: eval: ligne 0: erreur de syntaxe près du symbole inattendu « fi »
bash: eval: ligne 0: `fi'

(消息法语,的值$LANGUAGE在时间bash被调用,而不是西班牙语)。

实际上,使用其他shell并没有更好的效果。

zsh是不是翻译成其他语言,但没有使用strerror()它确实使用gettext的GNU系统内部:

$ LANGUAGE=fr zsh -c 'LANGUAGE=es; true</x; LANGUAGE=en; true</a; true < /etc/shadow'
zsh:1: no existe el archivo o el directorio: /x
zsh:1: no existe el archivo o el directorio: /a
zsh:1: permission denied: /etc/shadow

该命令LANGUAGE=es很荣幸,但请查看ENOENT的第二条消息如何未以英语显示(大概是由gettext缓存;该缓存应该在$LANGUAGE更改时已失效,但事实并非如此)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

什么时候以及为什么我们需要在bash上使用“ wait”命令?

来自分类Dev

为什么apt-get clean需要重新启动才能生效

来自分类Dev

Yii2。为什么我需要上传文件两次才能生效?

来自分类Dev

我是否真的需要安装自制软件才能安装滑轨,为什么?

来自分类Dev

为什么需要在套接字上定义两次端点才能开始接收数据?

来自分类Dev

为什么我需要在Windows bash上用winpty作为前缀openssl?

来自分类Dev

为什么 Apache 需要停止和启动(而不是重新启动)才能使新的 PHP 版本生效?

来自分类Dev

为什么我们需要在Linux上挂载?

来自分类Dev

为什么ClassCleanup属性需要在静态方法上?

来自分类Dev

为什么我们需要在Linux上挂载?

来自分类Dev

为什么需要在实体类上放置@NamedQuery?

来自分类Dev

为什么我需要在资源上使用.close()

来自分类Dev

jQuery / JavaScript,为什么需要在$()中包装变量才能使用它们?

来自分类Dev

为什么我需要在Windows上格式化USB才能使用unetbootin

来自分类Dev

为什么这里需要在函数中具有if语句才能起作用?

来自分类Dev

为什么我需要在Windows上格式化USB才能使用unetbootin

来自分类Dev

为什么需要在父目录上具有执行权限才能重命名文件

来自分类Dev

为什么“需要认证才能...?”

来自分类Dev

为什么要在主线程上休眠才能运行Camel示例

来自分类Dev

为什么要在webpack-dev-server中同时需要内联和热标记才能启用热重装

来自分类Dev

为什么我需要在程序的逻辑内枚举列表才能使其在这种情况下起作用?

来自分类Dev

为什么要在webpack-dev-server中同时需要内联和热标记才能启用热重装

来自分类Dev

为什么我需要在 UITableView 中的单元格上点击两次才能显示警报

来自分类Dev

我需要在 Proguard 中保留什么才能运行 ObjectDB?

来自分类Dev

为什么需要在结构中填充?

来自分类Dev

为什么需要配对才能插入地图?

来自分类Dev

为什么需要UAC才能更改文件?

来自分类Dev

为什么需要配对才能插入地图?

来自分类Dev

sudoers 文件是否需要重启才能生效

Related 相关文章

  1. 1

    什么时候以及为什么我们需要在bash上使用“ wait”命令?

  2. 2

    为什么apt-get clean需要重新启动才能生效

  3. 3

    Yii2。为什么我需要上传文件两次才能生效?

  4. 4

    我是否真的需要安装自制软件才能安装滑轨,为什么?

  5. 5

    为什么需要在套接字上定义两次端点才能开始接收数据?

  6. 6

    为什么我需要在Windows bash上用winpty作为前缀openssl?

  7. 7

    为什么 Apache 需要停止和启动(而不是重新启动)才能使新的 PHP 版本生效?

  8. 8

    为什么我们需要在Linux上挂载?

  9. 9

    为什么ClassCleanup属性需要在静态方法上?

  10. 10

    为什么我们需要在Linux上挂载?

  11. 11

    为什么需要在实体类上放置@NamedQuery?

  12. 12

    为什么我需要在资源上使用.close()

  13. 13

    jQuery / JavaScript,为什么需要在$()中包装变量才能使用它们?

  14. 14

    为什么我需要在Windows上格式化USB才能使用unetbootin

  15. 15

    为什么这里需要在函数中具有if语句才能起作用?

  16. 16

    为什么我需要在Windows上格式化USB才能使用unetbootin

  17. 17

    为什么需要在父目录上具有执行权限才能重命名文件

  18. 18

    为什么“需要认证才能...?”

  19. 19

    为什么要在主线程上休眠才能运行Camel示例

  20. 20

    为什么要在webpack-dev-server中同时需要内联和热标记才能启用热重装

  21. 21

    为什么我需要在程序的逻辑内枚举列表才能使其在这种情况下起作用?

  22. 22

    为什么要在webpack-dev-server中同时需要内联和热标记才能启用热重装

  23. 23

    为什么我需要在 UITableView 中的单元格上点击两次才能显示警报

  24. 24

    我需要在 Proguard 中保留什么才能运行 ObjectDB?

  25. 25

    为什么需要在结构中填充?

  26. 26

    为什么需要配对才能插入地图?

  27. 27

    为什么需要UAC才能更改文件?

  28. 28

    为什么需要配对才能插入地图?

  29. 29

    sudoers 文件是否需要重启才能生效

热门标签

归档