module Idiom #:nodoc:
# Finds English language translation keys which have not been translated
# and translates them through Google Translate.
#
module Directories #:nodoc:
def use_directories?
use_dirs
end
def destination_path(lang)
output_path = File.basename(@base_source).split(".").first
if use_directories?
"#{destination}/#{lang}/#{output_path}_#{lang}.#{extension}"
else
"#{destination}/#{output_path}_#{lang}.#{extension}"
end
end
def ensure_destination_path_exists(lang)
dest = destination_path(lang)
dir = File.dirname(dest)
FileUtils.mkdir_p(dir)
dest
end
def destination_file_or_directory(lang)
if use_directories?
dir = File.dirname(destination_path(lang))
"#{dir}/*.#{extension}"
else
destination_path(lang)
end
end
end
module Locales #:nodoc:
# Mapping of the I18n country codes with the Google Translate codes.
#
# The key is the I18n representation, and the value is the code Google Translate would expect.
#
LOCALES = YAML.load_file("./config/locales.yml")
# locales
def non_us_locales
@non_us_locales ||= locales.select do |lang|
lang != "en-US"
end
end
def locales
@languages || LOCALES.keys
end
end
module Processing #:nodoc:
def pre_process(value, lang)
vars = []
index = 0
while value =~ /(\{\d+\})/
vars << $1
value.sub!(/(\{\d+\})/, "[#{index}]")
index += 1
end
if lang !~ /^en/ && value != value.downcase
value = value.capitalize
end
value
end
def post_process(value, lang)
if lang =~ /zh/
value.gsub!("", "")
value.gsub!("", "")
end
value.gsub!(/^#{194.chr}#{160.chr}/, "")
value.gsub!(" ]", "]")
value.gsub!("«", "\"")
value.gsub!("»", "\"")
value.gsub!(/\"\.$/, ".\"")
value.gsub!(/\\ \"/, "\\\"")
value.gsub!(/<\/ /, "<\/")
value.gsub!(/(“|”)/, "\"")
value.gsub!(" ", "")
value.gsub!(" ", "")
value.gsub!(""", "\"")
value.gsub!("'", "\"")
value.gsub!("> ", ">")
value.gsub!("\"", "'")
value.gsub!(" \"O", " \\\"O")
while value =~ /\[(\d)\]/
index = $1.to_i
value.sub!(/\[#{index}\]/, "{#{index}}")
end
value.gsub!(/\((0)\)/, "{0}")
value.gsub!(/\((1)\)/, "{1}")
value.gsub!(/\((2)\)/, "{2}")
value.gsub!("(0)", "{0}")
value.strip
end
end
module ClassMethods #:nodoc:
def translate(options={})
options.stringify_keys!
@source = options["source"]
@destination = options["destination"]
@use_dirs = options["use_dirs"]
Timer.new.time do
find_and_translate_all(options)
end
end
def source_files
if @source =~ /\.(yml|pres)$/
source_files = Dir[@source]
else
dir = File.expand_path(@source)
source_files = Dir["#{dir}/**/*_en-US.pres"] + Dir["#{dir}/**/*_en-US.yml"]
source_files.flatten
end
end
def find_and_translate_all(options={})
options.stringify_keys!
source_files.each do |path|
$stdout.puts "Processing #{path}"
translate_file(path, options)
end
end
def translate_file(path, options={})
options.stringify_keys!
if path =~ /\.yml$/i
Idiom::Yaml.new(options.merge({"source" => path})).generate
end
if path =~ /\.pres$/i
Idiom::Yrb.new(options.merge({"source" => path})).generate
end
end
end
class Base
extend Idiom::ClassMethods
include Idiom::Directories
include Idiom::Locales
include Idiom::Processing
# Original filename to translate.
#
attr_accessor :source
# Destination directory to output the translated files to.
#
attr_accessor :destination
# Write the translated strings into a directory for each language?
#
attr_accessor :use_dirs
# Array of languages to translate into.
#
attr_accessor :languages
def initialize(options={})
options.stringify_keys!
@source = File.expand_path(options["source"])
@overwrite = options["overwrite"]
@languages = options["languages"]
@base_source = @source.gsub(/_en-US/, "")
# base directory of the source file
#
@source_dir = File.dirname(@source)
# if they specify the :use_dirs option, use that
# if not, detect whether the source path uses directories for each language
#
if options.has_key?("use_dirs")
@use_dirs = options["use_dirs"]
else
@use_dirs = @source_dir =~ /\/en-US$/
end
if @use_dirs
@source_dir = File.dirname(@source).gsub(/\/en-US$/, "")
end
@destination = options["destination"] || @source_dir
end
def generate
non_us_locales.each do |lang|
code = LOCALES[lang]
destination = ensure_destination_path_exists(lang)
new_content = each_line do |line|
copy_and_translate_line(line, lang)
end
write_content(destination, new_content)
clear_all_keys
end
end
def new_translation_message
now = Time.now
date = now.day
month = now.month
year = now.year
timestamp = "#{month}/#{date}/#{year}"
output = []
output << "# "
output << "# Keys translated automatically on #{timestamp}."
output << "# "
output.join("\n")
end
def each_line
output = []
@lines ||= File.readlines(source)
@lines.each do |line|
new_line = yield line
output << new_line
end
output.compact.join("\n")
end
def parse(p)
raise "Define in child"
end
def all_keys(lang)
unless @all_keys
@all_keys = {}
Dir[destination_file_or_directory(lang)].each do |path|
if File.exists?(path)
keys = parse(path)
@all_keys = @all_keys.merge(keys)
end
end
end
@all_keys
end
def clear_all_keys
@all_keys = nil
end
def write_content(destination, content)
unless content.blank?
$stdout.puts "Writing to #{destination}"
$stdout.puts content
$stdout.puts
File.open(destination, "a") do |f|
f.puts
f.puts new_translation_message
f.puts content
end
end
end
def copy_and_translate_line(line, lang)
line = line.split("\n").first
if comment?(line) || line.blank?
nil
else
translate_new_key(line, lang)
end
end
def key_is_new?(k, lang)
k && !all_keys(lang).has_key?(k)
end
def translate_new_key(line, lang)
k, v = key_and_value_from_line(line)
if @overwrite || key_is_new?(k, lang)
translation = translate(v, lang)
if translation == "Error: invalid result data"
return nil
end
format(k, translation)
else
nil
end
end
def translate(value, lang)
$stdout.puts("Translating #{value} into #{lang}...")
code = LOCALES[lang]
value = pre_process(value, lang)
translation = Translate.t(value, "ENGLISH", code)
value = post_process(translation, lang)
$stdout.puts("value: #{value}")
sleep(5)
value
end
def format(key, value)
raise "Define in child"
end
def key_and_value_from_line(line)
raise "Define in child"
end
def comment?(line)
line =~ /^[\s]*#/
end
end
end