lib/localeapp/updater.rb
require 'fileutils'
module Localeapp
class Updater
def update(data)
data['locales'].each do |short_code|
filename = File.join(Localeapp.configuration.translation_data_directory, "#{short_code}.yml")
if File.exist?(filename)
translations = Localeapp.load_yaml_file(filename)
if data['translations'] && data['translations'][short_code]
new_data = { short_code => data['translations'][short_code] }
translations = deep_merge translations, new_data
end
else
translations = { short_code => data['translations'][short_code] }
end
if data['deleted']
data['deleted'].each do |key|
remove_flattened_key!(translations, short_code, key)
end
end
if translations[short_code]
atomic_write(filename) do |file|
file.write generate_yaml(translations)
end
end
end
end
def dump(data)
data.each do |locale, translations|
filename = File.join(Localeapp.configuration.translation_data_directory, "#{locale}.yml")
atomic_write(filename) do |file|
file.write generate_yaml({locale => translations})
end
end
end
private
def deep_merge(original, other)
original.merge other do |_, a, b|
if Hash === a && Hash === b
deep_merge a, b
else
b
end
end
end
def generate_yaml(translations)
YAML.dump(translations, :line_width => -1)[4..-1]
end
def remove_flattened_key!(hash, locale, key)
keys = I18n.normalize_keys(locale, key, '').map(&:to_s)
current_key = keys.shift
remove_child_keys!(hash[current_key], keys)
hash
end
def remove_child_keys!(sub_hash, keys)
return if sub_hash.nil?
current_key = keys.shift
if keys.empty?
# delete key except if key is now used as a namespace for a child_hash
unless sub_hash[current_key].is_a?(Hash)
sub_hash.delete(current_key)
end
else
child_hash = sub_hash[current_key]
unless child_hash.nil?
remove_child_keys!(child_hash, keys)
if child_hash.empty?
sub_hash.delete(current_key)
end
end
end
end
# originally from ActiveSupport
def atomic_write(file_name, temp_dir = Dir.tmpdir)
target_dir = File.dirname(file_name)
unless File.directory?(target_dir)
raise "Could not write locale file, please make sure that #{target_dir} exists and is writable"
end
permissions = File.stat(file_name).mode if File.exist?(file_name)
temp_file = Tempfile.new(File.basename(file_name), temp_dir)
yield temp_file
temp_file.close
# heroku has /tmp on a different fs
# so move first to sure they're on the same fs
# so rename will work
FileUtils.mv(temp_file.path, "#{file_name}.tmp")
File.rename("#{file_name}.tmp", file_name)
# chmod the file to its previous permissions
# or set default permissions to 644
File.chmod(permissions ? permissions : 0644 , file_name)
end
end
end