I am currently wrapping up a client-project where I am preparing a Rails application for internationalization. The application is currently in English and I am translating it to Danish as a proof of concept.
I am using the I18n::Simple backend and the resulting Danish locale file is now at 2100 lines. That’s a bit much for me to keep in my head at once, so I created a small Rake task that takes all locales in your Rails application and reports back all the keys that are missing from one or more locales. Works wonders for finding those typos or oversights that would otherwise result in ‘missing translation data’ messages.
$ rake i18n:missing_keys
2 locales available: en and da
1474 unique keys found.
139 keys are missing from one or more locales:
'activerecord.attributes.category.description': Missing from en
'activerecord.attributes.person.last_name': Missing from en
'countries.Albania': Missing from en
'countries.Algeria': Missing from en
Just put the following in a .rake file in your lib/tasks directory and Rake should pick it up automagically:
namespace :i18n do
desc "Find and list translation keys that do not exist in all locales"
task :missing_keys => :environment do
def collect_keys(scope, translations)
full_keys = []
translations.to_a.each do |key, translations|
new_scope = scope.dup << key
if translations.is_a?(Hash)
full_keys += collect_keys(new_scope, translations)
else
full_keys << new_scope.join('.')
end
end
return full_keys
end
# Make sure we've loaded the translations
I18n.backend.send(:init_translations)
puts "#{I18n.available_locales.size} #{I18n.available_locales.size == 1 ? 'locale' : 'locales'} available: #{I18n.available_locales.to_sentence}"
# Get all keys from all locales
all_keys = I18n.backend.send(:translations).collect do |check_locale, translations|
collect_keys([], translations).sort
end.flatten.uniq
puts "#{all_keys.size} #{all_keys.size == 1 ? 'unique key' : 'unique keys'} found."
missing_keys = {}
all_keys.each do |key|
I18n.available_locales.each do |locale|
I18n.locale = locale
begin
result = I18n.translate(key, :raise => true)
rescue I18n::MissingInterpolationArgument
# noop
rescue I18n::MissingTranslationData
if missing_keys[key]
missing_keys[key] << locale
else
missing_keys[key] = [locale]
end
end
end
end
puts "#{missing_keys.size} #{missing_keys.size == 1 ? 'key is missing' : 'keys are missing'} from one or more locales:"
missing_keys.keys.sort.each do |key|
puts "'#{key}': Missing from #{missing_keys[key].join(', ')}"
end
end
end
Update: This is now available on Github at http://github.com/koppen/i18n_missing_keys.
Very interesting.
There is also a very nice and simple plugin by Peter Marklund to assist you in making translations easier.
I didn't know about that plugin, looks interesting. Looks like the above rake task supplements the tasks from the Translate plugin quite nicely.
I am using your code to get all locales. However, it seems that som keys are missing. The yml file looks like (part of it)
messages:
inclusion: "is not included in the list"
exclusion: "is reserved"
models:
user:
email: "should look like an email addres"
login: "use only letters, numbers, and .-_@ "
name: "avoid non-printing characters"
label_messages:
validates_acceptance_of: 'Must be accepted'
validates_confirmation_of: 'Must be confirmed'
It doe not find the keys sv activerecord errors messages models user email
and not any of the keys for label messages
I have tried with the models part deleted but the result is the same
Any help would be appriciated
Hans, I can't seem to replicate that issue.
I have pushed the above Rake task to Github at http://github.com/koppen/i18n_missing_keys and added some basic tests. I would definitely appreciate a patch or at least a failing test case in order to fix the issue.