Skip to content

Commit

Permalink
Introduce support for deprecating translation keys
Browse files Browse the repository at this point in the history
Adds an `I18n::deprecate` API that allows users to mark a key as
deprecated and superseded by another.

`I18n::t` will then use the following logic:

- If the key supersedes a deprecated one, and the old one is still
  defined, use the old one instead. If the old one is not defined
  anymore, use the new one.

- If the key is deprecated and the old one is still defined, use
  the old one. If the old one is not defined anymore, use the new
  one.

- For all other keys, regular behavior is maintained.

The reason the old key is always preferred to the new one when
available is that users may have been using the new key for other
purposes, and we don't want to swap it for the old one without
notice. Instead, users have to manually go in and delete the old
key for the new one to start being used.
  • Loading branch information
kennyadsl authored and aldesantis committed Sep 25, 2019
1 parent 2942126 commit 981b12d
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 1 deletion.
4 changes: 4 additions & 0 deletions lib/i18n.rb
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ def translate(key = nil, *, throw: false, raise: false, locale: nil, **options)
end
alias :t :translate

def deprecate(deprecation)
config.deprecations[deprecation.keys.first.to_sym] = deprecation.values.first.to_sym
end

# 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 = EMPTY_HASH)
Expand Down
1 change: 1 addition & 0 deletions lib/i18n/backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module Backend
autoload :CacheFile, 'i18n/backend/cache_file'
autoload :Cascade, 'i18n/backend/cascade'
autoload :Chain, 'i18n/backend/chain'
autoload :Deprecator, 'i18n/backend/deprecator'
autoload :Fallbacks, 'i18n/backend/fallbacks'
autoload :Flatten, 'i18n/backend/flatten'
autoload :Gettext, 'i18n/backend/gettext'
Expand Down
25 changes: 24 additions & 1 deletion lib/i18n/backend/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,30 @@ def translate(locale, key, options = EMPTY_HASH)
raise InvalidLocale.new(locale) unless locale
return nil if key.nil? && !options.key?(:default)

entry = lookup(locale, key, options[:scope], options) unless key.nil?
entry = nil

if key
normalized_key = I18n.normalize_keys(locale, key, options[:scope])[1..-1].join(I18n.config.default_separator).to_sym
deprecated_key = I18n.config.deprecations.key(normalized_key)

# Does this key supersede a deprecated one?
if deprecated_key
# Try to use up the old key, if present.
entry = lookup(locale, deprecated_key, nil, options)
end

entry ||= lookup(locale, key, options[:scope], options)

if entry.nil?
# Is this key deprecated by another?
new_key = I18n.config.deprecations[normalized_key]

if new_key
puts "DEPRECATION WARNING: #{normalized_key} is deprecated, use #{new_key} instead"
entry = lookup(locale, new_key, nil, options)
end
end
end

if entry.nil? && options.key?(:default)
entry = default(locale, key, options[:default], options)
Expand Down
17 changes: 17 additions & 0 deletions lib/i18n/backend/deprecator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

module I18n
module Backend
module Deprecator
def store_translations(locale, data, options = EMPTY_HASH)
super

I18n.config.deprecations.each do |deprecated_key, new_key|
if lookup(locale, deprecated_key)
puts "DEPRECATION WARNING: #{deprecated_key} is deprecated, use #{new_key} instead"
end
end
end
end
end
end
4 changes: 4 additions & 0 deletions lib/i18n/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ def backend=(backend)
@@backend = backend
end

def deprecations
@@deprecations ||= {}
end

# Returns the current default locale. Defaults to :'en'
def default_locale
@@default_locale ||= :en
Expand Down
35 changes: 35 additions & 0 deletions test/backend/deprecator_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require 'test_helper'

class I18nBackendDeprecatorTest < I18n::TestCase
class Backend < I18n::Backend::Simple
include I18n::Backend::Deprecator
include I18n::Backend::Fallbacks
end

def setup
super
I18n.backend = Backend.new
I18n.deprecate(old_key: :new_key)
end

test 'old key defined, new key undefined' do
store_translations(:xx, old_key: 'Hello world')

assert_equal 'Hello world', I18n.t(:old_key, locale: :xx)
assert_equal 'Hello world', I18n.t(:new_key, locale: :xx)
end

test 'old key undefined, new key defined' do
store_translations(:xx, new_key: 'Hello new world')

assert_equal 'Hello new world', I18n.t(:old_key, locale: :xx)
assert_equal 'Hello new world', I18n.t(:new_key, locale: :xx)
end

test 'old key defined, new key defined' do
store_translations(:xx, old_key: 'Hello world', new_key: 'Hello new world')

assert_equal 'Hello world', I18n.t(:old_key, locale: :xx)
assert_equal 'Hello world', I18n.t(:new_key, locale: :xx)
end
end

0 comments on commit 981b12d

Please sign in to comment.