Skip to content

Commit

Permalink
Make TranslationHelper#translate use the :rescue_format option in I18…
Browse files Browse the repository at this point in the history
…n 0.5.0 (backports 896e25e)

    
Don't catch exceptions here. Instead only declare that we want exceptions to be rescued as :html, but also let users configure reactions to exceptions in I18n.
  • Loading branch information
Sven Fuchs committed Feb 28, 2011
1 parent 75015d1 commit afe4495
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 36 deletions.
32 changes: 25 additions & 7 deletions actionpack/lib/action_view/helpers/translation_helper.rb
@@ -1,13 +1,33 @@
require 'action_view/helpers/tag_helper'
require 'i18n/exceptions'

module I18n
class ExceptionHandler
include Module.new {
def call(exception, locale, key, options)
exception.is_a?(MissingTranslationData) ? super.html_safe : super
end
}
end
end

module ActionView
# = Action View Translation Helpers
module Helpers
module TranslationHelper
# Delegates to I18n#translate but also performs three additional functions.
# First, it'll catch MissingTranslationData exceptions and turn them into
# inline spans that contains the missing key, such that you can see in a
# view what is missing where.
#
# First, it'll pass the :rescue_format => :html option to I18n so that any caught
# MissingTranslationData exceptions will be turned into inline spans that
#
# * have a "translation-missing" class set,
# * contain the missing key as a title attribute and
# * a titleized version of the last key segment as a text.
#
# E.g. the value returned for a missing translation key :"blog.post.title" will be
# <span class="translation_missing" title="translation missing: blog.post.title">Title</span>.
# This way your views will display rather reasonableful strings but it will still
# be easy to spot missing translations.
#
# Second, it'll scope the key by the current partial if the key starts
# with a period. So if you call <tt>translate(".foo")</tt> from the
Expand All @@ -24,15 +44,13 @@ module TranslationHelper
# naming convention helps to identify translations that include HTML tags so that
# you know what kind of output to expect when you call translate in a template.
def translate(key, options = {})
translation = I18n.translate(scope_key_by_partial(key), options.merge!(:raise => true))
options.merge!(:rescue_format => :html) unless options.key?(:rescue_format)
translation = I18n.translate(scope_key_by_partial(key), options)
if html_safe_translation_key?(key) && translation.respond_to?(:html_safe)
translation.html_safe
else
translation
end
rescue I18n::MissingTranslationData => e
keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope])
content_tag('span', keys.join(', '), :class => 'translation_missing')
end
alias :t :translate

Expand Down
1 change: 0 additions & 1 deletion actionpack/test/fixtures/test/scoped_translation.erb

This file was deleted.

1 change: 0 additions & 1 deletion actionpack/test/fixtures/test/translation.erb

This file was deleted.

1 change: 1 addition & 0 deletions actionpack/test/fixtures/translations/templates/array.erb
@@ -0,0 +1 @@
<%= t('.foo.bar') %>
1 change: 1 addition & 0 deletions actionpack/test/fixtures/translations/templates/found.erb
@@ -0,0 +1 @@
<%= t('.foo') %>
@@ -0,0 +1 @@
<%= t('.missing') %>
67 changes: 40 additions & 27 deletions actionpack/test/template/translation_helper_test.rb
Expand Up @@ -4,60 +4,73 @@ class TranslationHelperTest < ActiveSupport::TestCase
include ActionView::Helpers::TagHelper
include ActionView::Helpers::TranslationHelper

attr_reader :request
attr_reader :request, :view

def setup
I18n.backend.store_translations(:en,
:translations => {
:templates => {
:found => { :foo => 'Foo' },
:array => { :foo => { :bar => 'Foo Bar' } }
},
:foo => 'Foo',
:hello => '<a>Hello World</a>',
:html => '<a>Hello World</a>',
:hello_html => '<a>Hello World</a>',
:array_html => %w(foo bar),
:array => %w(foo bar)
}
)
@view = ::ActionView::Base.new(ActionController::Base.view_paths, {})
end

def test_delegates_to_i18n_setting_the_raise_option
I18n.expects(:translate).with(:foo, :locale => 'en', :raise => true).returns("")
def test_delegates_to_i18n_setting_the_rescue_format_option_to_html
I18n.expects(:translate).with(:foo, :locale => 'en', :rescue_format => :html).returns("")
translate :foo, :locale => 'en'
end

def test_delegates_localize_to_i18n
@time = Time.utc(2008, 7, 8, 12, 18, 38)
I18n.expects(:localize).with(@time)
localize @time
end

def test_returns_missing_translation_message_wrapped_into_span
expected = '<span class="translation_missing">en, foo</span>'
assert_equal expected, translate(:foo)
expected = '<span class="translation_missing" title="translation missing: en.translations.missing">Missing</span>'
assert_equal expected, translate(:"translations.missing")
end

def test_translation_returning_an_array
I18n.expects(:translate).with(:foo, :raise => true).returns(["foo", "bar"])
assert_equal ["foo", "bar"], translate(:foo)
expected = %w(foo bar)
assert_equal expected, translate(:"translations.array")
end

def test_delegates_localize_to_i18n
@time = Time.utc(2008, 7, 8, 12, 18, 38)
I18n.expects(:localize).with(@time)
localize @time
def test_finds_translation_scoped_by_partial
assert_equal 'Foo', view.render(:file => 'translations/templates/found').strip
end

def test_scoping_by_partial
I18n.expects(:translate).with("test.translation.helper", :raise => true).returns("helper")
@view = ActionView::Base.new(ActionController::Base.view_paths, {})
assert_equal "helper", @view.render(:file => "test/translation")
def test_finds_array_of_translations_scoped_by_partial
assert_equal 'Foo Bar', @view.render(:file => 'translations/templates/array').strip
end

def test_scoping_by_partial_of_an_array
I18n.expects(:translate).with("test.scoped_translation.foo.bar", :raise => true).returns(["foo", "bar"])
@view = ActionView::Base.new(ActionController::Base.view_paths, {})
assert_equal "foobar", @view.render(:file => "test/scoped_translation")
def test_missing_translation_scoped_by_partial
expected = '<span class="translation_missing" title="translation missing: en.translations.templates.missing.missing">Missing</span>'
assert_equal expected, view.render(:file => 'translations/templates/missing').strip
end

def test_translate_does_not_mark_plain_text_as_safe_html
I18n.expects(:translate).with("hello", :raise => true).returns("Hello World")
assert_equal false, translate("hello").html_safe?
assert_equal false, translate(:'translations.hello').html_safe?
end

def test_translate_marks_translations_named_html_as_safe_html
I18n.expects(:translate).with("html", :raise => true).returns("<a>Hello World</a>")
assert translate("html").html_safe?
assert translate(:'translations.html').html_safe?
end

def test_translate_marks_translations_with_a_html_suffix_as_safe_html
I18n.expects(:translate).with("hello_html", :raise => true).returns("<a>Hello World</a>")
assert translate("hello_html").html_safe?
assert translate(:'translations.hello_html').html_safe?
end

def test_translation_returning_an_array_ignores_html_suffix
I18n.expects(:translate).with(:foo_html, :raise => true).returns(["foo", "bar"])
assert_equal ["foo", "bar"], translate(:foo_html)
assert_equal ["foo", "bar"], translate(:'translations.array_html')
end
end

0 comments on commit afe4495

Please sign in to comment.