From 9f74ae9d4869b011bfbef0c3396726b6f108de41 Mon Sep 17 00:00:00 2001
From: stereobooster <stereobooster@gmail.com>
Date: Thu, 9 Nov 2017 11:02:07 +0100
Subject: [PATCH 1/2] Frozen strings

---
 lib/i18n.rb                                |  2 ++
 lib/i18n/backend.rb                        |  2 ++
 lib/i18n/backend/base.rb                   |  2 ++
 lib/i18n/backend/cache.rb                  |  8 +++++---
 lib/i18n/backend/cascade.rb                |  2 ++
 lib/i18n/backend/chain.rb                  |  2 ++
 lib/i18n/backend/fallbacks.rb              |  2 ++
 lib/i18n/backend/flatten.rb                |  2 ++
 lib/i18n/backend/gettext.rb                |  2 ++
 lib/i18n/backend/interpolation_compiler.rb |  2 ++
 lib/i18n/backend/key_value.rb              |  2 ++
 lib/i18n/backend/memoize.rb                |  2 ++
 lib/i18n/backend/metadata.rb               |  2 ++
 lib/i18n/backend/pluralization.rb          |  2 ++
 lib/i18n/backend/simple.rb                 |  2 ++
 lib/i18n/backend/transliterator.rb         |  2 ++
 lib/i18n/config.rb                         |  4 +++-
 lib/i18n/exceptions.rb                     |  2 ++
 lib/i18n/gettext.rb                        |  2 ++
 lib/i18n/gettext/helpers.rb                |  2 ++
 lib/i18n/gettext/po_parser.rb              | 14 +++++++-------
 lib/i18n/locale.rb                         |  2 ++
 lib/i18n/middleware.rb                     |  2 ++
 lib/i18n/tests.rb                          |  2 ++
 lib/i18n/version.rb                        |  2 ++
 25 files changed, 59 insertions(+), 11 deletions(-)

diff --git a/lib/i18n.rb b/lib/i18n.rb
index cf44ce3c..50a4db20 100644
--- a/lib/i18n.rb
+++ b/lib/i18n.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'concurrent/map'
 
 require 'i18n/version'
diff --git a/lib/i18n/backend.rb b/lib/i18n/backend.rb
index 46ef054b..222271e3 100644
--- a/lib/i18n/backend.rb
+++ b/lib/i18n/backend.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module I18n
   module Backend
     autoload :Base,                  'i18n/backend/base'
diff --git a/lib/i18n/backend/base.rb b/lib/i18n/backend/base.rb
index a73a3ae0..6d29a7cf 100644
--- a/lib/i18n/backend/base.rb
+++ b/lib/i18n/backend/base.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'yaml'
 require 'i18n/core_ext/hash'
 require 'i18n/core_ext/kernel/suppress_warnings'
diff --git a/lib/i18n/backend/cache.rb b/lib/i18n/backend/cache.rb
index 1aa64348..1612e3d9 100644
--- a/lib/i18n/backend/cache.rb
+++ b/lib/i18n/backend/cache.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 # This module allows you to easily cache all responses from the backend - thus
 # speeding up the I18n aspects of your application quite a bit.
 #
@@ -14,9 +16,9 @@
 # ActiveSupport::Cache (only the methods #fetch and #write are being used).
 #
 # The cache_key implementation by default assumes you pass values that return
-# a valid key from #hash (see 
-# http://www.ruby-doc.org/core/classes/Object.html#M000337). However, you can 
-# configure your own digest method via which responds to #hexdigest (see 
+# a valid key from #hash (see
+# http://www.ruby-doc.org/core/classes/Object.html#M000337). However, you can
+# configure your own digest method via which responds to #hexdigest (see
 # http://ruby-doc.org/stdlib/libdoc/digest/rdoc/index.html):
 #
 #   I18n.cache_key_digest = Digest::MD5.new
