rails i18n-내부 링크가있는 텍스트 번역


101

나는 다음과 같은 텍스트를 i18n하고 싶습니다.

이미 가입 하셨나요? 로그인!

텍스트에 링크가 있습니다. 이 예제에서는 google을 가리 킵니다. 실제로는 내 앱의 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>

이것은 작동 하지만 <a href=...</a>부분을 갖는 것은 en.yml나에게별로 깨끗하지 않습니다.

다른 옵션 I의 노하우가 사용하는 지역화 된 뷰를 - login.en.html.erb,하고 login.es.html.erb.

유일한 다른 선이 앞서 언급 한 선이기 때문에 이것은 또한 옳지 않다고 생각합니다. 나머지보기 (~ 30 줄)는 모든보기에 대해 반복됩니다. 그것은 매우 건조하지 않을 것입니다.

나는 "localized partials"를 사용할 수 있다고 생각하지만 너무 복잡해 보인다. 나는 너무 많은 작은 뷰 파일을 갖는 것보다 첫 번째 옵션을 선호한다고 생각합니다.

그래서 내 질문은 : 이것을 구현하는 "적절한"방법이 있습니까?



@Wuggy Foofie 질문을 복제하지 않았어야합니다. 그리고 Simone의 대답은 당신이 얻은 것보다 낫습니다.
kikito

답변:


178

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에서는 이에 대한 구문이 %{href}YAML 번역 문자열로 변경되었습니다 . 또한 출력이 자동으로 이스케이프되기 때문에 in 및 이스케이프가 자동으로 건너 뛰기 때문에 번역 키를 지정 raw하거나 .html_safe명시 적으로 지정 하거나 접미사 _htmllogin_message_html를 붙여야합니다.
coreyward 2011-06-09

15
분명하지 않은 경우 (그리고 편집 로그를 확인하기에는 너무 게으른 사람들을 위해) .. 위 의 답변 은 이미 @coreyward의 의견을 포함하도록 편집되었습니다.
abbood

2
링크 텍스트에 하나 이상의 단어가있는 경우 이와 같이 번역을 분할하면 이상한 번역이 생성됩니다. 예를 들어 "우리는 당신이 살 수있는 놀라운 <a href='x'> 여러 가지 물건을 제공 </a>하고 있습니다. 잘게 썬 것을 번역사에게 보내면"We 다른 언어로 "구입할 수있는 놀라운 <a href='x'> 전체 품목 </a>이 있습니다."로 분리되지 않는 솔루션을 찾는 것이 가장
좋습니다

3
@Archonic 사실이 아닙니다. t('string')와 동일합니다 t("string"). 그들은 같은 것입니다.
meagar

3
링크에서 f를 복잡하게 만드는 레일을 좋아했습니다. 다음과 같아야합니다t('some.key', link: link_to()).html_safe
에디

11

locale.yml 파일에서 텍스트와 링크를 분리하는 것은 잠시 동안 작동하지만 더 긴 텍스트의 경우 링크가 별도의 번역 항목에 있기 때문에 번역 및 유지 관리가 어렵습니다 (Simones 답변에서와 같이). 링크로 많은 문자열 / 번역을 시작하면 조금 더 건조시킬 수 있습니다.

내 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.yml에서 :

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

그리고 내 견해 :

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

이렇게하면 링크 텍스트가 locale.yml-files에 명확하게 정의되어 있기 때문에 메시지를 번역하기가 더 쉽습니다.


6
훌륭한 솔루션입니다. 저는 이것을 Gem에 넣어서 link를 정의 할 수 있습니다 This is a %{link:link to Google}. 단일 문자열에 여러 링크를 가질 수 있고 XSS를 처리하며 중첩 된 번역을 허용합니다. 한 번 봐 가지고 github.com/iGEL/i18n_link
이젤

나는 "str = t str"로 그것을했다. 그래서 나는 단지 함수에서 번역 키를 준다. 더 편안하게!
Tim Kretschmer

1
가능하다면 @iGEL을 더 많이 추천하겠습니다. 이 프로젝트는 이동 github.com/iGEL/it을 하고 당신이에 대한 컨트롤러를 사용하려는 경우 flash레일 3+에서 메시지를 다음과 같이 그것을view_context.it(key, ...)
크리스 벡

다음은 컨트롤러에서 사용하기위한 더 좋은 예입니다 - github.com/iGEL/it/issues/10
크리스 벡


5

에서 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 %>

3

이 접근 방식을 공유해 주셔서 대단히 감사합니다. 제게는 매력처럼 작동합니다. 내가 할 수 있다면 투표 하겠지,하지만 이것은 내 첫 번째 게시물이므로 적절한 평판이 부족합니다 ... 퍼즐에 대한 추가 부분 : 귀하의 접근 방식에서 내가 깨달은 문제는 여전히 내부에서 작동하지 않는다는 것입니다. 컨트롤러. 나는 약간의 조사를했고 당신의 접근 방식 을 rubypond에 대한 Glenn 의 접근 방식과 결합 했습니다 .

내가 생각해 낸 것은 다음과 같습니다.

도우미보기 (예 : 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 %>

이 게시물이 저에게 투표 할 수있는 명성을 얻길 바랍니다. holli :) 모든 피드백을 환영합니다.


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

그러면 다음과 같은 문자열을 사용할 수 있습니다 (devise 사용).

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

-2

이 작업을 수행하는 간단한 방법은 다음과 같이하는 것입니다.

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

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

죄송합니다.이 솔루션은 작동하지 않습니다. 텍스트를 다른 언어로 번역하고 싶었습니다. 이것은 어떤 경우에 "링크"가 텍스트의 시작 부분이나 중간 부분에있을 수 있음을 의미합니다. 솔루션은 링크가 끝에 있도록 강제합니다 (잘 번역되지 않음).
kikito 2010 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.