i18n-verify 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|