module Aigu class Exporter def initialize(opts = {}) @output_file = opts[:'output-file'] @input_directory = opts[:'input-directory'] @locale = opts[:locale] @ignore = opts[:ignore] end def process! puts "Generating Accent JSON file `#{@output_file}` based on YAML localization files in `#{@input_directory}` directory" if @ignore print 'Ignoring ' puts @ignore.join(', ') end puts '---' build_output write_json_file puts '---' puts 'Done' end protected def build_output @output = {} pattern = File.join(@input_directory, '**', "*.#{@locale}.yml") Dir[pattern].each do |file| filepath = file.gsub(/\A#{@input_directory}\//, '') if ignored_filepath?(filepath) puts "Ignoring #{filepath}" else puts "Processing #{filepath}" content = YAML.load_file(file) base_key = file.gsub(@input_directory, '').gsub(/^\/*/, '').gsub(/\.yml$/, '|') content = flattenize_hash(content, base_key) content = flattenize_content_values(content) content = globalize_content_keys(content) @output.merge! content end end end def write_json_file file_path = @output_file puts "Generating #{file_path}" FileUtils.mkdir_p(File.dirname(file_path)) File.open(file_path, 'w+') do |file| file << @output.to_json end end def globalize_content_keys(content) content.reduce({}) do |memo, (key, value)| globalized_key = key.gsub(/\.#{@locale}\|#{@locale}\./, '|') memo.merge globalized_key => value end end def flattenize_content_values(hash) result = {} hash.reduce({}) do |memo, (key, value)| if value.is_a?(Array) value.each_with_index do |array_value, index| tainted_key = "#{key}___KEY___#{index}" memo[tainted_key] = sanitize_value_to_string(array_value) end else memo[key] = sanitize_value_to_string(value) end memo end end def sanitize_value_to_string(value) case value when true '___TRUE___' when false '___FALSE___' when nil '___NULL___' else value end end def flattenize_hash(hash, base_key = '') if hash.is_a?(Hash) hash.reduce({}) do |memo, (key, value)| new_base_key = [base_key, key].join('.').gsub(/\|\.+/, '|') memo.merge! flattenize_hash(value, new_base_key) end else { base_key => hash } end end def ignored_filepath?(filepath) @ignore && @ignore.any? do |pattern| File.fnmatch(pattern, filepath, File::FNM_PATHNAME | File::FNM_DOTMATCH) end end end end