diff --git a/lib/i18n/backend/cascade.rb b/lib/i18n/backend/cascade.rb
index d8fb1cf4..182824cf 100644
--- a/lib/i18n/backend/cascade.rb
+++ b/lib/i18n/backend/cascade.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 # The Cascade module adds the ability to do cascading lookups to backends that
 # are compatible to the Simple backend.
 #
diff --git a/lib/i18n/backend/chain.rb b/lib/i18n/backend/chain.rb
index 2a45cad3..c08d1398 100644
--- a/lib/i18n/backend/chain.rb
+++ b/lib/i18n/backend/chain.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module I18n
   module Backend
     # Backend that chains multiple other backends and checks each of them when
diff --git a/lib/i18n/backend/fallbacks.rb b/lib/i18n/backend/fallbacks.rb
index a3badaea..27c1beb9 100644
--- a/lib/i18n/backend/fallbacks.rb
+++ b/lib/i18n/backend/fallbacks.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 # I18n locale fallbacks are useful when you want your application to use
 # translations from other locales when translations for the current locale are
 # missing. E.g. you might want to use :en translations when translations in
diff --git a/lib/i18n/backend/flatten.rb b/lib/i18n/backend/flatten.rb
index 995c3462..f2ce3a0d 100644
--- a/lib/i18n/backend/flatten.rb
+++ b/lib/i18n/backend/flatten.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module I18n
   module Backend
     # This module contains several helpers to assist flattening translations.
diff --git a/lib/i18n/backend/gettext.rb b/lib/i18n/backend/gettext.rb
index f41df685..ea2b6a3c 100644
--- a/lib/i18n/backend/gettext.rb
+++ b/lib/i18n/backend/gettext.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'i18n/gettext'
 require 'i18n/gettext/po_parser'
 
diff --git a/lib/i18n/backend/interpolation_compiler.rb b/lib/i18n/backend/interpolation_compiler.rb
index 0e3a603a..c715897a 100644
--- a/lib/i18n/backend/interpolation_compiler.rb
+++ b/lib/i18n/backend/interpolation_compiler.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 # The InterpolationCompiler module contains optimizations that can tremendously
 # speed up the interpolation process on the Simple backend.
 #
diff --git a/lib/i18n/backend/key_value.rb b/lib/i18n/backend/key_value.rb
index 95bdc641..10d9b7fe 100644
--- a/lib/i18n/backend/key_value.rb
+++ b/lib/i18n/backend/key_value.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'i18n/backend/base'
 
 module I18n
diff --git a/lib/i18n/backend/memoize.rb b/lib/i18n/backend/memoize.rb
index a11bdec1..7ab300f5 100644
--- a/lib/i18n/backend/memoize.rb
+++ b/lib/i18n/backend/memoize.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 # Memoize module simply memoizes the values returned by lookup using
 # a flat hash and can tremendously speed up the lookup process in a backend.
 #
diff --git a/lib/i18n/backend/metadata.rb b/lib/i18n/backend/metadata.rb
index a8d922a0..5de83396 100644
--- a/lib/i18n/backend/metadata.rb
+++ b/lib/i18n/backend/metadata.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 # I18n translation metadata is useful when you want to access information
 # about how a translation was looked up, pluralized or interpolated in
 # your application.
diff --git a/lib/i18n/backend/pluralization.rb b/lib/i18n/backend/pluralization.rb
index 01e68d27..a0a2f565 100644
--- a/lib/i18n/backend/pluralization.rb
+++ b/lib/i18n/backend/pluralization.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 # I18n Pluralization are useful when you want your application to
 # customize pluralization rules.
 #
diff --git a/lib/i18n/backend/simple.rb b/lib/i18n/backend/simple.rb
index 4744130f..e3c6aaf3 100644
--- a/lib/i18n/backend/simple.rb
+++ b/lib/i18n/backend/simple.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module I18n
   module Backend
     # A simple backend that reads translations from YAML files and stores them in
diff --git a/lib/i18n/backend/transliterator.rb b/lib/i18n/backend/transliterator.rb
index 2617bcf2..bb704ab7 100644
--- a/lib/i18n/backend/transliterator.rb
+++ b/lib/i18n/backend/transliterator.rb
@@ -1,4 +1,6 @@
 # encoding: utf-8
