2010-03-30 65 views
79

链接翻译文本,我想国际化,看起来像这样的文字:导轨国际化 - 里面

已经签约了? Log in!

请注意,文本上有一个链接。在这个例子中,它指向谷歌 - 实际上它会指向我的应用程序的log_in_path

我发现有两种方法可以做到这一点,但没有一个看起来“正确”。

我知道的第一方式包括有这个我en.yml

log_in_message: "Already signed up? <a href='{{url}}'>Log in!</a>" 

在我看来:

<p> <%= t('log_in_message', :url => login_path) %> </p> 

工作,但其对en.yml<a href=...</a>部分不看起来对我来说很干净。

我知道的另一个选择是使用localized views - login.en.html.erblogin.es.html.erb

这也不觉得正确,因为唯一不同的路线是上述路线;其余的视图(~30行)将重复所有视图。它不会很干。

我想我可以使用“局部化的部分”,但似乎太笨重;我认为我更喜欢有这么多小视图文件的第一个选项。

所以我的问题是:是否有一个“适当”的方式来实现这一点?

+0

这个是什么? http://stackoverflow.com/questions/12334183/rails-i18n-better-way-of-interpolating-links – 2012-09-19 14:45:32

+0

@Wuggy Foofie你应该没有重复的问题。 Simone的答案比你得到的答案要好。 – kikito 2012-09-19 15:03:27

回答

152
log_in_message_html: "This is a text, with a %{href} inside." 
log_in_href: "link" 

<p> <%= t("log_in_message_html", :href => link_to(t("log_in_href"), login_path)) %> </p> 
+61

在Rails 3中,这个语法在YAML转换字符串中变成了'%{href}'。另外,因为输出会自动转义,所以您需要明确指定'raw'或'.html_safe',或者使用'_html'后缀您的翻译键,如'login_message_html'中所示,并且转义会自动跳过。 – coreyward 2011-06-09 00:16:31

+15

以防万一,如果它不明显(对于那些懒得检查编辑日志)..上面的[答案](http://stackoverflow.com/a/2544107/766570)已被编辑为包含@核心的评论。 – abbood 2013-12-09 06:35:51

+1

如果您在链接文本中有多于一个单词,那么将会产生奇怪的翻译。例如“我们有一个惊人的offering of assorted things,你可以买到,你把这些东西发给翻译,你可能会得到两个措辞,如”我们有一个惊人的 whole bunch of items,你可以购买“在其他语言。 – trcarden 2014-12-10 16:48:48

-4

为什么不使用第一种方式,但分裂它像

log_in_message: Already signed up? 
log_in_link_text: Log in! 

然后

<p> <%= t('log_in_message') %> <%= link_to t('log_in_link_text'), login_path %> </p> 
+0

对不起,此解决方案不起作用。请记住,我想将文本翻译成其他语言。这意味着在某些时候,“链接”可能在文本的开头或中间。您的解决方案强制链接到最后(不好翻译)。 – kikito 2010-03-30 09:44:50

11

分离文本和链接locale.yml文件工作了一段时间,但与较长的文本难以翻译和维护,因为链接在单独的翻译项目中(如在Simone答案中)。如果你开始有很多字符串/带链接的翻译,你可以多干一点。

# 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($1, link_url, link_options) + $') 
    else 
    raise "string_with_link: No place for __link__ given in #{str}" if Rails.env.test? 
    nil 
    end 
end 

在我en.yml:

log_in_message: "Already signed up? __Log in!__" 

在我的观点:

<p><%= string_with_link(t('.log_in_message'), login_path) %></p> 

这种方式更容易

我在application_helper.rb做一个帮手来翻译消息,因为链接文本在locale.yml文件中明确定义。

+4

伟大的解决方案。我把它放到一个Gem中,它可以让你定义链接'这是一个%{链接:链接到Google}'。它允许您在单个字符串中有多个链接,负责XSS并允许嵌套转换。看看https://github.com/iGEL/i18n_link/ – iGEL 2011-07-16 07:55:16

+0

我是用“str = t str”来做的,所以我只给了函数中的翻译键。更舒适! – 2012-07-17 21:45:11

+1

如果可以的话,我会提高@iGEL。该项目已经移动https://github.com/iGEL/it,如果你想在控制器中使用它在Rails 3+中的'flash'消息,就像这样'view_context.it(key,...) ' – 2014-02-08 18:23:19

3

非常感谢holli,分享这种方法。它对我来说就像一个魅力。如果可以的话会投你一票,但这是我的第一篇文章,所以我缺乏适当的声誉......作为拼图的另一部分:我用你的方法意识到的问题是它仍然不能从控制器内部工作。我做了一些研究,并将您的方法与Glenn on rubypond中的方法结合起来。

这里是我想出了:

视图助手,例如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($1, link_url, link_options) + $' 
    else 
     raise "string_with_link: No place for __link__ given in #{str}" if Rails.env.test? 
     nil 
    end 
    end 

在控制器:

flash.now[:alert] = t("path.to.translation") 
flash.now[:alert_link] = here_comes_the_link_path # or _url 

在locale.yml:

path: 
    to: 
    translation: "string with __link__ in the middle" 

在视图:

<%= render_flash_messages %> 

希望这篇文章我挣声望投票给你,霍利: ) 欢迎任何反馈。

7

我拿了hollis的解决方案,并制作了a gem called it。让我们来看一个例子:

log_in_message: "Already signed up? %{login:Log in!}" 

然后

<p><%=t_link "log_in_message", :login => login_path %></p> 

有关详细信息,请参阅https://github.com/iGEL/it

2

我们有以下几点:

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($1, &block) # Pass in what's between the markers 
     }.html_safe 
    else 
     s 
    end 
    end 
    alias :t :translate 
end 

或更明确:

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($1, &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 

然后在ApplicationController.rb只是

class ApplicationController < ActionController::Base 
    helper I18nHelpers 

鉴于像

en.yml文件的关键
mykey: "Click %|here|!" 

可以在ERB作为

<%= t '.mykey' do |text| %> 
    <%= link_to text, 'http://foo.com' %> 
<% end %> 

应该产生

Click <a href="http://foo.com">here</a>! 
1

我想不仅仅是添加链接闪烁从YAML文件的消息(更多的灵活性,例如登录用户名等等),所以我想在字符串中使用ERB表示法。

正如我使用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("&times;"), :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 

然后,可以使用字符串像以下的(使用色器件):

signed_in: "Welcome back <%= current_user.first_name %>! <%= link_to \"Click here\", account_path %> for your account." 

这可能不适用于所有情况,并且可能有一个参数,不应混淆代码和字符串定义(特别是从DRY角度来看),但这对我来说似乎很适用。该代码应该适应其他许多情况下,重要的比特是以下几点:

require 'erb' 

.... 

     begin 
      msg = ERB.new(msg).result(binding) if msg 
     rescue Exception=>e 
      puts e.message 
      puts e.backtrace 
     end 
3

en.yml

registration: 
    terms: 
     text: "I do agree with the terms and conditions: %{gtc}/%{stc}" 
     gtc: "GTC" 
     stc: "STC" 

de.yml

registration: 
    terms: 
     text: "Ich stimme den Geschäfts- und Nutzungsbedingungen zu: %{gtc}/%{stc}" 
     gtc: "AGB" 
     stc: "ANB" 

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 %> 
-1

我想一个简单的方法做,这是通过简单地做:

<%= link_to some_path do %> 
<%= t '.some_locale_key' %> 
<% end %>