Ruby-on-rails rails i18n - 翻译带有链接的文本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2543936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
rails i18n - translating text with links inside
提问by kikito
I'd like to i18n a text that looks like this:
我想输入一个看起来像这样的文本:
Already signed up? Log in!
已经注册?登录!
Note that there is a link on the text. On this example it points to google - in reality it will point to my app's log_in_path.
请注意,文本上有一个链接。在这个例子中,它指向 google - 实际上它会指向我的应用程序的log_in_path.
I've found two ways of doing this, but none of them looks "right".
我找到了两种方法来做到这一点,但它们看起来都不“正确”。
The first way I know involves having this my en.yml:
我知道的第一种方法是让我的en.yml:
log_in_message: "Already signed up? <a href='{{url}}'>Log in!</a>"
And in my view:
在我看来:
<p> <%= t('log_in_message', :url => login_path) %> </p>
This works, but having the <a href=...</a>part on the en.ymldoesn't look very clean to me.
这有效,但对我来说,这<a href=...</a>部分en.yml看起来不太干净。
The other option I know is using localized views- login.en.html.erb, and login.es.html.erb.
我知道的另一个选项是使用本地化视图-login.en.html.erb和login.es.html.erb.
This also doesn't feel right since the only different line would be the aforementioned one; the rest of the view (~30 lines) would be repeated for all views. It would not be very DRY.
这也感觉不对,因为唯一不同的是前面提到的那一行;视图的其余部分(约 30 行)将针对所有视图重复。它不会很干。
I guess I could use "localized partials" but that seems too cumberstone; I think I prefer the first option to having so many tiny view files.
我想我可以使用“本地化部分”,但这似乎太麻烦了;我想我更喜欢第一个选项而不是拥有这么多小的视图文件。
So my question is: is there a "proper" way to implement this?
所以我的问题是:是否有“正确”的方法来实现这一点?
回答by Simone Carletti
en.yml
编码
log_in_message_html: "This is a text, with a %{href} inside."
log_in_href: "link"
login.html.erb
登录.html.erb
<p> <%= t("log_in_message_html", href: link_to(t("log_in_href"), login_path)) %> </p>
回答by holli
Separating text and link in locale.yml file works for a while but with longer text those are hard to translate and maintain as the link is in separate translation-item (as in Simones answer). If you start having many strings/translations with links you can dry it a bit more.
在 locale.yml 文件中分离文本和链接可以使用一段时间,但对于较长的文本,由于链接位于单独的翻译项中(如 Simones 的回答),这些文本很难翻译和维护。如果你开始有很多带有链接的字符串/翻译,你可以再干燥一点。
I made one helper in my application_helper.rb:
我在 application_helper.rb 中创建了一个助手:
# Converts
# "string with __link__ in the middle." to
# "string with #{link_to('link', link_url, link_options)} in the middle."
def string_with_link(str, link_url, link_options = {})
match = str.match(/__([^_]{2,30})__/)
if !match.blank?
raw($` + link_to(, link_url, link_options) + $')
else
raise "string_with_link: No place for __link__ given in #{str}" if Rails.env.test?
nil
end
end
In my en.yml:
在我的 en.yml 中:
log_in_message: "Already signed up? __Log in!__"
And in my views:
在我看来:
<p><%= string_with_link(t('.log_in_message'), login_path) %></p>
This way it's easier to translate messages as also the link text is clearly defined in the locale.yml-files.
通过这种方式,可以更轻松地翻译消息,因为在 locale.yml 文件中也清楚地定义了链接文本。
回答by iGEL
I took hollis solution and made a gem called itout of it. Let's look at an example:
我服用了 hollis 溶液并用它制成了一颗宝石it。让我们看一个例子:
log_in_message: "Already signed up? %{login:Log in!}"
And then
进而
<p><%=t_link "log_in_message", :login => login_path %></p>
For more details, see https://github.com/iGEL/it.
有关更多详细信息,请参阅https://github.com/iGEL/it。
回答by Emu
In en.yml
在en.yml
registration:
terms:
text: "I do agree with the terms and conditions: %{gtc} / %{stc}"
gtc: "GTC"
stc: "STC"
In de.yml
在de.yml
registration:
terms:
text: "Ich stimme den Gesch?fts- und Nutzungsbedingungen zu: %{gtc} / %{stc}"
gtc: "AGB"
stc: "ANB"
in new.html.erb[assumed]
在new.html.erb[假定]
<%= t(
'registration.terms.text',
gtc: link_to(t('registration.terms.gtc'), terms_and_conditions_home_index_url + "?tab=gtc"),
stc: link_to(t('registration.terms.stc'), terms_and_conditions_home_index_url + "?tab=stc")
).html_safe %>
回答by emrass
Thank you very much, holli, for sharing this approach. It works like a charm for me. Would vote you up if I could, but this is my first post so I'm lacking the proper reputation ... As an additional piece to the puzzle: The problem I realized with your approach is that it still won't work from inside the controller. I did some research and combined your approach with the one from Glenn on rubypond.
非常感谢你,holli,分享这种方法。它对我来说就像一种魅力。如果可以,我会投票给你,但这是我的第一篇文章,所以我缺乏适当的声誉......作为拼图的另一个部分:我意识到你的方法的问题是它仍然无法从内部工作控制器。我做了一些研究,并将您的方法与Glenn 在 rubypond 上的方法相结合。
Here is what I came up with:
这是我想出的:
View helper, e.g. application_helper.rb
查看助手,例如 application_helper.rb
def render_flash_messages
messages = flash.collect do |key, value|
content_tag(:div, flash_message_with_link(key, value), :class => "flash #{key}") unless key.to_s =~ /_link$/i
end
messages.join.html_safe
end
def flash_message_with_link(key, value)
link = flash["#{key}_link".to_sym]
link.nil? ? value : string_with_link(value, link).html_safe
end
# Converts
# "string with __link__ in the middle." to
# "string with #{link_to('link', link_url, link_options)} in the middle."
# --> see http://stackoverflow.com/questions/2543936/rails-i18n-translating-text-with-links-inside (holli)
def string_with_link(str, link_url, link_options = {})
match = str.match(/__([^_]{2,30})__/)
if !match.blank?
$` + link_to(, link_url, link_options) + $'
else
raise "string_with_link: No place for __link__ given in #{str}" if Rails.env.test?
nil
end
end
In the controller:
在控制器中:
flash.now[:alert] = t("path.to.translation")
flash.now[:alert_link] = here_comes_the_link_path # or _url
In the locale.yml:
在 locale.yml 中:
path:
to:
translation: "string with __link__ in the middle"
In the view:
在视图中:
<%= render_flash_messages %>
Hope this post earns me the reputation to vote you up, holli :) Any feedback is welcome.
希望这篇文章能让我赢得投票给你的声誉,holli :) 欢迎任何反馈。
回答by Jaime Cham
We had the following:
我们有以下内容:
module I18nHelpers
def translate key, options={}, &block
s = super key, options # Default translation
if block_given?
String.new(ERB::Util.html_escape(s)).gsub(/%\|([^\|]*)\|/){
capture(, &block) # Pass in what's between the markers
}.html_safe
else
s
end
end
alias :t :translate
end
or more explicitly:
或更明确地:
module I18nHelpers
# Allows an I18n to include the special %|something| marker.
# "something" will then be passed in to the given block, which
# can generate whatever HTML is needed.
#
# Normal and _html keys are supported.
#
# Multiples are ok
#
# mykey: "Click %|here| and %|there|"
#
# Nesting should work too.
#
def translate key, options={}, &block
s = super key, options # Default translation
if block_given?
# Escape if not already raw HTML (html_escape won't escape if already html_safe)
s = ERB::Util.html_escape(s)
# ActiveSupport::SafeBuffer#gsub broken, so convert to String.
# See https://github.com/rails/rails/issues/1555
s = String.new(s)
# Find the %|| pattern to substitute, then replace it with the block capture
s = s.gsub /%\|([^\|]*)\|/ do
capture(, &block) # Pass in what's between the markers
end
# Mark as html_safe going out
s = s.html_safe
end
s
end
alias :t :translate
end
then in ApplicationController.rb just
然后在 ApplicationController.rb 中
class ApplicationController < ActionController::Base
helper I18nHelpers
Given a key in the en.ymlfile like
给定en.yml文件中的一个键,如
mykey: "Click %|here|!"
can be used in ERB as
可以在 ERB 中用作
<%= t '.mykey' do |text| %>
<%= link_to text, 'http://foo.com' %>
<% end %>
should generate
应该产生
Click <a href="http://foo.com">here</a>!
回答by zelanix
I wanted a bit more flexibility than just adding links to flash messages from YAML files (for example the logged in username etc.) so instead I wanted to use ERB notation in the string.
我想要更多的灵活性,而不仅仅是从 YAML 文件(例如登录的用户名等)添加到 Flash 消息的链接,所以我想在字符串中使用 ERB 表示法。
As I am using bootstrap_flashso I modified the helper code as follows to decode the ERB strings before displaying:
由于我正在使用,bootstrap_flash因此我修改了帮助程序代码,如下所示,以便在显示之前解码 ERB 字符串:
require 'erb'
module BootstrapFlashHelper
ALERT_TYPES = [:error, :info, :success, :warning] unless const_defined?(:ALERT_TYPES)
def bootstrap_flash
flash_messages = []
flash.each do |type, message|
# Skip empty messages, e.g. for devise messages set to nothing in a locale file.
next if message.blank?
type = type.to_sym
type = :success if type == :notice
type = :error if type == :alert
next unless ALERT_TYPES.include?(type)
Array(message).each do |msg|
begin
msg = ERB.new(msg).result(binding) if msg
rescue Exception=>e
puts e.message
puts e.backtrace
end
text = content_tag(:div,
content_tag(:button, raw("×"), :class => "close", "data-dismiss" => "alert") +
msg.html_safe, :class => "alert fade in alert-#{type}")
flash_messages << text if msg
end
end
flash_messages.join("\n").html_safe
end
end
It is then possible to use strings like the following (using devise):
然后就可以使用如下字符串(使用 devise):
signed_in: "Welcome back <%= current_user.first_name %>! <%= link_to \"Click here\", account_path %> for your account."
This may not work for all situations and there may be an argument that code and string definitions should not be mixed (especially from a DRY perspective), but this seems to work well for me. The code should be adaptable for many other situations, the important bits being the following:
这可能不适用于所有情况,并且可能有人认为不应混合代码和字符串定义(尤其是从 DRY 的角度来看),但这对我来说似乎很有效。该代码应该适用于许多其他情况,重要的部分如下:
require 'erb'
....
begin
msg = ERB.new(msg).result(binding) if msg
rescue Exception=>e
puts e.message
puts e.backtrace
end
回答by Sankalp Singha
I think a simple way to do this is by simply doing :
我认为一个简单的方法是简单地做:
<%= link_to some_path do %>
<%= t '.some_locale_key' %>
<% end %>
回答by alex.zherdev
Why not use the first way, but splitting it up like
为什么不使用第一种方式,而是将其拆分为
log_in_message: Already signed up?
log_in_link_text: Log in!
And then
进而
<p> <%= t('log_in_message') %> <%= link_to t('log_in_link_text'), login_path %> </p>

