Mind Dump, Tech And Life Blog
written by Ivan Alenko
published under license Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)copy! share!
posted at 08. Feb '18

Howto: Extending FastGettext with custom translation repository

Scenario: I want to have translations for one language in more files than one file. Current FastGettext::TranslationRepository::Yaml can’t handle this. So we create our own Yamlr module.

Readme.md tells something about custom modules, but one must be skilled to understand how to use this knowledge. This howto aims to fill this gap.

1. Modify load path

I know how to do this in Rails.

~~~ruby # add to config/application.rb config.autoload_paths += %W(#{config.root}/lib) ~~~

This won’t load all files from /lib directory, but tells Rails where to search when you call require function.

2. Add module to new load path

Create lib/fast_gettext/translation_repository in Rails application. Now we move our yaml_recursive.rb here. Yes, only one file here.

The source is modified version of the original Yaml module:

~~~`ruby require ‘fast_gettext/translation_repository/base’ require ‘yaml’ require ‘active_support/core_ext/hash/deep_merge.rb’

module FastGettext module TranslationRepository # Responsibility: # - find and store yaml files # - provide access to translations in yaml files class Yamlr < Base def initialize(name,options={}) super reload end

  def available_locales
    @files.keys
  end

  def plural(*keys)
    ['one', 'other', 'plural2', 'plural3'].map do |name|
      self[yaml_dot_notation(keys.first, name)]
    end
  end

  def pluralisation_rule
    self['pluralisation_rule'] ? lambda{|n| eval(self['pluralisation_rule']) } : nil
  end

  def reload
    find_and_store_files(@options)
    super
  end

  protected

  MAX_FIND_DEPTH = 10

  def find_and_store_files(options)
    @files = {}
    path = options[:path] || 'config/locales'
    Dir["#{path}/**/*.yml"].each do |yaml_file|
				@files.deep_merge!(load_yaml(yaml_file))
    end
			@files
  end

  def current_translations
    @files[FastGettext.locale] || super
  end

  # Given a yaml file return a hash of key -> translation
  def load_yaml(file)
    yaml = YAML.load_file(file)
			yaml.keys.reduce({}) do |processed, locale|
				processed[locale] ||= {}
				processed[locale].merge!(yaml_hash_to_dot_notation(yaml[locale]))
				processed
			end
  end

  def yaml_hash_to_dot_notation(yaml_hash)
    add_yaml_key({}, nil, yaml_hash)
  end

  def add_yaml_key(result, prefix, hash)
    hash.each_pair do |key, value|
      if value.kind_of?(Hash)
        add_yaml_key(result, yaml_dot_notation(prefix, key), value)
      else
        result[yaml_dot_notation(prefix, key)] = value
      end
    end
    result
  end

  def yaml_dot_notation(a,b)
    a ? "#{a}.#{b}" : b
  end
end   end end ~~~`

Now we can read I18n translations too. To use these translations with fast_gettext you need to override calls to I18n. (TODO how?)

3. Enjoy

~~~`ruby rails c

… require ‘fast_gettext/translation_repository/yaml_recursive’ #=> true FastGettext.add_text_domain(‘lala’, path: ‘config/locales’, type: :yamlr) #=> { …our translations … } ~~~`

4. Debug

From the initializer:

~~~ruby puts FastGettext.add_text_domain('lala', path: 'config/locales', type: :yamlr).inspect ~~~

Add Comment