+# frozen_string_literal: true
+
 module I18n
   module Backend
     module Transliterator
diff --git a/lib/i18n/config.rb b/lib/i18n/config.rb
index b3736896..9c4221c7 100644
--- a/lib/i18n/config.rb
+++ b/lib/i18n/config.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'set'
 
 module I18n
@@ -57,7 +59,7 @@ def available_locales=(locales)
       @@available_locales = nil if @@available_locales.empty?
       @@available_locales_set = nil
     end
-    
+
     # Returns true if the available_locales have been initialized
     def available_locales_initialized?
       ( !!defined?(@@available_locales) && !!@@available_locales )
diff --git a/lib/i18n/exceptions.rb b/lib/i18n/exceptions.rb
index 7e8b0d69..c37f7fe8 100644
--- a/lib/i18n/exceptions.rb
+++ b/lib/i18n/exceptions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'cgi'
 
 module I18n
diff --git a/lib/i18n/gettext.rb b/lib/i18n/gettext.rb
index 392cccd3..858daff4 100644
--- a/lib/i18n/gettext.rb
+++ b/lib/i18n/gettext.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module I18n
   module Gettext
     PLURAL_SEPARATOR  = "\001"
diff --git a/lib/i18n/gettext/helpers.rb b/lib/i18n/gettext/helpers.rb
index c97fd349..7f777976 100644
--- a/lib/i18n/gettext/helpers.rb
+++ b/lib/i18n/gettext/helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'i18n/gettext'
 
 module I18n
diff --git a/lib/i18n/gettext/po_parser.rb b/lib/i18n/gettext/po_parser.rb
index 547df6a5..a07fdc58 100644
--- a/lib/i18n/gettext/po_parser.rb
+++ b/lib/i18n/gettext/po_parser.rb
@@ -28,7 +28,7 @@ def unescape(orig)
     ret.gsub!(/\\"/, "\"")
     ret
   end
-  
+
   def parse(str, data, ignore_fuzzy = true)
     @comments = []
     @data = data
@@ -64,7 +64,7 @@ def parse(str, data, ignore_fuzzy = true)
 	str = $'
       when /\A\#(.*)/
 	@q.push [:COMMENT, $&]
-	str = $'      
+	str = $'
       when /\A\"(.*)\"/
 	@q.push [:STRING, $1]
 	str = $'
@@ -73,7 +73,7 @@ def parse(str, data, ignore_fuzzy = true)
 	#@q.push [:STRING, c]
 	str = str[1..-1]
       end
-    end 
+    end
     @q.push [false, '$end']
     if $DEBUG
       @q.each do |a,b|
@@ -88,7 +88,7 @@ def parse(str, data, ignore_fuzzy = true)
     end
     @data
   end
-  
+
   def next_token
     @q.shift
   end
@@ -101,11 +101,11 @@ def on_message(msgid, msgstr)
     @comments.clear
     @msgctxt = ""
   end
-      
+
   def on_comment(comment)
     @fuzzy = true if (/fuzzy/ =~ comment)
     @comments << comment
-  end 
+  end
 
 
 ..end src/poparser.ry modeval..id7a99570e05
@@ -245,7 +245,7 @@ def _reduce_5( val, _values, result )
 
 module_eval <<'.,.,', 'src/poparser.ry', 48
   def _reduce_8( val, _values, result )
-    if @fuzzy and $ignore_fuzzy 
+    if @fuzzy and $ignore_fuzzy
       if val[1] != ""
         $stderr.print _("Warning: fuzzy message was ignored.\n")
         $stderr.print "         msgid '#{val[1]}'\n"
diff --git a/lib/i18n/locale.rb b/lib/i18n/locale.rb
index 4f9d0266..c4078e61 100644
--- a/lib/i18n/locale.rb
+++ b/lib/i18n/locale.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module I18n
   module Locale
   autoload :Fallbacks, 'i18n/locale/fallbacks'
