i18n-verify 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/i18n-verify/railtie.rb +11 -0
- data/lib/i18n_verify.rb +111 -0
- data/lib/tasks/i18_verify.rake +97 -0
- metadata +6 -3
data/lib/i18n_verify.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
# the user interface is in rake tasks
|
2
|
+
# for more info see lib/tasks/i18n-verify.rake
|
3
|
+
|
4
|
+
module I18nVerfiy
|
5
|
+
|
6
|
+
require 'i18n-verify/railtie' if defined?(Rails)
|
7
|
+
|
8
|
+
class Checker
|
9
|
+
def initialize(filenames = )
|
10
|
+
@translations = load_files(filenames)
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_key(match=Regexp,new(''), group_by_filename=false)
|
14
|
+
# select translations with matching keys
|
15
|
+
matching_translations = @translations.select {|t| [t[:locale],t[:key]].join('.') =~ regexp}
|
16
|
+
|
17
|
+
# print matching translations
|
18
|
+
if group_by_filename
|
19
|
+
matching_translations.group_by {|t| t[:filename]}.each_pair do |filename, translations|
|
20
|
+
puts "#{filename}:"
|
21
|
+
translations.each do |t|
|
22
|
+
puts " #{[t[:locale],t[:key]].join('.')}: #{t[:translation]}\n"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
else
|
26
|
+
matching_translations.each do |t|
|
27
|
+
puts "#{t[:filename]} # #{[t[:locale],t[:key]].join('.')}: #{t[:translation]}\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def is_complete?(locales_requested = [])
|
33
|
+
# check each pair of locales
|
34
|
+
# if the first one has keys the second one doesn't => these are the incomplete translations
|
35
|
+
locales = @translations.collect{|tr| tr[:locale]}.uniq
|
36
|
+
locales_to_check = locales_requested.empty? ? locales : (locales & locales_requested)
|
37
|
+
|
38
|
+
puts "Checking locales #{locales_to_check.inspect} out of #{locales.inspect} for completeness"
|
39
|
+
locales_to_check.permutation.each do |first, second|
|
40
|
+
first_translations = @translations.select {|translation| translation[:locale] == first}
|
41
|
+
second_translations = @translations.select {|translation| translation[:locale] == second}
|
42
|
+
|
43
|
+
differences = first_translations.select {|f| f if second_translations.none? {|s| f[:key]==s[:key]} }.compact
|
44
|
+
if differences.empty?
|
45
|
+
puts "#{first} => #{second}: complete\n"
|
46
|
+
else
|
47
|
+
puts "Missing from #{second} vs. #{first}:\n"
|
48
|
+
differences.each do |difference|
|
49
|
+
puts " " + [difference[:locale], difference[:key]].join('.') + " defined for #{first} in #{difference[:filename]}\n"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def duplicates(locales_requested = [])
|
56
|
+
locales = @translations.collect{|tr| tr[:locale]}.uniq
|
57
|
+
locales_to_check = locales_requested.empty? ? locales : (locales & locales_requested)
|
58
|
+
|
59
|
+
puts "Checking locales #{locales_to_check.inspect} out of #{locales.inspect} for redundancy"
|
60
|
+
|
61
|
+
# collect and print duplicate translations
|
62
|
+
locales_to_check.each do |locale|
|
63
|
+
puts "#{locale}:"
|
64
|
+
translations_by_key = @translations.select {|t| t[:locale] == locale}.uniq.group_by {|t| t[:key]}
|
65
|
+
translations_by_key.reject {|t| t[1].count == 1}.each_pair do |key, translations|
|
66
|
+
puts " #{key}: #{translations.collect{|t| t[:filename]}.join(", ")}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
# convert translations hash to flat keys
|
73
|
+
# i.e. from { :de => {:new => neue, :old => alt} } to [ ['de.new', 'neue'], ['de.old', 'alte'] ]
|
74
|
+
# and yields a flat key and the value to the block
|
75
|
+
def flatten_keys(hash, prev_key=nil, &block)
|
76
|
+
hash.each_pair do |key, value|
|
77
|
+
curr_key = [prev_key, key].compact.join('.')
|
78
|
+
if value.is_a?(Hash)
|
79
|
+
flatten_keys(value, curr_key, &block)
|
80
|
+
else
|
81
|
+
yield curr_key, value
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# read files and store translations (similar to i18n's internals but include filenames)
|
87
|
+
def load_files(filenames)
|
88
|
+
translations = []
|
89
|
+
filenames.each do |filename|
|
90
|
+
type = File.extname(filename).tr('.', '').downcase.to_sym
|
91
|
+
case type
|
92
|
+
when :rb
|
93
|
+
data = eval IO.read(filename) # , binding, filename)
|
94
|
+
when :yml
|
95
|
+
data = YAML.load_file(filename)
|
96
|
+
else
|
97
|
+
raise I18n::UnknownFileType.new(type, filename)
|
98
|
+
end
|
99
|
+
raise I18n::InvalidLocaleData.new(filename) unless data.is_a?(Hash)
|
100
|
+
data.each_pair do |locale, d|
|
101
|
+
flatten_keys(d || {}) do |flat_key, translation|
|
102
|
+
translations.push({ :filename => filename, :locale => locale.to_s, :key => flat_key, :translation => translation })
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
translations
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
namespace :i18n do
|
2
|
+
|
3
|
+
#
|
4
|
+
# find_key helps to find where certain (partial) keys have translations
|
5
|
+
#
|
6
|
+
# the first parameter is a regexp to look for (beware of period separators!)
|
7
|
+
# the second parameter is a flag if results are to be grouped by file
|
8
|
+
# (the default is one match per line with filename included)
|
9
|
+
#
|
10
|
+
# Examples:
|
11
|
+
# rake find_key[/models/]
|
12
|
+
# rake find_key[/\.models\.attributes/,true]
|
13
|
+
#
|
14
|
+
desc "Find translation keys matching a regexp"
|
15
|
+
task :find_key, :regexp, :group_by_filename do |t, args|
|
16
|
+
require "#{::Rails.root.to_s}/config/environment.rb"
|
17
|
+
regexp = Regexp.new(args[:regexp] || "")
|
18
|
+
group_by_filename = args[:group_by_filename]
|
19
|
+
checker = I18nVerify:Checker.new(I18n.config.load_path)
|
20
|
+
checker.find_key(regexp,group_by_filename)
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# is_complete helps in checking if all translations are set up in all directions
|
25
|
+
# that is: verifies there are no missing keys in any of the trasnlations
|
26
|
+
#
|
27
|
+
# is_complete takes a command line rake param: the list of locales to check (all pairs)
|
28
|
+
# omit for all
|
29
|
+
#
|
30
|
+
# Examples:
|
31
|
+
# rake i18n:is_complete
|
32
|
+
# rake i18n:is_complete locales=en,de
|
33
|
+
#
|
34
|
+
desc "Checks if translations are complete or there are missing ones"
|
35
|
+
task :is_complete do |t, args|
|
36
|
+
require "#{::Rails.root.to_s}/config/environment.rb"
|
37
|
+
translations = load_files( I18n.config.load_path )
|
38
|
+
locales_requested = ENV['locales'].downcase.split(',')
|
39
|
+
checker = I18nVerify:Checker.new(I18n.config.load_path)
|
40
|
+
checker.is_complete?(locales_requested)
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# duplicates helps in finding keys with multiple translations to the same locale
|
45
|
+
#
|
46
|
+
# redundancies takes a command line rake param: the list of locales to check
|
47
|
+
# omit for all
|
48
|
+
#
|
49
|
+
# Examples:
|
50
|
+
# rake i18n:duplicates
|
51
|
+
# rake i18n:duplicates locales=en,de
|
52
|
+
#
|
53
|
+
desc "Checks if any keys are translated multiple times"
|
54
|
+
task :duplicates do |t, args|
|
55
|
+
require "#{::Rails.root.to_s}/config/environment.rb"
|
56
|
+
translations = load_files( I18n.config.load_path )
|
57
|
+
locales_requested = ENV['locales'].downcase.split(',')
|
58
|
+
checker = I18nVerify:Checker.new(I18n.config.load_path)
|
59
|
+
checker.duplicates?(locales_requested)
|
60
|
+
end
|
61
|
+
|
62
|
+
=begin
|
63
|
+
# TODO: write method
|
64
|
+
desc "Checks translations spellings"
|
65
|
+
task :spelling do |t, args|
|
66
|
+
end
|
67
|
+
=end
|
68
|
+
|
69
|
+
desc "Run all checks"
|
70
|
+
task :verify => [:is_complete, :duplicates] do
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# BONUS :)
|
77
|
+
#
|
78
|
+
namespace :yaml do
|
79
|
+
desc "Finds keys in yaml files; regexp to match keys; command line: rake yaml:find[config/locales/**/*.yml,/\.models\./]"
|
80
|
+
task :find, :filename_pattern, :regexp, :group_by_filename do |t, args|
|
81
|
+
filenames = Dir[args[:filename_pattern] || Rails.root.join('**', '*.{yaml,yml}').to_s]
|
82
|
+
regexp = Regexp.new(args[:regexp] || "")
|
83
|
+
group_by_filename = args[:group_by_filename]
|
84
|
+
|
85
|
+
filenames.each do |filename|
|
86
|
+
print filename + ":\n" if group_by_filename
|
87
|
+
|
88
|
+
File.open( filename ) do |infile|
|
89
|
+
yaml_hash = YAML::parse(infile).transform
|
90
|
+
flatten_keys( yaml_hash ) do |key, value|
|
91
|
+
puts "#{group_by_filename ? '' : (filename + ' #')} #{key}: #{value}\n" if key =~ regexp
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: i18n-verify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- fastcatch
|
@@ -28,6 +28,9 @@ extensions: []
|
|
28
28
|
extra_rdoc_files: []
|
29
29
|
|
30
30
|
files:
|
31
|
+
- lib/i18n-verify/railtie.rb
|
32
|
+
- lib/i18n_verify.rb
|
33
|
+
- lib/tasks/i18_verify.rake
|
31
34
|
- LICENSE.txt
|
32
35
|
- README.markdown
|
33
36
|
has_rdoc: true
|