missing_t 0.4.0 → 0.4.1
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/Gemfile.lock +1 -1
- data/lib/missing_t.rb +68 -34
- data/spec/acceptance/missing_t_spec.rb +10 -5
- data/spec/missing_t_spec.rb +10 -10
- data/spec/support/new.html.erb +5 -5
- metadata +4 -4
data/Gemfile.lock
CHANGED
data/lib/missing_t.rb
CHANGED
@@ -1,19 +1,24 @@
|
|
1
1
|
require "yaml"
|
2
2
|
|
3
3
|
#TODO: Should I feel about these 'global' helper functions?
|
4
|
-
def hashify(
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
def hashify(segments, value)
|
5
|
+
return {} if segments.empty?
|
6
|
+
s, *rest = segments
|
7
|
+
if rest.empty?
|
8
|
+
{ s => value }
|
9
|
+
else
|
10
|
+
{ s => hashify(rest, value) }
|
10
11
|
end
|
11
12
|
end
|
12
13
|
|
13
14
|
def print_hash(h, level)
|
14
15
|
h.each_pair do |k,v|
|
15
|
-
|
16
|
-
|
16
|
+
if v.respond_to?(:each_pair)
|
17
|
+
puts %(#{" " * (level*2)}#{k}:)
|
18
|
+
print_hash(v, level+1)
|
19
|
+
else
|
20
|
+
puts %(#{" " * (level*2)}#{k}: #{v})
|
21
|
+
end
|
17
22
|
end
|
18
23
|
end
|
19
24
|
|
@@ -23,8 +28,8 @@ class Hash
|
|
23
28
|
self.merge(other_hash) do |key, oldval, newval|
|
24
29
|
oldval = oldval.to_hash if oldval.respond_to?(:to_hash)
|
25
30
|
newval = newval.to_hash if newval.respond_to?(:to_hash)
|
26
|
-
if oldval
|
27
|
-
if newval
|
31
|
+
if oldval.is_a? Hash
|
32
|
+
if newval.is_a? Hash
|
28
33
|
oldval.deep_safe_merge(newval)
|
29
34
|
else
|
30
35
|
oldval
|
@@ -45,13 +50,13 @@ class MissingT
|
|
45
50
|
|
46
51
|
class FileReader
|
47
52
|
def read(file)
|
48
|
-
|
49
|
-
yield
|
53
|
+
IO.readlines(file).each do |line|
|
54
|
+
yield line
|
50
55
|
end
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
54
|
-
VERSION = "0.4.
|
59
|
+
VERSION = "0.4.1"
|
55
60
|
|
56
61
|
def initialize(options={})
|
57
62
|
@reader = options.fetch(:reader, FileReader.new)
|
@@ -60,11 +65,11 @@ class MissingT
|
|
60
65
|
end
|
61
66
|
|
62
67
|
def run
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
+
missing = {}
|
69
|
+
collect_missing.each do |file, message_strings|
|
70
|
+
message_strings.each do |message_string, value|
|
71
|
+
missing.deep_safe_merge! hashify(message_string.split('.'), value)
|
72
|
+
end
|
68
73
|
end
|
69
74
|
|
70
75
|
missing.each do |language, missing_for_language|
|
@@ -74,7 +79,7 @@ class MissingT
|
|
74
79
|
end
|
75
80
|
end
|
76
81
|
|
77
|
-
def
|
82
|
+
def collect_missing
|
78
83
|
ts = translation_keys
|
79
84
|
#TODO: If no translation keys were found and the languages were not given explicitly
|
80
85
|
# issue a warning and bail out
|
@@ -84,9 +89,9 @@ class MissingT
|
|
84
89
|
|
85
90
|
def get_missing_translations(keys, queries, languages)
|
86
91
|
languages.each_with_object({}) do |lang, missing|
|
87
|
-
|
88
|
-
missing[file] ||=
|
89
|
-
missing[file].
|
92
|
+
get_missing_translations_for_language(keys, queries, lang).each do |file, queries_for_language|
|
93
|
+
missing[file] ||= {}
|
94
|
+
missing[file].merge!(queries_for_language)
|
90
95
|
end
|
91
96
|
end
|
92
97
|
end
|
@@ -144,30 +149,59 @@ class MissingT
|
|
144
149
|
end
|
145
150
|
|
146
151
|
def extract_i18n_queries(file)
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
([]).tap do |i18n_message_strings|
|
152
|
-
i18n_message_strings.concat content.scan(i18n_query_pattern).map { |match| match[0].gsub(/['"\s]/, '') }
|
153
|
-
i18n_message_strings.concat content.scan(i18n_query_no_parens_pattern).map { |match| match[1].gsub(/['"\s]/, '') }
|
152
|
+
({}).tap do |queries|
|
153
|
+
@reader.read(File.expand_path(file)) do |line|
|
154
|
+
qs = scan_line(line)
|
155
|
+
queries.merge!(qs)
|
154
156
|
end
|
155
157
|
end
|
156
158
|
end
|
157
159
|
|
158
160
|
private
|
159
161
|
|
160
|
-
def
|
161
|
-
queries.
|
162
|
-
queries_with_no_translation = queries_in_file.reject { |q| has_translation?(keys,
|
162
|
+
def get_missing_translations_for_language(keys, queries, l)
|
163
|
+
queries.each_with_object({}) do |(file, queries_in_file), missing_translations|
|
164
|
+
queries_with_no_translation = queries_in_file.reject { |q, _| has_translation?(keys, l, q) }
|
163
165
|
if queries_with_no_translation.any?
|
164
|
-
[file
|
166
|
+
missing_translations[file] = add_langauge_prefix(queries_with_no_translation, l)
|
165
167
|
end
|
166
|
-
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def add_langauge_prefix(qs, l)
|
172
|
+
qs.each_with_object({}) do |(q, v), with_prefix|
|
173
|
+
with_prefix["#{l}.#{q}"] = v
|
174
|
+
end
|
167
175
|
end
|
168
176
|
|
169
177
|
def i18n_label(lang, query)
|
170
178
|
"#{lang}.#{query}"
|
171
179
|
end
|
172
180
|
|
181
|
+
def scan_line(line)
|
182
|
+
with_parens = /[^\w]+(?:I18n\.translate|I18n\.t|translate|t)\s*\((['"](.*?)['"].*?)\)/
|
183
|
+
no_parens = /[^\w]+(?:I18n\.translate|I18n\.t|translate|t)\s+(['"](.*?)['"].*?)/
|
184
|
+
[with_parens, no_parens].each_with_object({}) do |pattern, extracted_queries|
|
185
|
+
line.scan(pattern).each do |m|
|
186
|
+
if m.any?
|
187
|
+
message_string = m[1]
|
188
|
+
_, *options = m[0].split(',')
|
189
|
+
extracted_queries[message_string] = extract_default_value(options)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def extract_default_value(message_string_options)
|
196
|
+
[/:default\s*=>\s*['"](.*)['"]/, /default:\s*['"](.*)['"]/].each do |default_extractor|
|
197
|
+
message_string_options.each do |option|
|
198
|
+
if default_key_match=default_extractor.match(option)
|
199
|
+
return default_key_match[1]
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
''
|
204
|
+
end
|
205
|
+
|
206
|
+
|
173
207
|
end
|
@@ -3,10 +3,15 @@ require_relative '../spec_helper'
|
|
3
3
|
describe "MissingT" do
|
4
4
|
describe "correctly finds all missing translations" do
|
5
5
|
m = MissingT.new({ languages: ["en"], path: "spec/support/new.html.erb" })
|
6
|
-
m.
|
7
|
-
"en.flights.new.new_flight"
|
8
|
-
"en.flights.new.
|
9
|
-
"en.flights.new.
|
10
|
-
|
6
|
+
m.collect_missing['spec/support/new.html.erb'].should == {
|
7
|
+
"en.flights.new.new_flight" => "",
|
8
|
+
"en.flights.new.name" => "Name",
|
9
|
+
"en.flights.new.capacity" => "Capacity",
|
10
|
+
"en.flights.new.duration" => "Duration",
|
11
|
+
"en.flights.new.from" => "From",
|
12
|
+
"en.flights.new.to" => "",
|
13
|
+
"en.flights.new.create" => "Create",
|
14
|
+
"en.flights.new.back" => "Back"
|
15
|
+
}
|
11
16
|
end
|
12
17
|
end
|
data/spec/missing_t_spec.rb
CHANGED
@@ -32,25 +32,25 @@ describe "MissingT" do
|
|
32
32
|
content = <<-EOS
|
33
33
|
<div class="title_gray"><span><%= I18n.t("anetcom.member.projects.new.page_title") %></span></div>
|
34
34
|
EOS
|
35
|
-
@missing_t.extract_i18n_queries(content).should ==
|
35
|
+
@missing_t.extract_i18n_queries(content).should == {"anetcom.member.projects.new.page_title" => ""}
|
36
36
|
end
|
37
37
|
it "should correctly extract the key not right after the <%= mark" do
|
38
38
|
content = <<-EOS
|
39
39
|
<%= submit_tag I18n.t('anetcom.member.projects.new.create_project'), :class => 'button' %>
|
40
40
|
EOS
|
41
|
-
@missing_t.extract_i18n_queries(content).should ==
|
41
|
+
@missing_t.extract_i18n_queries(content).should == {"anetcom.member.projects.new.create_project" => ""}
|
42
42
|
end
|
43
43
|
|
44
44
|
it "should correctly extract the key when there is an argument in the call" do
|
45
45
|
content = <<-EOS
|
46
46
|
:html => {:title => I18n.t("tog_social.sharing.share_with", :name => shared.name)}
|
47
47
|
EOS
|
48
|
-
@missing_t.extract_i18n_queries(content).should ==
|
48
|
+
@missing_t.extract_i18n_queries(content).should == {"tog_social.sharing.share_with" => ""}
|
49
49
|
end
|
50
50
|
|
51
51
|
it "should find and correctly extract a dynamic key translation message" do
|
52
52
|
content = %q(<div class="title_gray"><span><%= I18n.t("mycompany.welcome.#{key}") %></span></div>)
|
53
|
-
@missing_t.extract_i18n_queries(content).should ==
|
53
|
+
@missing_t.extract_i18n_queries(content).should == {%q(mycompany.welcome.#{key}) => ""}
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -59,21 +59,21 @@ describe "MissingT" do
|
|
59
59
|
content = <<-EOS
|
60
60
|
<div class="title_gray"><span><%= t("anetcom.member.projects.new.page_title") %></span></div>
|
61
61
|
EOS
|
62
|
-
@missing_t.extract_i18n_queries(content).should ==
|
62
|
+
@missing_t.extract_i18n_queries(content).should == {"anetcom.member.projects.new.page_title" => ""}
|
63
63
|
end
|
64
64
|
|
65
65
|
it "should find several messages on the same line" do
|
66
66
|
content = <<-EOS
|
67
|
-
|
67
|
+
<div class="title_gray"><span><%= t("anetcom.member.projects.new.page_title") %></span><span>t("anetcom.member.projects.new.page_size")</span></div>
|
68
68
|
EOS
|
69
|
-
@missing_t.extract_i18n_queries(content).should ==
|
69
|
+
@missing_t.extract_i18n_queries(content).should == {"anetcom.member.projects.new.page_title" => "", "anetcom.member.projects.new.page_size" => ""}
|
70
70
|
end
|
71
71
|
|
72
72
|
it "should find messages with a parens-less call" do
|
73
73
|
content = <<-EOS
|
74
74
|
<div class="title_gray"><span><%= t "anetcom.member.projects.new.page_title" %></span></div>
|
75
75
|
EOS
|
76
|
-
@missing_t.extract_i18n_queries(content).should ==
|
76
|
+
@missing_t.extract_i18n_queries(content).should == {"anetcom.member.projects.new.page_title" => ""}
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
@@ -81,14 +81,14 @@ describe "MissingT" do
|
|
81
81
|
content = <<-EOS
|
82
82
|
<div class="title_gray"><span><%= I18n.translate("anetcom.member.projects.new.page_title") %></span></div>
|
83
83
|
EOS
|
84
|
-
@missing_t.extract_i18n_queries(content).should ==
|
84
|
+
@missing_t.extract_i18n_queries(content).should == {"anetcom.member.projects.new.page_title" => ""}
|
85
85
|
end
|
86
86
|
|
87
87
|
it "should not extract a function call that just ends in t" do
|
88
88
|
content = <<-EOS
|
89
89
|
<div class="title_gray"><span><%= at(3) %></span></div>
|
90
90
|
EOS
|
91
|
-
@missing_t.extract_i18n_queries(content).should ==
|
91
|
+
@missing_t.extract_i18n_queries(content).should == {}
|
92
92
|
end
|
93
93
|
|
94
94
|
end
|
data/spec/support/new.html.erb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
|
-
<h1><%= I18n.t("flights.new.new_flight"
|
1
|
+
'<h1><%= I18n.t("flights.new.new_flight") %></h1>'
|
2
2
|
|
3
3
|
<% form_for(@flight) do |f| %>
|
4
4
|
<%= f.error_messages %>
|
5
5
|
|
6
6
|
<p>
|
7
|
-
<%= f.label I18n.t("flights.new.name", :default => "
|
7
|
+
<%= f.label I18n.t("flights.new.name", :default => "Name") %><br />
|
8
8
|
<%= f.text_field :name %>
|
9
9
|
</p>
|
10
10
|
<p>
|
11
|
-
<%= f.label I18n.t("flights.new.capacity", :default => "
|
11
|
+
<%= f.label I18n.t("flights.new.capacity", :default => "Capacity") %><br />
|
12
12
|
<%= f.text_field :capacity %>
|
13
13
|
</p>
|
14
14
|
<p>
|
15
|
-
<%= f.label I18n.t("flights.new.duration", :default => "
|
15
|
+
<%= f.label I18n.t("flights.new.duration", :default => "Duration") %><br />
|
16
16
|
<%= f.text_field :duration %>
|
17
17
|
</p>
|
18
18
|
<p>
|
@@ -20,7 +20,7 @@
|
|
20
20
|
<%= f.select :from_id, @airport_options %>
|
21
21
|
</p>
|
22
22
|
<p>
|
23
|
-
<%= f.label :to_id, I18n.t("flights.new.to"
|
23
|
+
<%= f.label :to_id, I18n.t("flights.new.to") %><br />
|
24
24
|
<%= f.select :to_id, @airport_options %>
|
25
25
|
</p>
|
26
26
|
<p>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: missing_t
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -152,7 +152,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
152
152
|
version: '0'
|
153
153
|
segments:
|
154
154
|
- 0
|
155
|
-
hash:
|
155
|
+
hash: -2158977663221811532
|
156
156
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
157
|
none: false
|
158
158
|
requirements:
|
@@ -161,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
161
161
|
version: '0'
|
162
162
|
segments:
|
163
163
|
- 0
|
164
|
-
hash:
|
164
|
+
hash: -2158977663221811532
|
165
165
|
requirements: []
|
166
166
|
rubyforge_project:
|
167
167
|
rubygems_version: 1.8.23
|