require "FileUtils" unless defined?(FileUtils)
module SimplesIdeias
module I18n
extend self
require "i18n-js/railtie" if Rails.version >= "3.0"
# deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
MERGER = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &MERGER) : v2 }
def config_file
Rails.root.join("config/i18n-js.yml")
end
def javascript_file
Rails.root.join("public/javascripts/i18n.js")
end
# Export translations to JavaScript, considering settings
# from configuration file
def export!
if config?
for options in config[:translations]
options.reverse_merge!(:only => "*")
if options[:only] == "*"
save translations, options[:file]
else
result = scoped_translations(options[:only])
save result, options[:file] unless result.empty?
end
end
else
save translations, "public/javascripts/translations.js"
end
end
# Load configuration file for partial exporting and
# custom output directory
def config
HashWithIndifferentAccess.new YAML.load_file(config_file)
end
# Check if configuration file exist
def config?
File.file? config_file
end
# Copy configuration and JavaScript library files to
# SimplesIdeias::I18n::CONFIG_FILE and public/i18n.js.
def setup!
FileUtils.cp File.dirname(__FILE__) + "/../source/i18n.js", javascript_file
FileUtils.cp(File.dirname(__FILE__) + "/../source/i18n-js.yml", config_file) unless config?
end
# Retrieve an updated JavaScript library from Github.
def update!
require "open-uri"
contents = open("http://github.com/fnando/i18n-js/raw/master/lib/i18n.js").read
File.open(javascript_file, "w+") {|f| f << contents}
end
# Convert translations to JSON string and save file.
def save(translations, file)
file = Rails.root.join(file)
FileUtils.mkdir_p File.dirname(file)
File.open(file, "w+") do |f|
f << %(var I18n = I18n || {};\n)
f << %(I18n.translations = );
f << sorted_hash(translations).to_json
f << %(;)
end
end
def scoped_translations(scopes) # :nodoc:
result = {}
[scopes].flatten.each do |scope|
deep_merge! result, filter(translations, scope)
end
result
end
# Filter translations according to the specified scope.
def filter(translations, scopes)
scopes = scopes.split(".") if scopes.is_a?(String)
scopes = scopes.clone
scope = scopes.shift
if scope == "*"
results = {}
translations.each do |scope, translations|
tmp = scopes.empty? ? translations : filter(translations, scopes)
results[scope.to_sym] = tmp unless tmp.nil?
end
return results
elsif translations.has_key?(scope.to_sym)
return {scope.to_sym => scopes.empty? ? translations[scope.to_sym] : filter(translations[scope.to_sym], scopes)}
end
nil
end
# Initialize and return translations
def translations
::I18n.backend.instance_eval do
init_translations unless initialized?
translations
end
end
def deep_merge(target, hash) # :nodoc:
target.merge(hash, &MERGER)
end
def deep_merge!(target, hash) # :nodoc:
target.merge!(hash, &MERGER)
end
# Taken from http://seb.box.re/2010/1/15/deep-hash-ordering-with-ruby-1-8/
def sorted_hash(object, deep = false) # :nodoc:
if object.is_a?(Hash)
res = returning(ActiveSupport::OrderedHash.new) do |map|
object.each {|k, v| map[k] = deep ? sorted_hash(v, deep) : v }
end
return res.class[res.sort {|a, b| a[0].to_s <=> b[0].to_s } ]
elsif deep && object.is_a?(Array)
array = Array.new
object.each_with_index {|v, i| array[i] = sorted_hash(v, deep) }
return array
else
return object
end
end
end
end