rails i18n - içindeki bağlantıları olan metni çevirme


101

Şuna benzeyen bir metni i18n etmek istiyorum:

Zaten üye misiniz? Oturum aç!

Metinde bir bağlantı olduğuna dikkat edin. Bu örnekte google'a işaret ediyor - gerçekte benim uygulamalarıma işaret edecek log_in_path.

Bunu yapmanın iki yolunu buldum, ancak hiçbiri "doğru" görünmüyor.

İlk bildiğim yol, buna sahip olmayı içerir en.yml:

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

Ve benim görüşüme göre:

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

Bu işe yarıyor , ancak <a href=...</a>parçanın üzerinde en.ymlolması bana pek temiz görünmüyor.

Bildiğim diğer seçenek yerelleştirilmiş görünümler kullanmak - login.en.html.erbve login.es.html.erb.

Bu aynı zamanda doğru gelmiyor çünkü tek farklı çizgi yukarıda bahsedilen çizgi olacaktır; görünümün geri kalanı (~ 30 satır) tüm görünümler için tekrarlanacaktır. Çok KURU olmazdı.

Sanırım "yerelleştirilmiş bölümler" kullanabilirim ama bu çok külfetli görünüyor; Sanırım bu kadar çok küçük görüntü dosyasına sahip olmak yerine ilk seçeneği tercih ediyorum.

Öyleyse sorum şu: Bunu uygulamanın "uygun" bir yolu var mı?



@Wuggy Foofie Soruyu tekrar etmemeliydin. Ve Simone'un cevabı seninkilerden daha iyi.
kikito

Yanıtlar:


179

en.yml

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

login.html.erb

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

66
Rails 3'te bunun sözdizimi %{href}YAML çeviri dizesinde olarak değiştirildi. Ayrıca, çıktı otomatik olarak atlandığı için, ya rawda .html_safeaçıkça belirtmeniz ya da açıkça çeviri anahtarınızın son ekini eklemeniz gerekir _html, olduğu gibi login_message_htmlve kaçış otomatik olarak atlanacaktır.
coreyward

15
açık değilse (ve düzenleme günlüğünü kontrol edemeyecek kadar tembel olanlar için) .. yukarıdaki cevap @ coreyward'ın yorumunu içerecek şekilde düzenlendi.
abbood

2
Bağlantı metninde tek bir kelimeden başka bir şeyiniz varsa, bunun gibi çevirileri bölerek tuhaf çeviriler elde edersiniz. Örneğin, "Satın alabileceğiniz harika bir <a href='x'> çeşitli ürün teklifimiz </a> var. Kıyılmış şeyi bir çevirmene gönderirsiniz ve büyük olasılıkla" Biz "diğer dillerde" satın alabileceğiniz harika <a href='x'> bir sürü öğeye </a> sahip olun. Bunları birbirinden ayırmayan bir çözüm bulmak
iyisi

3
@Archonic Bu doğru değil. t('string')ile aynıdır t("string"). Aynı şey.
meagar

3
Bağlantıları zorlaştıran rayları sevmeliyim. böyle görünmelit('some.key', link: link_to()).html_safe
Eddie

11

Locale.yml dosyasında metin ve bağlantıyı ayırmak bir süre işe yarar, ancak daha uzun metinlerde, bağlantı ayrı bir çeviri öğesinde olduğu için çevrilmesi ve bakımı zordur (Simones yanıtında olduğu gibi). Bağlantılı çok sayıda dizeye / çeviriye başlarsanız, onu biraz daha kurutabilirsiniz.

Application_helper.rb dosyamda bir yardımcı yaptım:

# 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

Benim en.yml'de:

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

Ve benim görüşüme göre:

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

Bağlantı metni de locale.yml-dosyalarında açıkça tanımlandığından, bu şekilde iletileri çevirmek daha kolaydır.


