I made a little rake task to allow you to scrape your views for translation calls, and also run through models and generate locale files. The model scraping allows the resulting file to be used with formtastic.
There are plenty of comments in the code, but if anyone has questions or problems please comment.
require 'find'
class Hash
# sets value at a dot seperated key path
# key = 'general.name' = hash[:general][:name]
def set_value_for_key(key, value)
key_parts = key.split('.')
if key_parts.length > 1
key_part = key_parts[0]
new_key = key_parts[1..-1].join('.')
self[key_part] ||= {}
self[key_part].set_value_for_key(new_key, value)
else
self[key] = value
end
end
end
module I18n
def self.translation_exception(*args)
locale = args[1] # => :en
key = args[2] # => 'general.name'
#load existing locale data
locale_file = Rails.root.join("config/locales/#{locale}.yml")
data = YAML.load_file(locale_file) if File.exists?(locale_file)
data ||= {}
# normalise the key
normalized_key = I18n.normalize_keys(locale, key, []) # => [:general,:name]
# used for the value if
value_text = normalized_key[-1] # => :name
# add to the hash
data.set_value_for_key(normalized_key.join('.'), value_text.to_s.humanize)
# save
File.open(locale_file, "w") {|f| f.write( data.to_yaml) }
end
end
# override default exception for translation exceptions
# this allows us to process missing translation with the above code
I18n.exception_handler = :translation_exception
namespace :translations do
desc "Update translation yaml from views"
task :from_views => :environment do
assets = []
#get all the view files
Find.find(Rails.configuration.view_path) do |view|
if File.file?(view) && File.extname(view) == '.erb'
File.readlines(view).each do |line|
#look for t or I18n.t calls on each line, and append to assets
assets += line.scan(/\st\(([^,\)]*)/).flatten
assets += line.scan(/\sI18n.t\(([^,\)]*)/).flatten
end
end
end
#clean the keys up
assets.map!{|a| a.gsub("'","").gsub(':','')}
#sort so deep keys are last
assets.sort!{|x,y| x.scan('.').count <=> y.scan('.').count}
#for each locale
I18n.available_locales.each do |locale|
I18n.locale = locale
#attempt to call translate for each key
assets.each do |translation_key|
I18n.t(translation_key)
end
end
end
desc "Update translation yaml from models"
task :from_models => :environment do
#require the model files so rails is aware of the model
Find.find(Rails.root.join('app/models')) do |model_file|
if File.file?(model_file) && File.extname(model_file) == '.rb'
require model_file
end
end
#for each available locale
I18n.available_locales.each do |locale|
I18n.locale = locale
#and each available model
ActiveRecord::Base.descendants.each do |model|
#in my case some models are for extension only and will not have a table
#so using a rescue block lets the code keep on going
begin
model_name = model.name.underscore
#for each column, try to access the translation
model.columns.each do |col|
I18n.t("activerecord.attributes.#{model_name}.#{col.name}".trim)
end
rescue Exception => ex
#do nothing
end
end
end
end
desc "Update translation yaml from all sources"
task :from_all => [:from_views, :from_models]
end










