Skip to content

Commit

Permalink
Switch from I18n::MissingTranslationData (which is an Exception) to I…
Browse files Browse the repository at this point in the history
…18n::MissingTranslation (which is a plain Object) for the default case. Create an I18n::MissingTranslationData exception only if it needs to be raised to the user.
  • Loading branch information
Sven Fuchs committed Apr 23, 2011
1 parent fc6485f commit 9d85541
Show file tree
Hide file tree
Showing 9 changed files with 55 additions and 34 deletions.
9 changes: 4 additions & 5 deletions lib/i18n.rb
Expand Up @@ -156,7 +156,7 @@ def translate(*args)
backend.translate(locale, key, options)
end
end
result.is_a?(MissingTranslationData) ? handle_exception(handling, result, locale, key, options) : result
result.is_a?(MissingTranslation) ? handle_exception(handling, result, locale, key, options) : result
end
alias :t :translate

Expand Down Expand Up @@ -266,7 +266,7 @@ def normalize_keys(locale, key, scope, separator = nil)

# Any exceptions thrown in translate will be sent to the @@exception_handler
# which can be a Symbol, a Proc or any other Object unless they're forced to
# be raised or thrown (MissingTranslationData).
# be raised or thrown (MissingTranslation).
#
# If exception_handler is a Symbol then it will simply be sent to I18n as
# a method call. A Proc will simply be called. In any other case the
Expand All @@ -285,7 +285,7 @@ def normalize_keys(locale, key, scope, separator = nil)
def handle_exception(handling, exception, locale, key, options)
case handling
when :raise
raise exception
raise(exception.respond_to?(:to_exception) ? exception.to_exception : exception)
when :throw
throw :exception, exception
else
Expand Down Expand Up @@ -325,8 +325,7 @@ def normalize_translation_keys(locale, key, scope, separator = nil)
def default_exception_handler(exception, locale, key, options)
puts "I18n.default_exception_handler is deprecated. Please use the class I18n::ExceptionHandler instead " +
"(an instance of which is set to I18n.exception_handler by default)."
return exception.message if MissingTranslationData === exception
raise exception
exception.is_a?(MissingTranslation) ? exception.message : raise(exception)
end
end
end
4 changes: 2 additions & 2 deletions lib/i18n/backend/base.rb
Expand Up @@ -34,7 +34,7 @@ def translate(locale, key, options = {})
default(locale, key, default, options) : resolve(locale, key, entry, options)
end

throw(:exception, I18n::MissingTranslationData.new(locale, key, options)) if entry.nil?
throw(:exception, I18n::MissingTranslation.new(locale, key, options)) if entry.nil?
entry = entry.dup if entry.is_a?(String)

entry = pluralize(locale, entry, count) if count
Expand Down Expand Up @@ -119,7 +119,7 @@ def resolve(locale, object, subject, options = {})
subject
end
end
result unless result.is_a?(MissingTranslationData)
result unless result.is_a?(MissingTranslation)
end

# Picks a translation from an array according to English pluralization
Expand Down
2 changes: 1 addition & 1 deletion lib/i18n/backend/cache.rb
Expand Up @@ -70,7 +70,7 @@ def translate(locale, key, options = {})

def fetch(cache_key, &block)
result = _fetch(cache_key, &block)
throw(:exception, result) if result.is_a?(MissingTranslationData)
throw(:exception, result) if result.is_a?(MissingTranslation)
result = result.dup if result.frozen? rescue result
result
end
Expand Down
4 changes: 2 additions & 2 deletions lib/i18n/backend/chain.rb
Expand Up @@ -54,7 +54,7 @@ def translate(locale, key, default_options = {})
end

return namespace if namespace
throw(:exception, I18n::MissingTranslationData.new(locale, key, options))
throw(:exception, I18n::MissingTranslation.new(locale, key, options))
end

def localize(locale, object, format = :default, options = {})
Expand All @@ -63,7 +63,7 @@ def localize(locale, object, format = :default, options = {})
result = backend.localize(locale, object, format, options) and return result
end
end
throw(:exception, I18n::MissingTranslationData.new(locale, format, options))
throw(:exception, I18n::MissingTranslation.new(locale, format, options))
end

protected
Expand Down
5 changes: 2 additions & 3 deletions lib/i18n/backend/fallbacks.rb
Expand Up @@ -29,8 +29,7 @@ module Fallbacks
# locale :"de-DE" it might try the locales :"de-DE", :de and :en
# (depends on the fallbacks implementation) until it finds a result with
# the given options. If it does not find any result for any of the
# locales it will then raise a MissingTranslationData exception as
# usual.
# locales it will then throw MissingTranslation as usual.
#
# The default option takes precedence over fallback locales
# only when it's a Symbol. When the default contains a String or a Proc
Expand All @@ -49,7 +48,7 @@ def translate(locale, key, options = {})
options.delete(:fallback)

