控制器I18n编码

时间:2018-11-02 14:53:43

标签: ruby-on-rails encoding rails-i18n

在Rails控制器中,我想计算要发送到前端的i18n消息。我进行如下操作:

flash[:notice] = I18n.t 'programs.update.program_saved'

在我的翻译文件(fr.yml)中,翻译为以下内容:“ 编程sauvegardé”。

在此行上设置断点,然后在控制台中键入它时,出现编码问题:

0> I18n.t 'programs.update.program_saved'
=> "Programme sauvegardé"

我已经实现了AJAX pattern来处理Flash消息,并且在正面,我可以看到相同的编码问题。

除此之外,当我在rails console中键入相同的内容时,没有任何编码问题。

我在Ruby 2.4.4Rails 5.2.1中。

什么会导致此编码问题,以及如何消除它?

编辑:添加其他详细信息

我使用RubyMine 2018.2开发。我的Rails服务器在WSL (Windows Subsystem for Linux)Ubuntu 16下运行。我从Windows端从RubyMine运行我的rails服务器。使用的rails SDK是一个Linuxrails serverLinux端运行。

我的问题的源头是显示HTTP请求响应中设置的Flash消息时,浏览器中的编码问题。按照说明计算这些Flash消息,即:I18n.t 'programs.update.program_saved'

当我从RubyMine或直接从Linux终端启动rails服务器时,问题是相同的。

要进行调查,我想调试和使用RubyMine控制台。从RubyMine调试器控制台执行此命令时,仍然存在编码问题:I18n.t 'programs.update.program_saved'。从rails consoleLinux中的Windows(在RubyMine中,rails控制台在Linux端执行)上,我没有编码问题。

此外,在heroku实例上运行应用程序时,该问题仍然存在,因此我想知道这是否与我的本地配置有关。

2 个答案:

答案 0 :(得分:1)

很明显,尽管实际上它是“ UTF-8”,但您的字符串仍被解释为“ ISO-8859-1”。 您可以在irb或Rails控制台中使用以下代码片段检查事实:

s=[0x64,0xc3,0xa9].pack('c*')  # => "d\xC3\xA9" ("dé" if UTF-8)
s.encoding    # => #<Encoding:ASCII-8BIT>
s.encode "UTF-8", "UTF-8"      # => "dé"  ("de'")
s.encode "UTF-8", "ISO-8859-1" # => "dé" ("d~A(c)")

我可以想到出现问题的两种可能性。

案例1

运行Rails控制台的终端无法解释UTF-8字符串或设置错误。

尝试以下代码段(nb。即使翻译未定义,也可以由任何人运行):

s2 = I18n.t('programs.update.program_saved', :default => nil)
s2 ||= [0x64,0xc3,0xa9].pack('c*').encode("UTF-8", "UTF-8")  # => "dé"  ("de'")
p s2[-2,2].bytes  # => [100, 195, 169]  if the object is in UTF-8
                  # => [100, 233]       if the object is in ISO-8859-1

,您会看到String对象的(内部)编码如何。 如果它是[100, 195, 169],则编码为UTF-8,因此Ruby和Rails都将转换后的String对象正确地视为UTF-8,因此问题出在您的终端上。您的终端错误地将它从Rails接收到的字节字符串[100, 195, 169]解释为ISO-8859-1,并选择要相应显示的字符和字体。

在终端的Rails控制台中,您可以尝试此操作;如果终端兼容UTF-8,它应该正确显示字符:

[0x64,0xc3,0xa9].pack('c*').force_encoding('UTF-8')
  # => "dé" ("de'") should be displayed.

破解您的终端确实能够显示UTF-8字符串(大多数现代终端应该能够,但旧终端则不能)。 另外,请检查您的终端设置。这个answer to "How to input Unicode character in Rails console?"可能会有帮助。

案例2

是Ruby将输入字符串解释为“ ISO-8859-1”并将其内部转换为“ UTF-8”(尽管默认情况下不应发生)。 在这种情况下,您的yml文件中可能包含一些看起来像“ ISO-8859-1”的字符;然后Rails可能会将整个文件解释为“ ISO-8859-1”(尽管可能性很小)。

您可以检查读取的文件(config/locales/fr.yml)是否确实位于UTF-8中,如下所示:

fn = 'config/locales/fr.yml'
IO.binread(fn).force_encoding('UTF-8').valid_encoding?  # => should be true
IO.binread(fn).force_encoding('ISO-8859-1').valid_encoding?  # => false

不幸的是,这里存在一些缺陷。某些UTF-8字符可以合法地解释为ISO-8859-1,在这种情况下,代码(Rails)对其解释的方式可能会有所不同。如果您怀疑是这种情况,可以查看上述命令的输出,例如IO.binread(fn).force_encoding('UTF-8'),看看是否每个字符都符合预期。

如果文件包含一些非UTF-8字符,请对其进行修复,希望一切都很好。

或者,在您的特定情况下,您可以将其修复为像这样的拙劣工作

I18n.t('programs.update.program_saved').encode('UTF-8', 'ISO-8859-1')

注意

只要您想将Rails设置为UTF-8(强烈建议),请确保您应用的默认编码为UTF-8。通过

签出
MyApp::Application.config.encoding  # => #<Encoding:UTF-8>

(参考:Configuring Rails Applications

此外,如果您使用的是Heroku,请将默认字符集设置为UTF-8。参见answer to "Set UTF-8 as default string encoding in Heroku"


请注意,2018年11月5日进行了重大更新以添加案例1。

答案 1 :(得分:0)

请确保在utf-8中打开fr.yml文件,以便将写入的内容正确保存在utf-8中。可能是您的浏览器正在使用的编码。

您可以转到Linux控制台,并通过查找LANG变量的值来查找当前配置。例如,我有LANG="ca_ES.UTF-8"。也许您还可以检查终端窗口的编码属性。

还要检查您正在查看网站的编码。例如,在Firefox中,请查看/编码选项。

最后,您需要使用与持久化内容相同的编码来查看内容。