2010-03-30 23 views
79

me gustaría i18n un texto que tiene este aspecto:carriles i18n - traducción de texto con enlaces dentro

Ya estás registrado? Log in!

Tenga en cuenta que hay un enlace en el texto. En este ejemplo, apunta a Google, en realidad señalará a mi aplicación log_in_path.

He encontrado dos formas de hacerlo, pero ninguna de ellas se ve "bien".

La primera forma que conozco implica tener presente mi en.yml:

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

Y en mi opinión:

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

Este funciona, pero tiene la parte <a href=...</a> en el en.yml no lo hace me pareces muy limpio.

La otra opción que conozco es usar localized views - login.en.html.erb, y login.es.html.erb.

Esto tampoco se siente bien ya que la única línea diferente sería la mencionada anteriormente; el resto de la vista (~ 30 líneas) se repetiría para todas las vistas. No sería muy seco

Supongo que podría usar "parciales localizados" pero parece demasiado cumberstone; Creo que prefiero la primera opción para tener tantos archivos de vista pequeños.

Entonces mi pregunta es: ¿hay una forma "adecuada" de implementar esto?

+0

¿Y esto? http://stackoverflow.com/questions/12334183/rails-i18n-better-way-of-interpolating-links –

+0

@Wuggy Foofie No debería haber duplicado la pregunta. Y la respuesta de Simone es mejor que las que tienes. – kikito

Respuesta

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

En Rails 3, la sintaxis para esto ha cambiado a '% {href}' en la cadena de traducción YAML. Además, como la salida se escapa automáticamente, debe especificar 'raw' o' .html_safe' explícitamente, o sufijo su clave de traducción con '_html', como en' login_message_html' y el escape se saltará automáticamente. – coreyward

+15

por si acaso, si no es obvio (y para aquellos demasiado perezosos para comprobar el registro de edición) .. la [respuesta] (http://stackoverflow.com/a/2544107/766570) anterior ya fue editada para incluir @ el comentario de coreyward. – abbood

+1

Si tiene algo más que una sola palabra en el enlace, dividir traducciones como esta producirá traducciones raras. Por ejemplo, "Tenemos un asombroso offering of assorted things que puede comprar. Envía el troceado a un traductor y es probable que obtenga dos frases que dicen" Tenemos un asombroso whole bunch of items que puede comprar "en otros idiomas. encuentre una solución que no los divida. – trcarden

-4

Por qué no utilizar la primera forma, pero dividirlo como

log_in_message: Already signed up? 
log_in_link_text: Log in! 

Y luego

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

Lo siento, esta solución no funcionará. Tenga en cuenta que quería traducir el texto a otros idiomas. Esto significa que en algunas ocasiones el "enlace" podría estar al principio, o en el medio del texto. Su solución fuerza que el enlace esté al final (no se traduce bien). – kikito

11

La separación de texto y enlace en el archivo locale.yml funciona por un tiempo, pero con textos más largos que son difíciles de traducir y mantener ya que el enlace está en un elemento de traducción separado (como en la respuesta de Simones). Si comienza a tener muchas cadenas/traducciones con enlaces, puede secarlo un poco más.

hice un ayudante en mi 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($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 mi en.yml:

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

Y en mis puntos de vista:

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

De esta manera es más fácil para traducir mensajes, como también el texto del enlace está claramente definido en los archivos locale.yml-files.

+4

Gran solución. Puse esto en una Gema, que te permite definir cosas link 'Esto es un% {link: link to Google}'. Le permite tener múltiples enlaces en una sola cadena, se ocupa de XSS y permite las traducciones anidadas. Eche un vistazo a https://github.com/iGEL/i18n_link/ – iGEL

+0

lo hice con "str = t str", así que simplemente le doy la clave de traducción en la función. ¡más cómodo! –

+1

Yo recomendaría @iGEL más si pudiera. El proyecto ha movido https://github.com/iGEL/it y si quiere usarlo en un controlador para un mensaje 'flash' en Rails 3+ hágalo así' view_context.it (key, ...) ' –

3

Muchas gracias, holli, por compartir este enfoque. Funciona como un encanto para mí. Te votaría si pudiera, pero esta es mi primera publicación, así que me falta la reputación adecuada ...Como una pieza adicional al rompecabezas: el problema que me di cuenta con su enfoque es que todavía no funcionará desde el interior del controlador. Investigué un poco y combiné su enfoque con el de Glenn on rubypond.

Esto es lo que ocurrió:

ayudante de vista, por ejemplo, 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 

En el controlador:

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

En el locale.yml:

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

En la vista:

<%= render_flash_messages %> 

Esperanza este post me gana la reputación de votar por usted, Holli:) Cualquier comentario es bienvenido.

7

Tomé la solución de Hollis e hice a gem called it. Veamos un ejemplo:

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

Y luego

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

Para más detalles, véase https://github.com/iGEL/it.

2

Tuvimos la siguiente:

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 

o más explícitamente:

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 

después en ApplicationController.rb simplemente

class ApplicationController < ActionController::Base 
    helper I18nHelpers 

Dada una clave en el archivo en.yml como

mykey: "Click %|here|!" 

se puede utilizar en ERB como

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

debe generar

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

quería un poco más de flexibilidad que simplemente añadir enlaces a flash Los mensajes de los archivos YAML (por ejemplo, ha iniciado la sesión en nombre de usuario etc.) así que en cambio quería usar la notación ERB en la cadena.

Como estoy usando bootstrap_flash por lo que modificó el código de ayudante de la siguiente manera para decodificar las cadenas ERB antes de mostrar:

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 

Entonces es posible utilizar cadenas como la siguiente (utilizando legado):

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

Esto puede no funcionar en todas las situaciones y puede haber un argumento de que las definiciones de código y cadena no se deben mezclar (especialmente desde una perspectiva DRY), pero esto parece funcionar bien para mí. El código debe ser adaptable para muchas otras situaciones, los bits importantes son los siguientes:

require 'erb' 

.... 

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

En en.yml

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

En de.yml

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

en new.html.erb [asumida]

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

Creo que una forma sencilla de hacer esto es simplemente haciendo:

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