return super(locale, nil, options.merge(:default => default)) if default
throw(:exception, I18n::MissingTranslationData.new(locale, key, options))
throw(:exception, I18n::MissingTranslation.new(locale, key, options))
end

def extract_string_or_lambda_default!(options)
Expand Down
46 changes: 31 additions & 15 deletions lib/i18n/exceptions.rb
Expand Up @@ -6,7 +6,7 @@ module I18n
class ExceptionHandler
include Module.new {
def call(exception, locale, key, options)
if exception.is_a?(MissingTranslationData)
if exception.is_a?(MissingTranslation)
options[:rescue_format] == :html ? exception.html_message : exception.message
else
raise exception
Expand All @@ -33,25 +33,41 @@ def initialize(filename)
end
end

class MissingTranslationData < ArgumentError
attr_reader :locale, :key, :options
class MissingTranslation
module Base
attr_reader :locale, :key, :options

def initialize(locale, key, opts = nil)
@key, @locale, @options = key, locale, opts.dup || {}
options.each { |k, v| options[k] = v.inspect if v.is_a?(Proc) }
super "translation missing: #{keys.join('.')}"
end
def initialize(locale, key, options = nil)
@key, @locale, @options = key, locale, options.dup || {}
options.each { |k, v| self.options[k] = v.inspect if v.is_a?(Proc) }
end

def html_message
key = keys.last.to_s.gsub('_', ' ').gsub(/\b('?[a-z])/) { $1.capitalize }
%(<span class="translation_missing" title="translation missing: #{keys.join('.')}">#{key}</span>)
end
def html_message
key = keys.last.to_s.gsub('_', ' ').gsub(/\b('?[a-z])/) { $1.capitalize }
%(<span class="translation_missing" title="translation missing: #{keys.join('.')}">#{key}</span>)
end

def keys
@keys ||= I18n.normalize_keys(locale, key, options[:scope]).tap do |keys|
keys << 'no key' if keys.size < 2
end
end

def message
"translation missing: #{keys.join('.')}"
end
alias :to_s :message

def keys
@keys ||= I18n.normalize_keys(locale, key, options[:scope]).tap do |keys|
keys << 'no key' if keys.size < 2
def to_exception
MissingTranslationData.new(locale, key, options)
end
end

include Base
end

class MissingTranslationData < ArgumentError
include MissingTranslation::Base
end

class InvalidPluralizationData < ArgumentError
Expand Down
4 changes: 2 additions & 2 deletions lib/i18n/rails/translation_helper.rb
Expand Up @@ -9,7 +9,7 @@ class ExceptionHandler
# are forced to html_safe
include Module.new {
def call(exception, locale, key, options)
exception.is_a?(MissingTranslationData) ? super.html_safe : super
exception.is_a?(MissingTranslation) ? super.html_safe : super
end
}
end
Expand All @@ -22,7 +22,7 @@ module TranslationHelper
# Delegates to I18n#translate but also performs three additional functions.
#
# First, it'll pass the :rescue_format => :html option to I18n so that any caught
# MissingTranslationData exceptions will be turned into inline spans that
# MissingTranslation exceptions will be turned into inline spans that
#
# * have a "translation-missing" class set,
# * contain the missing key as a title attribute and
Expand Down
7 changes: 7 additions & 0 deletions test/backend/exceptions_test.rb
Expand Up @@ -5,6 +5,13 @@ def setup
I18n.backend = I18n::Backend::Simple.new
end

test "throw message: MissingTranslation message from #translate includes the given scope and full key" do
exception = catch(:exception) do
I18n.t(:'baz.missing', :scope => :'foo.bar', :throw => true)
end
assert_equal "translation missing: en.foo.bar.baz.missing", exception.message
end

test "exceptions: MissingTranslationData message from #translate includes the given scope and full key" do
begin
I18n.t(:'baz.missing', :scope => :'foo.bar', :raise => true)
Expand Down
8 changes: 4 additions & 4 deletions test/i18n_test.rb
Expand Up @@ -197,8 +197,8 @@ def setup
test "can use a lambda as an exception handler" do
begin
previous_exception_handler = I18n.exception_handler
I18n.exception_handler = Proc.new { |exception, locale, key, options| exception }
assert_equal I18n::MissingTranslationData, I18n.translate(:test_proc_handler).class
I18n.exception_handler = Proc.new { |exception, locale, key, options| key }
assert_equal :test_proc_handler, I18n.translate(:test_proc_handler)
ensure
I18n.exception_handler = previous_exception_handler
end
Expand All @@ -208,9 +208,9 @@ def setup
begin
previous_exception_handler = I18n.exception_handler
I18n.exception_handler = Class.new do
def call(exception, locale, key, options); exception; end
def call(exception, locale, key, options); key; end
end.new
assert_equal I18n::MissingTranslationData, I18n.translate(:test_proc_handler).class
assert_equal :test_proc_handler, I18n.translate(:test_proc_handler)
ensure
I18n.exception_handler = previous_exception_handler
end
Expand Down

0 comments on commit 9d85541

Please sign in to comment.