diff --git a/lib/i18n/middleware.rb b/lib/i18n/middleware.rb
index 67461f7a..59b377e2 100644
--- a/lib/i18n/middleware.rb
+++ b/lib/i18n/middleware.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module I18n
   class Middleware
 
diff --git a/lib/i18n/tests.rb b/lib/i18n/tests.rb
index 554cdefe..30d0ed53 100644
--- a/lib/i18n/tests.rb
+++ b/lib/i18n/tests.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module I18n
   module Tests
     autoload :Basics,        'i18n/tests/basics'
diff --git a/lib/i18n/version.rb b/lib/i18n/version.rb
index 3f569028..5ae4433a 100644
--- a/lib/i18n/version.rb
+++ b/lib/i18n/version.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module I18n
   VERSION = "1.0.0"
 end

From 3495c6da457f49617655b3c8de540e5b768b32b2 Mon Sep 17 00:00:00 2001
From: stereobooster <stereobooster@gmail.com>
Date: Thu, 9 Nov 2017 13:07:02 +0100
Subject: [PATCH 2/2] Use constant instead of anonymous objects

---
 lib/i18n.rb                                |  4 ++--
 lib/i18n/backend/base.rb                   | 16 ++++++++--------
 lib/i18n/backend/cache.rb                  |  2 +-
 lib/i18n/backend/cascade.rb                |  2 +-
 lib/i18n/backend/chain.rb                  |  6 +++---
 lib/i18n/backend/fallbacks.rb              | 22 +++++++++-------------
 lib/i18n/backend/interpolation_compiler.rb |  2 +-
 lib/i18n/backend/key_value.rb              |  4 ++--
 lib/i18n/backend/memoize.rb                |  4 ++--
 lib/i18n/backend/metadata.rb               |  4 ++--
 lib/i18n/backend/simple.rb                 |  4 ++--
 lib/i18n/exceptions.rb                     |  2 +-
 lib/i18n/gettext/helpers.rb                |  2 +-
 13 files changed, 35 insertions(+), 39 deletions(-)

