在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.4
和Rails 5.2.1
中。
什么会导致此编码问题,以及如何消除它?
编辑:添加其他详细信息
我使用RubyMine 2018.2
开发。我的Rails服务器在WSL (Windows Subsystem for Linux)
和Ubuntu 16
下运行。我从Windows
端从RubyMine运行我的rails服务器。使用的rails SDK
是一个Linux
。 rails server
在Linux
端运行。
我的问题的源头是显示HTTP请求响应中设置的Flash消息时,浏览器中的编码问题。按照说明计算这些Flash消息,即:I18n.t 'programs.update.program_saved'
。
当我从RubyMine或直接从Linux终端启动rails服务器时,问题是相同的。
要进行调查,我想调试和使用RubyMine控制台。从RubyMine调试器控制台执行此命令时,仍然存在编码问题:I18n.t 'programs.update.program_saved'
。从rails console
或Linux
中的Windows
(在RubyMine
中,rails控制台在Linux
端执行)上,我没有编码问题。>
此外,在heroku实例上运行应用程序时,该问题仍然存在,因此我想知道这是否与我的本地配置有关。
答案 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)")
我可以想到出现问题的两种可能性。
运行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?"可能会有帮助。
是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中,请查看/编码选项。
最后,您需要使用与持久化内容相同的编码来查看内容。