I\'d like to i18n a text that looks like this:
Already signed up? Log in!
Note that there is a link on the text. On this example
I think a simple way to do this is by simply doing :
<%= link_to some_path do %>
<%= t '.some_locale_key' %>
<% end %>
Why not use the first way, but splitting it up like
log_in_message: Already signed up?
log_in_link_text: Log in!
And then
<p> <%= t('log_in_message') %> <%= link_to t('log_in_link_text'), login_path %> </p>
I took hollis solution and made a gem called it out of it. Let's look at an example:
log_in_message: "Already signed up? %{login:Log in!}"
And then
<p><%=t_link "log_in_message", :login => login_path %></p>
For more details, see https://github.com/iGEL/it.
We had the following:
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
or more explicitly:
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
then in ApplicationController.rb just
class ApplicationController < ActionController::Base
helper I18nHelpers
Given a key in the en.yml
file like
mykey: "Click %|here|!"
can be used in ERB as
<%= t '.mykey' do |text| %>
<%= link_to text, 'http://foo.com' %>
<% end %>
should generate
Click <a href="http://foo.com">here</a>!
Thank you very much, holli, for sharing this approach. It works like a charm for me. Would vote you up if I could, but this is my first post so I'm lacking the proper reputation ... As an additional piece to the puzzle: The problem I realized with your approach is that it still won't work from inside the controller. I did some research and combined your approach with the one from Glenn on rubypond.
Here is what I came up with:
View helper, e.g. 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
In the controller:
flash.now[:alert] = t("path.to.translation")
flash.now[:alert_link] = here_comes_the_link_path # or _url
In the locale.yml:
path:
to:
translation: "string with __link__ in the middle"
In the view:
<%= render_flash_messages %>
Hope this post earns me the reputation to vote you up, holli :) Any feedback is welcome.
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>