polint 0.0.3 → 0.2.0
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.
- checksums.yaml +4 -4
- data/.rspec +3 -0
- data/Gemfile.lock +64 -7
- data/Guardfile +14 -0
- data/lib/polint.rb +65 -42
- data/lib/polint/parser.rb +52 -0
- data/lib/polint/transform.rb +64 -0
- data/lib/polint/version.rb +1 -1
- data/polint.gemspec +5 -3
- data/spec/data/ar-valid.po +22 -0
- data/spec/data/en-valid.po +18 -0
- data/spec/data/fr-valid.po +18 -0
- data/spec/data/zh-valid.po +17 -0
- data/spec/lib/polint/parser_spec.rb +258 -0
- data/spec/lib/polint/transform_spec.rb +61 -0
- data/spec/lib/polint_spec.rb +15 -0
- data/spec/spec_helper.rb +12 -0
- metadata +61 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d183c6f2819c7036fef793ace5644f76349b3f24
|
4
|
+
data.tar.gz: e8a9bcda101105ce78e492790021fae4643cc015
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0dbb533fad098c6a220f317b8e88c910e2c80fa8fee04902b934c0f067b66d1f278b77c99319d1f3566d35329362ec5e30d22d14fada4e16b93706eb5b002ce4
|
7
|
+
data.tar.gz: 14b55b4f3a1d6078fe003ff097d6a574c7a77a483b2bcc7d513d8654b565258c375715531c82ccc420753d3bb4e30cde10788986e2a57811bd259948d5c72772
|
data/.rspec
ADDED
data/Gemfile.lock
CHANGED
@@ -1,29 +1,86 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
polint (0.0
|
4
|
+
polint (0.1.0)
|
5
|
+
parslet (~> 1.7, >= 1.7.1)
|
5
6
|
term-ansicolor
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
9
10
|
specs:
|
10
|
-
|
11
|
+
blankslate (3.1.3)
|
12
|
+
byebug (9.0.5)
|
13
|
+
coderay (1.1.1)
|
14
|
+
diff-lcs (1.2.5)
|
15
|
+
ffi (1.9.10)
|
16
|
+
formatador (0.2.5)
|
17
|
+
guard (2.14.0)
|
18
|
+
formatador (>= 0.2.4)
|
19
|
+
listen (>= 2.7, < 4.0)
|
20
|
+
lumberjack (~> 1.0)
|
21
|
+
nenv (~> 0.1)
|
22
|
+
notiffany (~> 0.0)
|
23
|
+
pry (>= 0.9.12)
|
24
|
+
shellany (~> 0.0)
|
25
|
+
thor (>= 0.18.1)
|
26
|
+
guard-compat (1.2.1)
|
27
|
+
guard-rspec (4.7.2)
|
28
|
+
guard (~> 2.1)
|
29
|
+
guard-compat (~> 1.1)
|
30
|
+
rspec (>= 2.99.0, < 4.0)
|
31
|
+
listen (3.1.5)
|
32
|
+
rb-fsevent (~> 0.9, >= 0.9.4)
|
33
|
+
rb-inotify (~> 0.9, >= 0.9.7)
|
34
|
+
ruby_dep (~> 1.2)
|
35
|
+
lumberjack (1.0.10)
|
11
36
|
method_source (0.8.2)
|
12
|
-
|
37
|
+
nenv (0.3.0)
|
38
|
+
notiffany (0.1.0)
|
39
|
+
nenv (~> 0.1)
|
40
|
+
shellany (~> 0.0)
|
41
|
+
parslet (1.7.1)
|
42
|
+
blankslate (>= 2.0, <= 4.0)
|
43
|
+
pry (0.10.3)
|
13
44
|
coderay (~> 1.1.0)
|
14
45
|
method_source (~> 0.8.1)
|
15
46
|
slop (~> 3.4)
|
16
|
-
|
47
|
+
pry-byebug (3.4.0)
|
48
|
+
byebug (~> 9.0)
|
49
|
+
pry (~> 0.10)
|
50
|
+
rake (10.5.0)
|
51
|
+
rb-fsevent (0.9.7)
|
52
|
+
rb-inotify (0.9.7)
|
53
|
+
ffi (>= 0.5.0)
|
54
|
+
rspec (3.4.0)
|
55
|
+
rspec-core (~> 3.4.0)
|
56
|
+
rspec-expectations (~> 3.4.0)
|
57
|
+
rspec-mocks (~> 3.4.0)
|
58
|
+
rspec-core (3.4.4)
|
59
|
+
rspec-support (~> 3.4.0)
|
60
|
+
rspec-expectations (3.4.0)
|
61
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
62
|
+
rspec-support (~> 3.4.0)
|
63
|
+
rspec-mocks (3.4.1)
|
64
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
65
|
+
rspec-support (~> 3.4.0)
|
66
|
+
rspec-support (3.4.1)
|
67
|
+
ruby_dep (1.3.1)
|
68
|
+
shellany (0.0.1)
|
17
69
|
slop (3.6.0)
|
18
|
-
term-ansicolor (1.3.
|
70
|
+
term-ansicolor (1.3.2)
|
19
71
|
tins (~> 1.0)
|
20
|
-
|
72
|
+
thor (0.19.1)
|
73
|
+
tins (1.10.2)
|
21
74
|
|
22
75
|
PLATFORMS
|
23
76
|
ruby
|
24
77
|
|
25
78
|
DEPENDENCIES
|
26
79
|
bundler (~> 1.7)
|
80
|
+
guard-rspec
|
27
81
|
polint!
|
28
|
-
pry
|
82
|
+
pry-byebug
|
29
83
|
rake (~> 10.0)
|
84
|
+
|
85
|
+
BUNDLED WITH
|
86
|
+
1.12.5
|
data/Guardfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
2
|
+
require "guard/rspec/dsl"
|
3
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
4
|
+
|
5
|
+
rspec = dsl.rspec
|
6
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
7
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
8
|
+
watch(rspec.spec_files)
|
9
|
+
|
10
|
+
ruby = dsl.ruby
|
11
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
12
|
+
|
13
|
+
watch(%r{^spec/data/.*\.po}) { 'spec/lib/polint_spec.rb' }
|
14
|
+
end
|
data/lib/polint.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
require 'polint/version'
|
3
|
+
require 'polint/parser'
|
4
|
+
require 'polint/transform'
|
5
|
+
require 'term/ansicolor'
|
3
6
|
require 'singleton'
|
4
7
|
|
5
8
|
module Polint
|
@@ -38,6 +41,34 @@ module Polint
|
|
38
41
|
|
39
42
|
private
|
40
43
|
|
44
|
+
def error(key, val, contexts, message)
|
45
|
+
log key, val, contexts, "Error: #{message}", :red
|
46
|
+
end
|
47
|
+
|
48
|
+
def warn(key, val, contexts, message)
|
49
|
+
log key, val, contexts, "Warning: #{message}", :yellow
|
50
|
+
end
|
51
|
+
|
52
|
+
def log(key, val, contexts, message, color)
|
53
|
+
if key =~ /(\d+):(.*)/
|
54
|
+
lineno = $1
|
55
|
+
file_and_line = "#{@pofile}:#{$1}:"
|
56
|
+
key = $2
|
57
|
+
else
|
58
|
+
lineno = nil
|
59
|
+
file_and_line = "#{@pofile}:"
|
60
|
+
end
|
61
|
+
puts "#{file_and_line}#{term.public_send(color)} #{message}.#{term.clear}"
|
62
|
+
if @verbose
|
63
|
+
contexts.each do |context|
|
64
|
+
puts "#{term.blue}CONTEXT:#{term.clear} #{context}"
|
65
|
+
end
|
66
|
+
puts "#{term.blue}KEY:#{term.clear} #{key}"
|
67
|
+
puts "#{term.blue}TRN:#{term.clear} #{val}"
|
68
|
+
puts "–" * 80
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
41
72
|
def term
|
42
73
|
@term ||= ENV['NOCOLOR'] ? BlackHole.instance : Term::ANSIColor
|
43
74
|
end
|
@@ -77,39 +108,49 @@ module Polint
|
|
77
108
|
io.write data.join
|
78
109
|
io.flush
|
79
110
|
io.close_write
|
80
|
-
data = io.read
|
111
|
+
data = io.read
|
81
112
|
end
|
82
113
|
success and return data
|
83
114
|
die "Error while loading the PO file '#{@pofile}', aborting."
|
84
115
|
end
|
85
116
|
|
86
|
-
def parse_data(
|
87
|
-
|
88
|
-
context = []
|
89
|
-
next_is_fuzzy = false
|
90
|
-
|
91
|
-
lines.each do |line|
|
92
|
-
case line
|
117
|
+
def parse_data(data)
|
118
|
+
return if data.nil? || data.empty?
|
93
119
|
|
94
|
-
|
95
|
-
|
120
|
+
tree = Polint::Parser.new.parse(data)
|
121
|
+
tree = Polint::Transform.new.apply(tree)
|
96
122
|
|
97
|
-
|
98
|
-
|
123
|
+
die 'No Plural-Forms header found' unless tree[:headers].key?('Plural-Forms')
|
124
|
+
nplurals = tree[:headers]['Plural-Forms'][:nplurals]
|
99
125
|
|
100
|
-
|
101
|
-
|
126
|
+
tree[:translations].each do |translation|
|
127
|
+
msgid, msgid_plural = translation[:msgid][:text], translation[:msgid_plural][:text]
|
128
|
+
contexts = translation[:references]
|
129
|
+
fuzzy = translation[:flags].include?(:fuzzy)
|
102
130
|
|
103
|
-
|
104
|
-
|
105
|
-
|
131
|
+
if msgid_plural.nil?
|
132
|
+
if translation[:msgstrs].size != 1
|
133
|
+
error msgid, nil, contexts, "#{translation[:msgstrs].size} plurals found but none expected"
|
134
|
+
@errors += 1
|
135
|
+
end
|
106
136
|
|
137
|
+
check_pair(msgid, translation[:msgstrs][0][:text], translation[:references], fuzzy)
|
107
138
|
else
|
108
|
-
|
109
|
-
|
110
|
-
|
139
|
+
if translation[:msgstrs].size != nplurals
|
140
|
+
error msgid, nil, contexts, "#{translation[:msgstrs].size} plurals found but #{nplurals} expected"
|
141
|
+
@errors += 1
|
142
|
+
end
|
143
|
+
|
144
|
+
plural_attr = (msgid_plural.scan(AttributeRe).uniq - msgid.scan(AttributeRe).uniq).first
|
145
|
+
translation[:msgstrs].each do |msgstr|
|
146
|
+
val = msgstr[:text]
|
147
|
+
msgid_check = val.scan(AttributeRe).include?(plural_attr) ? msgid_plural : msgid
|
148
|
+
check_pair(msgid_check, val, contexts, fuzzy)
|
149
|
+
end
|
111
150
|
end
|
112
151
|
end
|
152
|
+
rescue Parslet::ParseFailed => e
|
153
|
+
die e.cause.ascii_tree
|
113
154
|
end
|
114
155
|
|
115
156
|
# Check for errors in a key/translation pair.
|
@@ -129,36 +170,18 @@ module Polint
|
|
129
170
|
@errors += 1 if not_in_val.any? || not_in_key.any? || is_empty
|
130
171
|
@fuzzies += 1 if is_fuzzy
|
131
172
|
|
132
|
-
if key =~ /(\d+):(.*)/
|
133
|
-
lineno = $1
|
134
|
-
file_and_line = "#{@pofile}:#{$1}:"
|
135
|
-
key = $2
|
136
|
-
else
|
137
|
-
lineno = nil
|
138
|
-
file_and_line = "#{@pofile}:"
|
139
|
-
end
|
140
|
-
|
141
173
|
if is_empty
|
142
|
-
|
174
|
+
error key, val, contexts, "translated string empty"
|
143
175
|
elsif not_in_key.any?
|
144
176
|
not_in_key.each do |name|
|
145
|
-
|
177
|
+
error key, val, contexts, "#{name} absent from reference string"
|
146
178
|
end
|
147
179
|
elsif not_in_val.any?
|
148
180
|
not_in_val.each do |name|
|
149
|
-
|
181
|
+
warn key, val, contexts, "#{name} absent from translated string"
|
150
182
|
end
|
151
183
|
elsif is_fuzzy
|
152
|
-
|
153
|
-
end
|
154
|
-
|
155
|
-
if @verbose
|
156
|
-
contexts.each do |context|
|
157
|
-
puts "#{term.blue}CONTEXT:#{term.clear} #{context}"
|
158
|
-
end
|
159
|
-
puts "#{term.blue}KEY:#{term.clear} #{key}"
|
160
|
-
puts "#{term.blue}TRN:#{term.clear} #{val}"
|
161
|
-
puts "–" * 80
|
184
|
+
warn key, val, contexts, "translation is fuzzy"
|
162
185
|
end
|
163
186
|
end
|
164
187
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
module Polint
|
4
|
+
class Parser < Parslet::Parser
|
5
|
+
|
6
|
+
rule(:endl) { str("\n").maybe }
|
7
|
+
rule(:sp) { str(' ') }
|
8
|
+
rule(:htab) { str("\t") }
|
9
|
+
rule(:wsp) { sp | htab }
|
10
|
+
rule(:lwsp) { wsp.repeat }
|
11
|
+
rule(:tcase) { match(/[A-Z]/).repeat(1) >> match(/[a-z]/).repeat }
|
12
|
+
rule(:blank_line) { endl }
|
13
|
+
|
14
|
+
rule(:quote) { str('"') }
|
15
|
+
rule(:quoted_char) { match(/[^"]/) }
|
16
|
+
rule(:quoted_pair) { str('\\') >> quote }
|
17
|
+
rule(:quoted_string) { quote >> (quoted_pair | quoted_char).repeat.as(:quoted_string) >> quote >> lwsp }
|
18
|
+
rule(:quoted_strings) { (quoted_string >> endl).repeat(1) }
|
19
|
+
|
20
|
+
rule(:header_sep) { str(':') >> lwsp }
|
21
|
+
rule(:header_name) { (tcase >> (str('-') >> tcase).repeat).as(:name) >> header_sep }
|
22
|
+
rule(:header_value) { match(/[^\n"]/).repeat.as(:value) }
|
23
|
+
rule(:raw_header) { header_name >> header_value }
|
24
|
+
rule(:nplurals) { str('nplurals=') >> match(/[0-9]/).repeat.as(:nplurals) >> str(';') >> lwsp }
|
25
|
+
rule(:plural) { str('plural=') >> match(/[^\n"]/).repeat.as(:plural) }
|
26
|
+
rule(:plural_forms_header) { str('Plural-Forms').as(:name) >> header_sep >> (nplurals >> plural).as(:value) }
|
27
|
+
rule(:unquoted_header) { plural_forms_header | raw_header }
|
28
|
+
rule(:header) { quote >> unquoted_header >> quote >> lwsp }
|
29
|
+
rule(:header_lines) { (header >> endl).repeat(1) }
|
30
|
+
rule(:headers) { str('msgid') >> lwsp >> quote >> quote >> endl >> str('msgstr') >> lwsp >> ((quoted_string >> endl).maybe >> header_lines).as(:headers) >> blank_line }
|
31
|
+
|
32
|
+
rule(:start_comment) { str('#') }
|
33
|
+
rule(:flag) { str(',') >> lwsp >> match(/[a-z\-]/).repeat(1).as(:flag) >> lwsp }
|
34
|
+
rule(:flag_comment) { start_comment >> flag.repeat(1).as(:flags) >> endl }
|
35
|
+
rule(:reference_comment) { start_comment >> str(':') >> lwsp >> match(/[^\n]/).repeat.as(:reference) >> endl }
|
36
|
+
rule(:comment) { flag_comment | reference_comment }
|
37
|
+
rule(:comments) { comment.repeat }
|
38
|
+
|
39
|
+
rule(:msgid) { str('msgid') >> lwsp >> quoted_strings.as(:msgid) }
|
40
|
+
rule(:msgid_plural) { str('msgid_plural') >> lwsp >> quoted_strings.as(:msgid_plural) }
|
41
|
+
|
42
|
+
rule(:index) { str('[') >> match(/[0-9]/).repeat(1).as(:index) >> str(']') }
|
43
|
+
rule(:msgstr) { str('msgstr') >> (index.maybe >> lwsp >> quoted_strings).as(:msgstr) }
|
44
|
+
|
45
|
+
rule(:translation) { (comments >> msgid >> msgid_plural.maybe >> msgstr.repeat(1)).as(:translation) >> blank_line }
|
46
|
+
rule(:translations) { translation.repeat }
|
47
|
+
|
48
|
+
rule(:file) { (headers >> translations).as(:file) }
|
49
|
+
root(:file)
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
module Polint
|
4
|
+
class Transform < Parslet::Transform
|
5
|
+
|
6
|
+
rule(flag: simple(:f)) { f.to_sym }
|
7
|
+
|
8
|
+
rule(quoted_string: simple(:qs)) { qs }
|
9
|
+
rule(quoted_string: sequence(:qs)) { '' } # empty string is parsed as []
|
10
|
+
|
11
|
+
rule(name: simple(:k), value: simple(:v)) { [k.to_s, v.to_s] }
|
12
|
+
rule(name: simple(:k), value: subtree(:v)) { [k.to_s, v] }
|
13
|
+
rule(nplurals: simple(:n), plural: simple(:p)) { { nplurals: n.to_i, plural: p } }
|
14
|
+
rule(headers: subtree(:items)) do
|
15
|
+
items.shift if items.first == ''
|
16
|
+
{ headers: items.to_h }
|
17
|
+
end
|
18
|
+
|
19
|
+
rule(msgid: sequence(:items)) { { msgid: { text: items.join("\n") } } }
|
20
|
+
rule(msgid_plural: sequence(:items)) { { msgid_plural: { text: items.join("\n") } } }
|
21
|
+
rule(msgstr: subtree(:items)) do
|
22
|
+
msgstr = {}
|
23
|
+
msgstr[:index] = items.shift[:index].to_i if items.first.is_a?(Hash)
|
24
|
+
msgstr[:text] = items.join("\n")
|
25
|
+
{ msgstr: msgstr }
|
26
|
+
end
|
27
|
+
|
28
|
+
rule(translation: subtree(:items)) do
|
29
|
+
translation = {
|
30
|
+
flags: [],
|
31
|
+
references: [],
|
32
|
+
msgid: {},
|
33
|
+
msgid_plural: {},
|
34
|
+
msgstrs: []
|
35
|
+
}
|
36
|
+
items.each do |hash|
|
37
|
+
k, v = hash.to_a.first
|
38
|
+
case k
|
39
|
+
when :flags then translation[:flags] |= v
|
40
|
+
when :reference then translation[:references] << v
|
41
|
+
when :msgid, :msgid_plural then translation[k] = v
|
42
|
+
when :msgstr then translation[:msgstrs] << v
|
43
|
+
end
|
44
|
+
end
|
45
|
+
{ translation: translation }
|
46
|
+
end
|
47
|
+
|
48
|
+
rule(file: subtree(:items)) do
|
49
|
+
file = {
|
50
|
+
headers: {},
|
51
|
+
translations: []
|
52
|
+
}
|
53
|
+
items.each do |hash|
|
54
|
+
k, v = hash.to_a.first
|
55
|
+
case k
|
56
|
+
when :headers then file[:headers] = v
|
57
|
+
when :translation then file[:translations] << v
|
58
|
+
end
|
59
|
+
end
|
60
|
+
file
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
data/lib/polint/version.rb
CHANGED
data/polint.gemspec
CHANGED
@@ -6,8 +6,8 @@ require 'polint/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "polint"
|
8
8
|
spec.version = Polint::VERSION
|
9
|
-
spec.authors = ["Julien Letessier"]
|
10
|
-
spec.email = ["julien.letessier@gmail.com"]
|
9
|
+
spec.authors = ["Julien Letessier", "Greg Beech"]
|
10
|
+
spec.email = ["julien.letessier@gmail.com", "greg@gregbeech.com"]
|
11
11
|
spec.summary = %q{A linter for Uniforum PO files.}
|
12
12
|
spec.homepage = ""
|
13
13
|
spec.license = "MIT"
|
@@ -19,7 +19,9 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.add_development_dependency "bundler", "~> 1.7"
|
21
21
|
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
-
spec.add_development_dependency "pry"
|
22
|
+
spec.add_development_dependency "pry-byebug"
|
23
|
+
spec.add_development_dependency "guard-rspec"
|
23
24
|
|
24
25
|
spec.add_dependency "term-ansicolor"
|
26
|
+
spec.add_dependency "parslet", "~> 1.7", ">= 1.7.1"
|
25
27
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
msgid ""
|
2
|
+
msgstr ""
|
3
|
+
"Language: ar\n"
|
4
|
+
"MIME-Version: 1.0\n"
|
5
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
6
|
+
"Content-Transfer-Encoding: 8bit\n"
|
7
|
+
"Plural-Forms: nplurals=6; plural= n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
|
8
|
+
"X-Generator: PhraseApp (phraseapp.com)\n"
|
9
|
+
|
10
|
+
#: ../some_file.rb:51
|
11
|
+
msgid "Hello World"
|
12
|
+
msgstr "مرحبا بالعالم"
|
13
|
+
|
14
|
+
#: ../some_file.rb:51
|
15
|
+
msgid "Hello World Plural"
|
16
|
+
msgid_plural "Hello %{n} Worlds Plural"
|
17
|
+
msgstr[0] "مرحبا العالمي الجمع"
|
18
|
+
msgstr[1] "مرحبا %{n} العالمين الجمع"
|
19
|
+
msgstr[2] "مرحبا %{n} العالمين الجمع"
|
20
|
+
msgstr[3] "مرحبا %{n} العالمين الجمع"
|
21
|
+
msgstr[4] "مرحبا %{n} العالمين الجمع"
|
22
|
+
msgstr[5] "مرحبا %{n} العالمين الجمع"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
msgid ""
|
2
|
+
msgstr ""
|
3
|
+
"Language: en\n"
|
4
|
+
"MIME-Version: 1.0\n"
|
5
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
6
|
+
"Content-Transfer-Encoding: 8bit\n"
|
7
|
+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
8
|
+
"X-Generator: PhraseApp (phraseapp.com)\n"
|
9
|
+
|
10
|
+
#: ../some_file.rb:51
|
11
|
+
msgid "Hello World"
|
12
|
+
msgstr "Hello World"
|
13
|
+
|
14
|
+
#: ../some_file.rb:51
|
15
|
+
msgid "Hello World Plural"
|
16
|
+
msgid_plural "Hello %{n} Worlds Plural"
|
17
|
+
msgstr[0] "Hello World Plural"
|
18
|
+
msgstr[1] "Hello %{n} Worlds Plural"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
msgid ""
|
2
|
+
msgstr ""
|
3
|
+
"Language: fr\n"
|
4
|
+
"MIME-Version: 1.0\n"
|
5
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
6
|
+
"Content-Transfer-Encoding: 8bit\n"
|
7
|
+
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
8
|
+
"X-Generator: PhraseApp (phraseapp.com)\n"
|
9
|
+
|
10
|
+
#: ../some_file.rb:51
|
11
|
+
msgid "Hello World"
|
12
|
+
msgstr "Bonjour le monde"
|
13
|
+
|
14
|
+
#: ../some_file.rb:51
|
15
|
+
msgid "Hello World Plural"
|
16
|
+
msgid_plural "Hello %{n} Worlds Plural"
|
17
|
+
msgstr[0] "Bonjour tout le monde pluriel"
|
18
|
+
msgstr[1] "Bonjour %{n} mondes pluriels"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
msgid ""
|
2
|
+
msgstr ""
|
3
|
+
"Language: zh\n"
|
4
|
+
"MIME-Version: 1.0\n"
|
5
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
6
|
+
"Content-Transfer-Encoding: 8bit\n"
|
7
|
+
"Plural-Forms: nplurals=1; plural=0;\n"
|
8
|
+
"X-Generator: PhraseApp (phraseapp.com)\n"
|
9
|
+
|
10
|
+
#: ../some_file.rb:51
|
11
|
+
msgid "Hello World"
|
12
|
+
msgstr "你好,世界"
|
13
|
+
|
14
|
+
#: ../some_file.rb:51
|
15
|
+
msgid "Hello World Plural"
|
16
|
+
msgid_plural "Hello %{n} Worlds Plural"
|
17
|
+
msgstr[0] "你好%{n}世界多元"
|
@@ -0,0 +1,258 @@
|
|
1
|
+
require 'polint/parser'
|
2
|
+
|
3
|
+
RSpec.describe Polint::Parser do
|
4
|
+
let(:parser) { described_class.new }
|
5
|
+
let(:rule) { :translation }
|
6
|
+
let(:line) { '' }
|
7
|
+
let(:tree) { parser.send(rule).parse(line) }
|
8
|
+
|
9
|
+
describe 'rule(:quoted_string)' do
|
10
|
+
let(:rule) { :quoted_string }
|
11
|
+
|
12
|
+
context 'when matching a simple string' do
|
13
|
+
let(:line) { '"Hello World"' }
|
14
|
+
it { expect(tree).to eq quoted_string: 'Hello World' }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'when matching a string with embedded quotes' do
|
18
|
+
let(:line) { '"Hello \\"my\\" World"' }
|
19
|
+
it { expect(tree).to eq quoted_string: 'Hello \\"my\\" World' }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'rule(:headers)' do
|
24
|
+
let(:rule) { :headers }
|
25
|
+
let(:line) { lines.join("\n") }
|
26
|
+
|
27
|
+
context 'when matching a plural forms header' do
|
28
|
+
let(:lines) {
|
29
|
+
[
|
30
|
+
'msgid ""',
|
31
|
+
'msgstr ""',
|
32
|
+
'"Language: ar\n"',
|
33
|
+
'"MIME-Version: 1.0\n"',
|
34
|
+
'"Content-Type: text/plain; charset=UTF-8\n"',
|
35
|
+
'"Content-Transfer-Encoding: 8bit\n"',
|
36
|
+
'"Plural-Forms: nplurals=6; plural= n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"',
|
37
|
+
'"X-Generator: PhraseApp (phraseapp.com)\n"'
|
38
|
+
]
|
39
|
+
}
|
40
|
+
it {
|
41
|
+
expect(tree).to eq headers: [
|
42
|
+
{ quoted_string: [] },
|
43
|
+
{ name: 'Language', value: 'ar\n' },
|
44
|
+
{ name: 'MIME-Version', value: '1.0\n' },
|
45
|
+
{ name: 'Content-Type', value: 'text/plain; charset=UTF-8\n' },
|
46
|
+
{ name: 'Content-Transfer-Encoding', value: '8bit\n' },
|
47
|
+
{ name: 'Plural-Forms', value: { nplurals: '6', plural: ' n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n' } },
|
48
|
+
{ name: 'X-Generator', value: 'PhraseApp (phraseapp.com)\n' }
|
49
|
+
]
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'when matching an unquoted header' do
|
54
|
+
let(:line) { 'Plural-Forms: nplurals=6; plural= n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n' }
|
55
|
+
it { expect{ tree }.to raise_error Parslet::ParseFailed }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'rule(:flag_comment)' do
|
60
|
+
let(:rule) { :flag_comment }
|
61
|
+
|
62
|
+
context 'when matching a fuzzy comment' do
|
63
|
+
let(:line) { '#, fuzzy' }
|
64
|
+
it { expect(tree).to eq flags: [{ flag: 'fuzzy' }] }
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'when matching a multi-flag comment' do
|
68
|
+
let(:line) { '#, java-format, fuzzy' }
|
69
|
+
it { expect(tree).to eq flags: [{ flag: 'java-format' }, { flag: 'fuzzy' }] }
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when matching a non-flags comment' do
|
73
|
+
let(:line) { '#: ../../some_file.rb:34' }
|
74
|
+
it { expect{ tree }.to raise_error Parslet::ParseFailed }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'rule(:reference_comment)' do
|
79
|
+
let(:rule) { :reference_comment }
|
80
|
+
|
81
|
+
context 'when matching a reference comment' do
|
82
|
+
let(:line) { '#: ../../some_file.rb:34' }
|
83
|
+
it { expect(tree).to eq reference: '../../some_file.rb:34' }
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when matching a non-reference comment' do
|
87
|
+
let(:line) { '#, fuzzy' }
|
88
|
+
it { expect{ tree }.to raise_error Parslet::ParseFailed }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe 'rule(:msgid)' do
|
93
|
+
let(:rule) { :msgid }
|
94
|
+
|
95
|
+
context 'when matching a single-line msgid' do
|
96
|
+
let(:line) { 'msgid "Hello World"' }
|
97
|
+
it { expect(tree).to eq msgid: [{ quoted_string: 'Hello World' }] }
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when matching a multi-line msgid' do
|
101
|
+
let(:line) { %{msgid ""\n"Hello World"\n"Hello Again"} }
|
102
|
+
it { expect(tree).to eq msgid: [{ quoted_string: [] }, { quoted_string: 'Hello World' }, { quoted_string: 'Hello Again'}] }
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when matching a msgid with embedded quotes' do
|
106
|
+
let(:line) { 'msgid "Hello \\"my\\" World"' }
|
107
|
+
it { expect(tree).to eq msgid: [{ quoted_string: 'Hello \\"my\\" World' }] }
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'when matching an unquoted msgid' do
|
111
|
+
let(:line) { 'msgid Unquoted String' }
|
112
|
+
it { expect{ tree }.to raise_error Parslet::ParseFailed }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'rule(:msgid_plural)' do
|
117
|
+
let(:rule) { :msgid_plural }
|
118
|
+
|
119
|
+
context 'when matching a single-line msgid_plural' do
|
120
|
+
let(:line) { 'msgid_plural "Hello %{n} Worlds"' }
|
121
|
+
it { expect(tree).to eq msgid_plural: [{ quoted_string: 'Hello %{n} Worlds' }] }
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'when matching a multi-line msgid_plural' do
|
125
|
+
let(:line) { %{msgid_plural ""\n"Hello %{n} Worlds"\n"Hello Again"} }
|
126
|
+
it { expect(tree).to eq msgid_plural: [{ quoted_string: [] }, { quoted_string: 'Hello %{n} Worlds' }, { quoted_string: 'Hello Again'}] }
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'when matching an unquoted msgid_plural' do
|
130
|
+
let(:line) { 'msgid_plural Unquoted String' }
|
131
|
+
it { expect{ tree }.to raise_error Parslet::ParseFailed }
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe 'rule(:msgstr)' do
|
136
|
+
let(:rule) { :msgstr }
|
137
|
+
|
138
|
+
context 'when matching a single-line msgstr' do
|
139
|
+
let(:line) { 'msgstr "Hello World"' }
|
140
|
+
it { expect(tree).to eq msgstr: [{ quoted_string: 'Hello World' }] }
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'when matching a single-line msgstr with an index' do
|
144
|
+
let(:line) { 'msgstr[3] "Hello World"' }
|
145
|
+
it { expect(tree).to eq msgstr: [{ index: '3' }, { quoted_string: 'Hello World' }] }
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'when matching a multi-line msgstr' do
|
149
|
+
let(:line) { %{msgstr ""\n"Hello World"\n"Hello Again"} }
|
150
|
+
it { expect(tree).to eq msgstr: [{ quoted_string: [] }, { quoted_string: 'Hello World' }, { quoted_string: 'Hello Again'}] }
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'when matching a multi-line msgstr with an index' do
|
154
|
+
let(:line) { %{msgstr[1] ""\n"Hello World"\n"Hello Again"} }
|
155
|
+
it { expect(tree).to eq msgstr: [{ index: '1' }, { quoted_string: [] }, { quoted_string: 'Hello World' }, { quoted_string: 'Hello Again'}] }
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'when matching an unquoted msgstr' do
|
159
|
+
let(:line) { 'msgstr Unquoted String' }
|
160
|
+
it { expect{ tree }.to raise_error Parslet::ParseFailed }
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe 'rule(:translation)' do
|
165
|
+
let(:rule) { :translation }
|
166
|
+
let(:line) { lines.join("\n") }
|
167
|
+
|
168
|
+
context 'when matching a singular single-line msgstr with comments' do
|
169
|
+
let(:lines) {
|
170
|
+
[
|
171
|
+
'#, fuzzy',
|
172
|
+
'#: ../../some_file.rb:34',
|
173
|
+
'msgid "Hello World"',
|
174
|
+
'msgstr "Hello World"'
|
175
|
+
]
|
176
|
+
}
|
177
|
+
it {
|
178
|
+
expect(tree).to eq translation: [
|
179
|
+
{ flags: [{ flag: 'fuzzy' }] },
|
180
|
+
{ reference: '../../some_file.rb:34' },
|
181
|
+
{ msgid: [{ quoted_string: 'Hello World' }] },
|
182
|
+
{ msgstr: [{ quoted_string: 'Hello World' }] }
|
183
|
+
]
|
184
|
+
}
|
185
|
+
end
|
186
|
+
|
187
|
+
context 'when matching a plural single-line msgstr with comments' do
|
188
|
+
let(:lines) {
|
189
|
+
[
|
190
|
+
'#, fuzzy',
|
191
|
+
'#: ../../some_file.rb:34',
|
192
|
+
'msgid "Hello World"',
|
193
|
+
'msgid_plural "Hello %{n} Worlds"',
|
194
|
+
'msgstr[0] "Hello World"',
|
195
|
+
'msgstr[1] "Hello %{n} Worlds"'
|
196
|
+
]
|
197
|
+
}
|
198
|
+
it {
|
199
|
+
expect(tree).to eq translation: [
|
200
|
+
{ flags: [{ flag: 'fuzzy' }] },
|
201
|
+
{ reference: '../../some_file.rb:34' },
|
202
|
+
{ msgid: [{ quoted_string: 'Hello World' }] },
|
203
|
+
{ msgid_plural: [{ quoted_string: 'Hello %{n} Worlds' }] },
|
204
|
+
{ msgstr: [{ index: '0' }, { quoted_string: 'Hello World' }] },
|
205
|
+
{ msgstr: [{ index: '1' }, { quoted_string: 'Hello %{n} Worlds' }] }
|
206
|
+
]
|
207
|
+
}
|
208
|
+
end
|
209
|
+
|
210
|
+
# TODO: Multiline strings and negative cases
|
211
|
+
end
|
212
|
+
|
213
|
+
describe 'rule(:translations)' do
|
214
|
+
let(:rule) { :translations }
|
215
|
+
let(:line) { lines.join("\n") }
|
216
|
+
|
217
|
+
context 'when matching multiple translations' do
|
218
|
+
let(:lines) {
|
219
|
+
[
|
220
|
+
'#, fuzzy',
|
221
|
+
'#: ../../some_file.rb:34',
|
222
|
+
'msgid "Hello World"',
|
223
|
+
'msgstr "Hello World"',
|
224
|
+
'',
|
225
|
+
'#, fuzzy',
|
226
|
+
'#: ../../some_file.rb:34',
|
227
|
+
'msgid "Hello World"',
|
228
|
+
'msgid_plural "Hello %{n} Worlds"',
|
229
|
+
'msgstr[0] "Hello World"',
|
230
|
+
'msgstr[1] "Hello %{n} Worlds"'
|
231
|
+
]
|
232
|
+
}
|
233
|
+
it {
|
234
|
+
expect(tree).to eq [
|
235
|
+
{
|
236
|
+
translation: [
|
237
|
+
{ flags: [{ flag: 'fuzzy' }] },
|
238
|
+
{ reference: '../../some_file.rb:34' },
|
239
|
+
{ msgid: [{ quoted_string: 'Hello World' }] },
|
240
|
+
{ msgstr: [{ quoted_string: 'Hello World' }] }
|
241
|
+
]
|
242
|
+
},
|
243
|
+
{
|
244
|
+
translation: [
|
245
|
+
{ flags: [{ flag: 'fuzzy' }] },
|
246
|
+
{ reference: '../../some_file.rb:34' },
|
247
|
+
{ msgid: [{ quoted_string: 'Hello World' }] },
|
248
|
+
{ msgid_plural: [{ quoted_string: 'Hello %{n} Worlds' }] },
|
249
|
+
{ msgstr: [{ index: '0' }, { quoted_string: 'Hello World' }] },
|
250
|
+
{ msgstr: [{ index: '1' }, { quoted_string: 'Hello %{n} Worlds' }] }
|
251
|
+
]
|
252
|
+
}
|
253
|
+
]
|
254
|
+
}
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'polint/transform'
|
2
|
+
|
3
|
+
RSpec.describe Polint::Transform do
|
4
|
+
let(:transform) { described_class.new }
|
5
|
+
let(:output) { transform.apply(tree) }
|
6
|
+
|
7
|
+
context 'with a headers tree' do
|
8
|
+
let(:tree) {
|
9
|
+
{
|
10
|
+
headers: [
|
11
|
+
{ quoted_string: [] },
|
12
|
+
{ name: 'Language', value: 'ar\n' },
|
13
|
+
{ name: 'MIME-Version', value: '1.0\n' },
|
14
|
+
{ name: 'Content-Type', value: 'text/plain; charset=UTF-8\n' },
|
15
|
+
{ name: 'Content-Transfer-Encoding', value: '8bit\n' },
|
16
|
+
{ name: 'Plural-Forms', value: { nplurals: '6', plural: ' n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n' } },
|
17
|
+
{ name: 'X-Generator', value: 'PhraseApp (phraseapp.com)\n' }
|
18
|
+
]
|
19
|
+
}
|
20
|
+
}
|
21
|
+
it {
|
22
|
+
expect(output).to eq headers: {
|
23
|
+
'Language' => 'ar\n',
|
24
|
+
'MIME-Version' => '1.0\n',
|
25
|
+
'Content-Type' => 'text/plain; charset=UTF-8\n',
|
26
|
+
'Content-Transfer-Encoding' => '8bit\n',
|
27
|
+
'Plural-Forms' => { nplurals: 6, plural: ' n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n' },
|
28
|
+
'X-Generator' => 'PhraseApp (phraseapp.com)\n'
|
29
|
+
}
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with a plural tree' do
|
34
|
+
let(:tree) {
|
35
|
+
{
|
36
|
+
translation: [
|
37
|
+
{ flags: [{ flag: 'fuzzy' }] },
|
38
|
+
{ reference: '../../some_file.rb:34' },
|
39
|
+
{ reference: '../../some_other_file.rb:283' },
|
40
|
+
{ msgid: [{ quoted_string: [] }, { quoted_string: 'Hello World' }, { quoted_string: 'Hello Again'}] },
|
41
|
+
{ msgid_plural: [{ quoted_string: [] }, { quoted_string: 'Hello %{n} Worlds' }, { quoted_string: 'Hello Again'}] },
|
42
|
+
{ msgstr: [{ index: '0' }, { quoted_string: [] }, { quoted_string: 'Hello World' }, { quoted_string: 'Hello Again'}] },
|
43
|
+
{ msgstr: [{ index: '1' }, { quoted_string: [] }, { quoted_string: 'Hello %{n} Worlds' }, { quoted_string: 'Hello Again'}] }
|
44
|
+
]
|
45
|
+
}
|
46
|
+
}
|
47
|
+
it {
|
48
|
+
expect(output).to eq translation: {
|
49
|
+
flags: [:fuzzy],
|
50
|
+
references: ['../../some_file.rb:34', '../../some_other_file.rb:283'],
|
51
|
+
msgid: { text: "\nHello World\nHello Again" },
|
52
|
+
msgid_plural: { text: "\nHello %{n} Worlds\nHello Again" },
|
53
|
+
msgstrs: [
|
54
|
+
{ index: 0, text: "\nHello World\nHello Again" },
|
55
|
+
{ index: 1, text: "\nHello %{n} Worlds\nHello Again" }
|
56
|
+
]
|
57
|
+
}
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'polint'
|
2
|
+
|
3
|
+
RSpec.describe Polint::Checker do
|
4
|
+
|
5
|
+
Dir.glob(File.join(__dir__, '..', 'data', '*-valid.po')) do |file|
|
6
|
+
context "#{File.basename(file, '.po').split('-').join(' ')}" do
|
7
|
+
let(:checker) { described_class.new(file) }
|
8
|
+
|
9
|
+
it 'has no errors' do
|
10
|
+
expect(checker.run).to eq 0
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'pry'
|
2
|
+
|
3
|
+
# rspec seems to complain about this class not having a #cause method; not sure
|
4
|
+
# why but this is a quick hacky fix just to get everything passing. it doesn't
|
5
|
+
# seem to affect the results of the tests anyway.
|
6
|
+
module Parslet
|
7
|
+
class Cause
|
8
|
+
def cause
|
9
|
+
StandardError.new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julien Letessier
|
8
|
+
- Greg Beech
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2016-06-22 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: bundler
|
@@ -39,7 +40,21 @@ dependencies:
|
|
39
40
|
- !ruby/object:Gem::Version
|
40
41
|
version: '10.0'
|
41
42
|
- !ruby/object:Gem::Dependency
|
42
|
-
name: pry
|
43
|
+
name: pry-byebug
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: guard-rspec
|
43
58
|
requirement: !ruby/object:Gem::Requirement
|
44
59
|
requirements:
|
45
60
|
- - ">="
|
@@ -66,24 +81,57 @@ dependencies:
|
|
66
81
|
- - ">="
|
67
82
|
- !ruby/object:Gem::Version
|
68
83
|
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: parslet
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '1.7'
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.7.1
|
94
|
+
type: :runtime
|
95
|
+
prerelease: false
|
96
|
+
version_requirements: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - "~>"
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '1.7'
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.7.1
|
69
104
|
description:
|
70
105
|
email:
|
71
106
|
- julien.letessier@gmail.com
|
107
|
+
- greg@gregbeech.com
|
72
108
|
executables:
|
73
109
|
- polint
|
74
110
|
extensions: []
|
75
111
|
extra_rdoc_files: []
|
76
112
|
files:
|
77
113
|
- ".gitignore"
|
114
|
+
- ".rspec"
|
78
115
|
- Gemfile
|
79
116
|
- Gemfile.lock
|
117
|
+
- Guardfile
|
80
118
|
- LICENSE.txt
|
81
119
|
- README.md
|
82
120
|
- Rakefile
|
83
121
|
- bin/polint
|
84
122
|
- lib/polint.rb
|
123
|
+
- lib/polint/parser.rb
|
124
|
+
- lib/polint/transform.rb
|
85
125
|
- lib/polint/version.rb
|
86
126
|
- polint.gemspec
|
127
|
+
- spec/data/ar-valid.po
|
128
|
+
- spec/data/en-valid.po
|
129
|
+
- spec/data/fr-valid.po
|
130
|
+
- spec/data/zh-valid.po
|
131
|
+
- spec/lib/polint/parser_spec.rb
|
132
|
+
- spec/lib/polint/transform_spec.rb
|
133
|
+
- spec/lib/polint_spec.rb
|
134
|
+
- spec/spec_helper.rb
|
87
135
|
homepage: ''
|
88
136
|
licenses:
|
89
137
|
- MIT
|
@@ -104,9 +152,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
152
|
version: '0'
|
105
153
|
requirements: []
|
106
154
|
rubyforge_project:
|
107
|
-
rubygems_version: 2.
|
155
|
+
rubygems_version: 2.5.1
|
108
156
|
signing_key:
|
109
157
|
specification_version: 4
|
110
158
|
summary: A linter for Uniforum PO files.
|
111
|
-
test_files:
|
112
|
-
|
159
|
+
test_files:
|
160
|
+
- spec/data/ar-valid.po
|
161
|
+
- spec/data/en-valid.po
|
162
|
+
- spec/data/fr-valid.po
|
163
|
+
- spec/data/zh-valid.po
|
164
|
+
- spec/lib/polint/parser_spec.rb
|
165
|
+
- spec/lib/polint/transform_spec.rb
|
166
|
+
- spec/lib/polint_spec.rb
|
167
|
+
- spec/spec_helper.rb
|