6
Harika çözüm. Bunu, bir şeyler bağlantısını tanımlamanıza izin veren bir Gem'e koydum This is a %{link:link to Google}. Tek bir dizede birden çok bağlantıya sahip olmanıza izin verir, XSS ile ilgilenir ve iç içe geçmiş çevirilere izin verir. Github.com/iGEL/i18n_link'e
iGEL

bunu "str = t str" ile yaptım, bu yüzden sadece işlevde çeviri anahtarını verdim. daha rahat!
Tim Kretschmer

1
Mümkünse @iGEL'e daha fazla oy veririm. Proje github.com/iGEL/it'e taşındı ve bunu flashRails 3+ içinde bir mesaj için bir kontrol cihazında kullanmak istiyorsanız, şöyle yapınview_context.it(key, ...)
Chris Beck

Bunu bir kontrol cihazında
Chris Beck

8

Hollis solüsyonunu aldım ve ondan bir mücevherit yaptım. Bir örneğe bakalım:

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

Ve sonra

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

Daha fazla ayrıntı için bkz. Https://github.com/iGEL/it .


5

In en.yml

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

In de.yml

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

içinde new.html.erb [kabul]

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

3

Bu yaklaşımı paylaştığınız için çok teşekkür ederim holli. Benim için bir cazibe gibi çalışıyor. Yapabilseydim sana oy veririm, ama bu benim ilk yazım, bu yüzden uygun bir itibara sahip değilim ... Bulmacaya ek bir parça olarak: Yaklaşımınla fark ettiğim sorun, hala içeriden işe yaramayacak olması. kontrol eden, denetleyici. Biraz araştırma yaptım ve yaklaşımınızı Rubypond'daki Glenn'den gelen yaklaşımla birleştirdim .

İşte bulduğum şey:

Yardımcısı görüntüleyin, örneğin 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

Denetleyicide:

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

Locale.yml'de:

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

Görünümde:

<%= render_flash_messages %>

Umarım bu gönderi size oy vermem için bana itibar kazandırır, holli :) Herhangi bir geri bildirim bekliyoruz.


2

Aşağıdakilere sahiptik:

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

veya daha açık bir şekilde:

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

sonra ApplicationController.rb içinde

class ApplicationController < ActionController::Base
  helper I18nHelpers

en.ymlDosyada şöyle bir anahtar verildi:

mykey: "Click %|here|!"

ERB'de şu şekilde kullanılabilir:

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

üretmeli

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

1

YAML dosyalarından flaş mesajlara bağlantılar eklemekten biraz daha fazla esneklik istedim (örneğin, oturum açmış kullanıcı adı vb.), Bunun yerine dizede ERB gösterimini kullanmak istedim.

Bunu kullandığım bootstrap_flashiçin yardımcı kodu görüntülemeden önce ERB dizelerinin kodunu çözmek için aşağıdaki gibi değiştirdim:

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

Daha sonra aşağıdaki gibi dizeleri kullanmak mümkündür (devise kullanarak):

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

Bu, tüm durumlarda işe yaramayabilir ve kod ve dize tanımlarının karıştırılmaması gerektiğine dair bir argüman olabilir (özellikle DRY açısından), ancak bu benim için iyi çalışıyor gibi görünüyor. Kod, diğer birçok duruma uyarlanabilir olmalıdır, önemli kısımlar aşağıdaki gibidir:

require 'erb'

....

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

-2

Bunu yapmanın basit bir yolu şunu yapmaktır:

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

-4

Neden birinci yolu kullanmıyorsunuz, ama onu bölerek

log_in_message: Already signed up?
log_in_link_text: Log in!

Ve sonra

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

Üzgünüz, bu çözüm işe yaramayacak. Metni diğer dillere çevirmek istediğimi unutmayın. Bu, bazı durumlarda "bağlantı" nın metnin başında veya ortasında olabileceği anlamına gelir. Çözümünüz, bağlantıyı sonunda olmaya zorlar (iyi tercüme edilmez).
kikito
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.