Rails 5 - Umlaute 和参数化方法有问题

Rails 5 - Problem with Umlaute and parameterize method

我在 Rails 5.2.3 和 Ruby 2.5.1 上工作。在某些时候,我发现了一个问题,我希望我的字符串数组常量包含一些字符串,但它没有。原来问题与德语元音变音字符 (öäü) 有关。

所以我定义了如下常量:

# coding: utf-8
# frozen_string_literal: true
class MyClass
  module MyModule
    MY_CONSTANT = [
      'Breite in mm',
      'Höhe in mm',
      'Länge in mm'
    ].map(&:parameterize).freeze
  end
end

我希望常量看起来像 ["breite-in-mm", "hoehe-in-mm", "laenge-in-mm"]

而是存储为 ["breite-in-mm", "hohe-in-mm", "lange-in-mm"]。您会看到,“ö”已被转换为 "o" 而不是 "oe"。与“ä”相同。现在是 "a",而不是 "ae"。

在生产环境、RSpec 测试中,甚至在我启动 Rails 控制台并调用此常量时,它都以这种方式工作。但是当我使用完全相同的代码从 Rails 控制台定义一个新常量时,字符串被成功转换为我所期望的,即 ["breite-in-mm", "hoehe-in-mm", "laenge-in-mm"]

我可以轻松摆脱这种 parameterize 方法,只需在需要时输入字符串即可。也许我将不得不这样做。但我真的很好奇为什么会发生这一切,我自己也找不到答案。

非常感谢您的任何想法。

Rails 中的 parameterize 方法(通过使用 ActiveSupport::Inflector#transliterate)是区域设置感知的。因此,它使用依赖于语言环境的规则将字符(例如变音符号)音译为 ASCII 字符。

当您的应用程序处理请求时(或至少在启动后处理一次),您通常会设置 I18n 语言环境,例如I18n.locale = :de 用于单个请求或 I18n.default_locale = :de 用于整个应用程序。之后,Rails(即 i18n gem)默认使用此语言环境作为其音译规则。

最初设置常量时,可能尚未设置此默认语言环境。因此,i18n gem 不了解德语音译规则,仅使用基本的 Unicode 规范化规则。

作为解决方法,您可以将要使用的所需区域设置传递给参数化方法,如

MY_CONSTANT = [
  'Breite in mm',
  'Höhe in mm',
  'Länge in mm'
].map { |const| const.parameterize(locale: :de).freeze }.freeze

或者您也可以在执行代码之前设置默认 i18n 语言环境(例如,在 config/initializers 中的文件中,具体取决于您初始化常量的位置):

I18n.default_locale = :de

谢谢,Holger 非常感谢您的回答。它似乎是正确的,只是它只适用于 Rails 6.0.0。所以我要 post 我在我的项目中使用的 Rails 5.2.3 版本。

不幸的是 Rails 5 parameterize 方法还不接受 locale 参数。这仅在 Rails 6.

中才有可能

但是,正如 Holger Just 的回答中提到的,parameterize 方法依赖于 transliterate 方法,该方法确实使用当前语言环境并根据它转换字符串。

请参阅 Rails 5.2.3 文档和这些方法的来源: https://api.rubyonrails.org/v5.2.3/classes/ActiveSupport/Inflector.html#method-i-parameterize https://api.rubyonrails.org/v5.2.3/classes/ActiveSupport/Inflector.html#method-i-transliterate

所以我无法将语言环境直接传递给 parameterize 方法。然后我应该在定义常量之前设置语言环境。

application.rb 文件中设置 I18n.default_locale = :de 没有帮助。我已经有了,不管怎样,字符串都被音译了。

最终有用的是手动设置 I18n.locale = :de。多亏了这个,我得到了正确参数化的字符串,而没有对 MyConstant 定义进行任何更改。