diff --git a/lib/i18n.rb b/lib/i18n.rb
index 50a4db20..471ca79a 100644
--- a/lib/i18n.rb
+++ b/lib/i18n.rb
@@ -16,7 +16,7 @@ module I18n
 
   RESERVED_KEYS = [:scope, :default, :separator, :resolve, :object, :fallback, :fallback_in_progress, :format, :cascade, :throw, :raise, :deep_interpolation]
   RESERVED_KEYS_PATTERN = /%\{(#{RESERVED_KEYS.join("|")})\}/
-
+  EMPTY_HASH = {}.freeze
 
   def self.new_double_nested_cache # :nodoc:
     Concurrent::Map.new { |h,k| h[k] = Concurrent::Map.new }
@@ -177,7 +177,7 @@ def translate(*args)
 
     # Wrapper for <tt>translate</tt> that adds <tt>:raise => true</tt>. With
     # this option, if no translation is found, it will raise <tt>I18n::MissingTranslationData</tt>
-    def translate!(key, options={})
+    def translate!(key, options = EMPTY_HASH)
       translate(key, options.merge(:raise => true))
     end
     alias :t! :translate!
diff --git a/lib/i18n/backend/base.rb b/lib/i18n/backend/base.rb
index 6d29a7cf..73a42ad7 100644
--- a/lib/i18n/backend/base.rb
+++ b/lib/i18n/backend/base.rb
@@ -19,11 +19,11 @@ def load_translations(*filenames)
 
       # This method receives a locale, a data hash and options for storing translations.
       # Should be implemented
-      def store_translations(locale, data, options = {})
+      def store_translations(locale, data, options = EMPTY_HASH)
         raise NotImplementedError
       end
 
-      def translate(locale, key, options = {})
+      def translate(locale, key, options = EMPTY_HASH)
         raise I18n::ArgumentError if (key.is_a?(String) || key.is_a?(Symbol)) && key.empty?
         raise InvalidLocale.new(locale) unless locale
         return nil if key.nil? && !options.key?(:default)
@@ -70,7 +70,7 @@ def exists?(locale, key)
       # Acts the same as +strftime+, but uses a localized version of the
       # format string. Takes a key from the date/time formats translations as
       # a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>).
-      def localize(locale, object, format = :default, options = {})
+      def localize(locale, object, format = :default, options = EMPTY_HASH)
         if object.nil? && options.include?(:default)
           return options[:default]
         end
@@ -99,7 +99,7 @@ def reload!
       protected
 
         # The method which actually looks up for the translation in the store.
-        def lookup(locale, key, scope = [], options = {})
+        def lookup(locale, key, scope = [], options = EMPTY_HASH)
           raise NotImplementedError
         end
 
@@ -111,7 +111,7 @@ def subtrees?
         # If given subject is an Array, it walks the array and returns the
         # first translation that can be resolved. Otherwise it tries to resolve
         # the translation directly.
-        def default(locale, object, subject, options = {})
+        def default(locale, object, subject, options = EMPTY_HASH)
           options = options.dup.reject { |key, value| key == :default }
           case subject
           when Array
@@ -128,7 +128,7 @@ def default(locale, object, subject, options = {})
         # If the given subject is a Symbol, it will be translated with the
         # given options. If it is a Proc then it will be evaluated. All other
         # subjects will be returned directly.
-        def resolve(locale, object, subject, options = {})
+        def resolve(locale, object, subject, options = EMPTY_HASH)
           return subject if options[:resolve] == false
           result = catch(:exception) do
             case subject
@@ -170,7 +170,7 @@ def pluralize(locale, entry, count)
         #   each element of the array is recursively interpolated (until it finds a string)
         #   method interpolates ["yes, %{user}", ["maybe no, %{user}, "no, %{user}"]], :user => "bartuz"
         #   # => "["yes, bartuz",["maybe no, bartuz", "no, bartuz"]]"
-        def interpolate(locale, subject, values = {})
+        def interpolate(locale, subject, values = EMPTY_HASH)
           return subject if values.empty?
 
           case subject
@@ -186,7 +186,7 @@ def interpolate(locale, subject, values = {})
         #   deep_interpolate { people: { ann: "Ann is %{ann}", john: "John is %{john}" } },
         #                    ann: 'good', john: 'big'
         #   #=> { people: { ann: "Ann is good", john: "John is big" } }
-        def deep_interpolate(locale, data, values = {})
+        def deep_interpolate(locale, data, values = EMPTY_HASH)
           return data if values.empty?
 
           case data
diff --git a/lib/i18n/backend/cache.rb b/lib/i18n/backend/cache.rb
index 1612e3d9..7231c199 100644
--- a/lib/i18n/backend/cache.rb
+++ b/lib/i18n/backend/cache.rb
@@ -77,7 +77,7 @@ def perform_caching?
   module Backend
     # TODO Should the cache be cleared if new translations are stored?
     module Cache
-      def translate(locale, key, options = {})
+      def translate(locale, key, options = EMPTY_HASH)
         I18n.perform_caching? ? fetch(cache_key(locale, key, options)) { super } : super
       end
 
diff --git a/lib/i18n/backend/cascade.rb b/lib/i18n/backend/cascade.rb
index 182824cf..782b07b5 100644
--- a/lib/i18n/backend/cascade.rb
+++ b/lib/i18n/backend/cascade.rb
@@ -33,7 +33,7 @@
 module I18n
   module Backend
     module Cascade
-      def lookup(locale, key, scope = [], options = {})
+      def lookup(locale, key, scope = [], options = EMPTY_HASH)
         return super unless cascade = options[:cascade]
 
         cascade   = { :step => 1 } unless cascade.is_a?(Hash)
diff --git a/lib/i18n/backend/chain.rb b/lib/i18n/backend/chain.rb
index c08d1398..2bc83cb7 100644
--- a/lib/i18n/backend/chain.rb
+++ b/lib/i18n/backend/chain.rb
@@ -30,7 +30,7 @@ def reload!
           backends.each { |backend| backend.reload! }
         end
 
-        def store_translations(locale, data, options = {})
+        def store_translations(locale, data, options = EMPTY_HASH)
           backends.first.store_translations(locale, data, options)
         end
 
@@ -38,7 +38,7 @@ def available_locales
           backends.map { |backend| backend.available_locales }.flatten.uniq
         end
 
-        def translate(locale, key, default_options = {})
+        def translate(locale, key, default_options = EMPTY_HASH)
           namespace = nil
           options = default_options.except(:default)
 
@@ -64,7 +64,7 @@ def exists?(locale, key)
           end
         end
 
-        def localize(locale, object, format = :default, options = {})
+        def localize(locale, object, format = :default, options = EMPTY_HASH)
           backends.each do |backend|
             catch(:exception) do
               result = backend.localize(locale, object, format, options) and return result
diff --git a/lib/i18n/backend/fallbacks.rb b/lib/i18n/backend/fallbacks.rb
index 27c1beb9..7355d192 100644
--- a/lib/i18n/backend/fallbacks.rb
+++ b/lib/i18n/backend/fallbacks.rb
@@ -36,25 +36,21 @@ module Fallbacks
       # The default option takes precedence over fallback locales only when
       # it's a Symbol. When the default contains a String, Proc or Hash
       # it is evaluated last after all the fallback locales have been tried.
-      def translate(locale, key, options = {})
+      def translate(locale, key, options = EMPTY_HASH)
         return super unless options.fetch(:fallback, true)
         return super if options[:fallback_in_progress]
         default = extract_non_symbol_default!(options) if options[:default]
 
-        begin
-          options[:fallback_in_progress] = true
-          I18n.fallbacks[locale].each do |fallback|
-            begin
-              catch(:exception) do
-                result = super(fallback, key, options)
-                return result unless result.nil?
-              end
-            rescue I18n::InvalidLocale
-              # we do nothing when the locale is invalid, as this is a fallback anyways.
+        fallback_options = options.merge(:fallback_in_progress => true)
+        I18n.fallbacks[locale].each do |fallback|
+          begin
+            catch(:exception) do
+              result = super(fallback, key, fallback_options)
+              return result unless result.nil?
             end
+          rescue I18n::InvalidLocale
+            # we do nothing when the locale is invalid, as this is a fallback anyways.
           end
-        ensure
-          options.delete(:fallback_in_progress)
         end
 
         return if options.key?(:default) && options[:default].nil?
diff --git a/lib/i18n/backend/interpolation_compiler.rb b/lib/i18n/backend/interpolation_compiler.rb
index c715897a..8b52e7b3 100644
--- a/lib/i18n/backend/interpolation_compiler.rb
+++ b/lib/i18n/backend/interpolation_compiler.rb
@@ -106,7 +106,7 @@ def interpolate(locale, string, values)
         end
       end
 
-      def store_translations(locale, data, options = {})
+      def store_translations(locale, data, options = EMPTY_HASH)
         compile_all_strings_in(data)
         super
       end
diff --git a/lib/i18n/backend/key_value.rb b/lib/i18n/backend/key_value.rb
index 10d9b7fe..ad1cc3d7 100644
--- a/lib/i18n/backend/key_value.rb
+++ b/lib/i18n/backend/key_value.rb
@@ -76,7 +76,7 @@ def initialize(store, subtrees=true)
           @store, @subtrees = store, subtrees
         end
 
-        def store_translations(locale, data, options = {})
+        def store_translations(locale, data, options = EMPTY_HASH)
           escape = options.fetch(:escape, true)
           flatten_translations(locale, data, escape, @subtrees).each do |key, value|
             key = "#{locale}.#{key}"
@@ -109,7 +109,7 @@ def subtrees?
           @subtrees
         end
 
-        def lookup(locale, key, scope = [], options = {})
+        def lookup(locale, key, scope = [], options = EMPTY_HASH)
           key   = normalize_flat_keys(locale, key, scope, options[:separator])
           value = @store["#{locale}.#{key}"]
           value = JSON.decode(value) if value
diff --git a/lib/i18n/backend/memoize.rb b/lib/i18n/backend/memoize.rb
index 7ab300f5..1aa1feb2 100644
--- a/lib/i18n/backend/memoize.rb
+++ b/lib/i18n/backend/memoize.rb
@@ -16,7 +16,7 @@ def available_locales
         @memoized_locales ||= super
       end
 
-      def store_translations(locale, data, options = {})
+      def store_translations(locale, data, options = EMPTY_HASH)
         reset_memoizations!(locale)
         super
       end
@@ -28,7 +28,7 @@ def reload!
 
       protected
 
-        def lookup(locale, key, scope = nil, options = {})
+        def lookup(locale, key, scope = nil, options = EMPTY_HASH)
           flat_key  = I18n::Backend::Flatten.normalize_flat_keys(locale,
             key, scope, options[:separator]).to_sym
           flat_hash = memoized_lookup[locale.to_sym]
diff --git a/lib/i18n/backend/metadata.rb b/lib/i18n/backend/metadata.rb
index 5de83396..04147cb6 100644
--- a/lib/i18n/backend/metadata.rb
+++ b/lib/i18n/backend/metadata.rb
@@ -37,7 +37,7 @@ def translation_metadata=(translation_metadata)
         end
       end
 
-      def translate(locale, key, options = {})
+      def translate(locale, key, options = EMPTY_HASH)
         metadata = {
           :locale    => locale,
           :key       => key,
@@ -49,7 +49,7 @@ def translate(locale, key, options = {})
         with_metadata(metadata) { super }
       end
 
-      def interpolate(locale, entry, values = {})
+      def interpolate(locale, entry, values = EMPTY_HASH)
         metadata = entry.translation_metadata.merge(:original => entry)
         with_metadata(metadata) { super }
       end
diff --git a/lib/i18n/backend/simple.rb b/lib/i18n/backend/simple.rb
index e3c6aaf3..48aeaf48 100644
--- a/lib/i18n/backend/simple.rb
+++ b/lib/i18n/backend/simple.rb
@@ -30,7 +30,7 @@ def initialized?
         # This uses a deep merge for the translations hash, so existing
         # translations will be overwritten by new ones only at the deepest
         # level of the hash.
-        def store_translations(locale, data, options = {})
+        def store_translations(locale, data, options = EMPTY_HASH)
           if I18n.enforce_available_locales &&
             I18n.available_locales_initialized? &&
             !I18n.available_locales.include?(locale.to_sym) &&
@@ -75,7 +75,7 @@ def translations
         # nested translations hash. Splits keys or scopes containing dots
         # into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
         # <tt>%w(currency format)</tt>.
-        def lookup(locale, key, scope = [], options = {})
+        def lookup(locale, key, scope = [], options = EMPTY_HASH)
           init_translations unless initialized?
           keys = I18n.normalize_keys(locale, key, scope, options[:separator])
 
diff --git a/lib/i18n/exceptions.rb b/lib/i18n/exceptions.rb
index c37f7fe8..13e32cc1 100644
--- a/lib/i18n/exceptions.rb
+++ b/lib/i18n/exceptions.rb
@@ -44,7 +44,7 @@ class MissingTranslation < ArgumentError
     module Base
       attr_reader :locale, :key, :options
 
-      def initialize(locale, key, options = {})
+      def initialize(locale, key, options = EMPTY_HASH)
         @key, @locale, @options = key, locale, options.dup
         options.each { |k, v| self.options[k] = v.inspect if v.is_a?(Proc) }
       end
diff --git a/lib/i18n/gettext/helpers.rb b/lib/i18n/gettext/helpers.rb
index 7f777976..309f555e 100644
--- a/lib/i18n/gettext/helpers.rb
+++ b/lib/i18n/gettext/helpers.rb
@@ -18,7 +18,7 @@ def N_(msgsid)
         msgsid
       end
 
-      def gettext(msgid, options = {})
+      def gettext(msgid, options = EMPTY_HASH)
         I18n.t(msgid, { :default => msgid, :separator => '|' }.merge(options))
       end
       alias _ gettext