polint 0.0.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|