Skip to content
Gem for automatic creation i18n keys in your YAML files as you develop
Find file



I18n translation spawner (ITS) addresses the issue of having to add translation keys to multiple translation files
manually as you develop an app.

Whenever I18n::MissingTranslationData exception is caught, ITS tries to add a new key into your translation file,
generates new translation for it and does it within all locales you have defined in your app.


Nothing fancy, just add gem 'i18n_translation_spawner' and run bundle install

Then add following line in an initializer, (e.g. /config/initializers/i18n.rb)

    I18n.exception_handler =


There is a number customizations possible to achieve with ITS

Automatic translations

If you want some keys being translated in a specific way, you can add those to default_translations

    translations_spawner =

    translations_spawner.default_translations = {"new.button_submit" => "Create",
    "edit.button_submit" => "Save changes",
    "save" => {"en-GB" => "Save", "nb-NO" => "Lagre" }}

    I18n.exception_handler = translations_spawner

Then for instance the following key will be automatically assigned with translation of “Create”

Automatic prefix removal

By default ITS humanizes the last part of key (“link_new_candidate” becomes “Link new candidate”).
If you want to automatically strip some of prefixes before humanization occurs, specify those in removable_prefixes

    translations_spawner =

    translations_spawner.removable_prefixes = %w(link table_header label header)

    I18n.exception_handler = translations_spawner

Then for instance the following key will be automatically assigned with translation of “New candidate”

Skipping some locale during automatic key spawning

As easy as

 translations_spawner =

 translations_spawner.skip_locales =["nb-NO"]

 I18n.exception_handler = translations_spawner

Hacking automatic key translations

For instance, you can try handling translations to different languages automatically.
Note, that this code is not super-duper-awesome. It just shows the basic how-to

translations_spawner =

require "net/http"
require "json"
require "iconv"
translations_spawner.key_translations_handler = lambda do |key, locale, spawner|
    default = spawner.default_translation_for_key(key, locale)

        source_language = 'en'
        target_language = locale.split('-').first.downcase

        target_language = case target_language
            when 'nb' then

        json_string = Net::HTTP.get('', "/translate_a/t?client=t&text=#{default}&hl=#{target_language}&sl=#{source_language}&tl=#{target_language}&multires=1&otf=1&ssel=0&tsel=0&sc=1").gsub(/,{2,}/, ',')
        ic ='UTF-8//IGNORE', 'UTF-8')
        valid_string = ic.iconv(json_string)

        return JSON.parse(valid_string).flatten.first
I18n.exception_handler = translations_spawner

Hacking file selection

If you have more complex structure of yaml files placement, you can always add some custom logic for it.
In this example, the first part of key can be a directory name, and in case of no directory with that name, it can be a file name.
If the directory is found, the second part of key is the file name within it (imagine having files like common.en-GB.yml and customer/common.en-GB.yml)

    translations_spawner =
    translations_spawner.file_path_decoder = lambda do |key, locale, _|
        tokens = key.to_s.split('.')
        file_path_tokens = if File.file?(File.join(Rails.root, 'config', 'locales', tokens.first, "#{tokens.second}.#{locale.to_s}.yml"))
        elsif File.file?(File.join(Rails.root, 'config', 'locales', "#{tokens.first}.#{locale.to_s}.yml"))
        raise I18n::TranslationSpawner::CannotDecodeTranslationFilePath unless file_path_tokens
        File.join(Rails.root, "config/locales", *file_path_tokens)+".#{locale.to_s}.yml"
    I18n.exception_handler = translations_spawner

Hacking exception catching

If you have some custom translation inheritance mechanism that is based on catching I18n::MissingTranslationData, you can always
incorporate it as well. In this case, the prefix is being stripped and translating re-attempted before re-raising an exception.

    translations_spawner =
    translations_spawner.exception_handler = lambda do |exception, locale, key, spawner, options|
        if exception.is_a?(I18n::MissingTranslationData) and %w(customer admin).include?(key.to_s.split('.').first)
            I18n.translate((key.to_s.split('.')[1..-1].join('.')), options.merge({:raise => true})) rescue spawner.handle_exception(exception, locale, key, options)
            spawner.handle_exception(exception, locale, key, options)
    I18n.exception_handler = translations_spawner
Something went wrong with that request. Please try again.