Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
I18n translation with Integers for map keys

Introduction

I18n uses YAML files to store translations, however when using an integer as a map key, the translation is then missing when referenced. This may be unexpected at first, but below describes the translation process, and why it is happening.

Sample YAML file

en:
  1:
    foo: 'bar'

Invokation

I18n.translate('1.foo') #=> "translation missing: en.1.foo"

We might have expected 'bar'

The Problem

  • I18n.translate calls
  • lookup calls
  • I18n.normalize_keys (i18n-0.6.1/lib/i18n.rb:255) calls
  • normalize_key (i18n-0.6.1/lib/i18n.rb:303)

The normalize_key method is shown below:

def normalize_key(key, separator)
  normalized_key_cache[separator][key] ||=
    case key
    when Array
      key.map { |k| normalize_key(k, separator) }.flatten
    else
      keys = key.to_s.split(separator)
      keys.delete('')
      keys.map! { |k| k.to_sym }
      keys
    end
end

Note that this calls key.to_s followed by .to_sym. e.g. normalize_key("1.foo", ".") # => [:"1", :foo]

The translation file is loaded in the lookup method at this time with the key preserved in Integer format. However our lookup key is now: key.to_s.to_sym They integer map key is converted to a symbol, however we are now comparing :"1" with "1" and the translation fails because the key is missing.

TL;DR

Even though YAML supports Integers as map keys - use string representations of Integers as map keys when using I18n

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.