2010-03-30 99 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 %>