Ответ 1
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>
Я бы хотел, чтобы текст выглядел следующим образом:
Уже зарегистрированы? Войти!
Обратите внимание, что есть ссылка на текст. В этом примере он указывает на 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
не выглядит очень чистым для меня.
Другим вариантом, который я знаю, является использование локализованных представлений - login.en.html.erb
и login.es.html.erb
.
Это также не очень хорошо, так как единственная другая линия была бы упомянутой выше; остальная часть представления (~ 30 строк) будет повторяться для всех просмотров. Это было бы не очень СУХОЙ.
Я предполагаю, что я мог бы использовать "локализованные частичные", но это кажется слишком каменным камнем; Я думаю, что предпочитаю первый вариант иметь так много крошечных файлов вида.
Итак, мой вопрос: есть ли "правильный" способ реализовать это?
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>
Разделение текста и ссылки в файле locale.yml работает некоторое время, но с более длинным текстом, которые трудно перевести и поддерживать, поскольку ссылка находится в отдельной позиции перевода (как в ответе Симонов). Если вы начинаете иметь много строк/переводов со ссылками, вы можете высушить их немного больше.
Я сделал один помощник в своем приложении 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.
Я принял решение hollis и сделал драгоценный камень, названный 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.
В ru.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 %>
Большое спасибо, Холли, за то, что поделился этим подходом. Он работает как прелесть для меня. Если бы я мог проголосовать за вас, но это мой первый пост, поэтому мне не хватает надлежащей репутации... В качестве дополнительной части для загадки: Проблема, которую я понял с вашим подходом, заключается в том, что она все еще не будет работать изнутри контроллер. Я провел некоторое исследование и объединил ваш подход с тем, который был от 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 %>
Надеюсь, что этот пост приносит мне репутацию, чтобы проголосовать за тебя, Холли:) Любая обратная связь приветствуется.
У нас было следующее:
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 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 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>!
Мне нужно было немного больше гибкости, чем просто добавлять ссылки на флеш-сообщения из файлов 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("×"), :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."
Это может не работать для всех ситуаций, и может быть аргумент, что определения кода и строк не должны смешиваться (особенно с точки зрения СУХОЙ), но это, похоже, хорошо работает для меня. Код должен быть адаптирован для многих других ситуаций, причем важными битами являются следующие:
require 'erb'
....
begin
msg = ERB.new(msg).result(binding) if msg
rescue Exception=>e
puts e.message
puts e.backtrace
end
Я думаю, что простой способ сделать это - просто:
<%= link_to some_path do %>
<%= t '.some_locale_key' %>
<% end %>
Почему бы не использовать первый способ, но разделив его как
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>