PoParser 2.0.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile +5 -2
- data/README.md +23 -1
- data/Rakefile +65 -1
- data/lib/poparser/comment.rb +33 -6
- data/lib/poparser/constants.rb +4 -2
- data/lib/poparser/entry.rb +10 -10
- data/lib/poparser/header.rb +20 -0
- data/lib/poparser/po.rb +10 -10
- data/lib/poparser/tokenizer.rb +5 -17
- data/lib/poparser/version.rb +1 -1
- data/lib/poparser.rb +9 -11
- data/poparser.gemspec +1 -1
- data/spec/poparser/comment_spec.rb +4 -2
- data/spec/poparser/entry_spec.rb +23 -6
- data/spec/poparser/po_spec.rb +6 -6
- data/spec/poparser/poparser_spec.rb +126 -0
- data/spec/spec_helper.rb +12 -3
- data/spec/utils/random_pofile_generator.rb +175 -0
- data/test/benchmark.po +683 -0
- data/test/benchmark_small.po +46 -0
- data/test/complex_entry.po +21 -0
- data/test/escape_string.txt +7 -0
- metadata +12 -12
- data/lib/poparser/parser.rb +0 -67
- data/lib/poparser/transformer.rb +0 -59
- data/spec/poparser/parser_spec.rb +0 -72
- data/spec/poparser/transformer_spec.rb +0 -24
@@ -0,0 +1,46 @@
|
|
1
|
+
# PO benchmark file header
|
2
|
+
#
|
3
|
+
#, fuzzy
|
4
|
+
msgid ""
|
5
|
+
msgstr ""
|
6
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
7
|
+
"Content-Transfer-Encoding: 8bit\n"
|
8
|
+
|
9
|
+
#: m
|
10
|
+
msgctxt "AESMM"
|
11
|
+
msgid "QtXRl"
|
12
|
+
msgid_plural "h"
|
13
|
+
msgstr[0] "spfQ9g"
|
14
|
+
msgstr[1] "spfQ9g"
|
15
|
+
|
16
|
+
# EnfA
|
17
|
+
#: EnthqvU2qf6kF
|
18
|
+
msgctxt "9ihYCwlIEg=="
|
19
|
+
msgid "AloClNt81srB2Op/gEoKap7QvzlMzWBXxMEWLyjI2bQZV3praFAT2jpYhfQmgzu4Wix2tAsOeZV6lZ1TcnRmuHXht8FLfE016Q=="
|
20
|
+
msgstr "i+9eqs/otjcsICeBK5MEcfQ5hJOmP++ROezIMcPEWVOEh+XAT1brUoxfqrQAMefK"
|
21
|
+
|
22
|
+
#: jg4iou6yRTCJ7XNHeEqikz
|
23
|
+
msgctxt "9dPrCW63vhWJwoO"
|
24
|
+
msgid ""
|
25
|
+
"ZPcE\n"
|
26
|
+
"llqi4\n"
|
27
|
+
msgstr ""
|
28
|
+
"sKNQc\n"
|
29
|
+
"BwQ\n"
|
30
|
+
|
31
|
+
#: Ld
|
32
|
+
#, fuzzy
|
33
|
+
#| msgctxt "M6J"
|
34
|
+
#| msgid "P4"
|
35
|
+
msgctxt "MA9k"
|
36
|
+
msgid "P4Zc"
|
37
|
+
msgstr "4ZcKx"
|
38
|
+
|
39
|
+
#: g3K
|
40
|
+
#~ msgctxt "CVdDY"
|
41
|
+
#~ msgid ""
|
42
|
+
#~ "8Jw\n"
|
43
|
+
#~ "dwtm\n"
|
44
|
+
#~ msgstr ""
|
45
|
+
#~ "KNV2\n"
|
46
|
+
#~ "lEWV\n"
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# translator-comment
|
2
|
+
#
|
3
|
+
#. extract
|
4
|
+
#: reference1
|
5
|
+
#: reference2
|
6
|
+
#, flag
|
7
|
+
#| msgctxt "previous context"
|
8
|
+
#| msgid ""
|
9
|
+
#| "multiline\n"
|
10
|
+
#|"previous messageid"
|
11
|
+
#| msgid_plural "previous msgid_plural"
|
12
|
+
msgctxt "Context"
|
13
|
+
msgid "msgid"
|
14
|
+
msgid_plural ""
|
15
|
+
"multiline msgid_plural\n"
|
16
|
+
""
|
17
|
+
msgstr[0] "msgstr 0"
|
18
|
+
msgstr[1] ""
|
19
|
+
"msgstr 1 multiline 1\n"
|
20
|
+
"msgstr 1 line 2\n"
|
21
|
+
msgstr[2] "msgstr 2"
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: PoParser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arash Mousavi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-05-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: simple_po_parser
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -75,10 +75,8 @@ files:
|
|
75
75
|
- lib/poparser/entry.rb
|
76
76
|
- lib/poparser/header.rb
|
77
77
|
- lib/poparser/message.rb
|
78
|
-
- lib/poparser/parser.rb
|
79
78
|
- lib/poparser/po.rb
|
80
79
|
- lib/poparser/tokenizer.rb
|
81
|
-
- lib/poparser/transformer.rb
|
82
80
|
- lib/poparser/version.rb
|
83
81
|
- poparser.gemspec
|
84
82
|
- spec/poparser/comment_spec.rb
|
@@ -92,12 +90,15 @@ files:
|
|
92
90
|
- spec/poparser/fixtures/tokenizer_empty_line.po
|
93
91
|
- spec/poparser/header_spec.rb
|
94
92
|
- spec/poparser/message_spec.rb
|
95
|
-
- spec/poparser/parser_spec.rb
|
96
93
|
- spec/poparser/po_spec.rb
|
97
94
|
- spec/poparser/poparser_spec.rb
|
98
95
|
- spec/poparser/tokenizer_spec.rb
|
99
|
-
- spec/poparser/transformer_spec.rb
|
100
96
|
- spec/spec_helper.rb
|
97
|
+
- spec/utils/random_pofile_generator.rb
|
98
|
+
- test/benchmark.po
|
99
|
+
- test/benchmark_small.po
|
100
|
+
- test/complex_entry.po
|
101
|
+
- test/escape_string.txt
|
101
102
|
homepage: http://github.com/arashm/poparser
|
102
103
|
licenses:
|
103
104
|
- MIT
|
@@ -118,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
119
|
version: '0'
|
119
120
|
requirements: []
|
120
121
|
rubyforge_project:
|
121
|
-
rubygems_version: 2.6.
|
122
|
+
rubygems_version: 2.6.12
|
122
123
|
signing_key:
|
123
124
|
specification_version: 4
|
124
125
|
summary: A PO file parser, editor and generator.
|
@@ -134,9 +135,8 @@ test_files:
|
|
134
135
|
- spec/poparser/fixtures/tokenizer_empty_line.po
|
135
136
|
- spec/poparser/header_spec.rb
|
136
137
|
- spec/poparser/message_spec.rb
|
137
|
-
- spec/poparser/parser_spec.rb
|
138
138
|
- spec/poparser/po_spec.rb
|
139
139
|
- spec/poparser/poparser_spec.rb
|
140
140
|
- spec/poparser/tokenizer_spec.rb
|
141
|
-
- spec/poparser/transformer_spec.rb
|
142
141
|
- spec/spec_helper.rb
|
142
|
+
- spec/utils/random_pofile_generator.rb
|
data/lib/poparser/parser.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
module PoParser
|
2
|
-
class Parser < Parslet::Parser
|
3
|
-
root(:document)
|
4
|
-
|
5
|
-
rule(:document) { lines.repeat }
|
6
|
-
rule(:lines) { comments | entries }
|
7
|
-
|
8
|
-
# Comments
|
9
|
-
rule(:comments) do
|
10
|
-
reference |
|
11
|
-
extracted_comment | flag |
|
12
|
-
previous_untraslated_string |
|
13
|
-
cached |
|
14
|
-
translator_comment
|
15
|
-
end
|
16
|
-
|
17
|
-
rule(:translator_comment) { spaced('#') >> comment_text_line.as(:translator_comment) }
|
18
|
-
rule(:extracted_comment) { spaced('#.') >> comment_text_line.as(:extracted_comment) }
|
19
|
-
rule(:reference) { spaced('#:') >> comment_text_line.as(:reference) }
|
20
|
-
rule(:flag) { spaced('#,') >> comment_text_line.as(:flag) }
|
21
|
-
rule(:previous_untraslated_string){ spaced('#|') >> comment_text_line.as(:previous_untraslated_string) }
|
22
|
-
rule(:cached) { spaced('#~') >> comment_text_line.as(:cached) }
|
23
|
-
|
24
|
-
# Entries
|
25
|
-
rule(:entries) do
|
26
|
-
msgid.as(:msgid) |
|
27
|
-
msgid_plural.as(:msgid_plural) |
|
28
|
-
msgstr.as(:msgstr) |
|
29
|
-
msgstr_plural.as(:msgstr_plural) |
|
30
|
-
msgctxt.as(:msgctxt)
|
31
|
-
end
|
32
|
-
|
33
|
-
rule(:multiline) { str('"').present? >> msg_text_line.repeat.maybe }
|
34
|
-
rule(:msgid) { spaced('msgid') >> msg_text_line >> multiline.repeat }
|
35
|
-
rule(:msgid_plural) { spaced('msgid_plural') >> msg_text_line >> multiline.repeat }
|
36
|
-
|
37
|
-
rule(:msgstr) { spaced('msgstr') >> msg_text_line >> multiline.repeat }
|
38
|
-
rule(:msgstr_plural){ str('msgstr') >> bracketed(match["[0-9]"].as(:plural_id)) >> space? >> msg_text_line >> multiline.repeat }
|
39
|
-
rule(:msgctxt) { spaced('msgctxt') >> msg_text_line >> multiline.repeat }
|
40
|
-
|
41
|
-
# Helpers
|
42
|
-
rule(:space) { match['\p{Blank}'].repeat } #match only whitespace and not newline
|
43
|
-
rule(:space?) { space.maybe }
|
44
|
-
rule(:newline) { match["\n"] }
|
45
|
-
rule(:eol) { newline | any.absent? }
|
46
|
-
rule(:character) { escaped | text }
|
47
|
-
rule(:text) { any }
|
48
|
-
rule(:escaped) { str('\\') >> any }
|
49
|
-
rule(:msg_line_end){ str('"') >> space? >> eol }
|
50
|
-
|
51
|
-
rule(:comment_text_line) do
|
52
|
-
(eol.absent? >> character).repeat.maybe.as(:text) >> eol
|
53
|
-
end
|
54
|
-
|
55
|
-
rule(:msg_text_line) do
|
56
|
-
str('"') >> (msg_line_end.absent? >> character).repeat.maybe.as(:text) >> msg_line_end
|
57
|
-
end
|
58
|
-
|
59
|
-
def bracketed(atom)
|
60
|
-
str('[') >> atom >> str(']')
|
61
|
-
end
|
62
|
-
|
63
|
-
def spaced(character)
|
64
|
-
str(character) >> space?
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
data/lib/poparser/transformer.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
module PoParser
|
2
|
-
# Converts the array returned from {Parser} to a usable hash
|
3
|
-
class Transformer
|
4
|
-
def initialize
|
5
|
-
@hash = {}
|
6
|
-
super
|
7
|
-
end
|
8
|
-
|
9
|
-
def transform(obj)
|
10
|
-
apply_transforms(obj).each do |hash|
|
11
|
-
merge(hash)
|
12
|
-
end
|
13
|
-
@hash
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
# @Note: There was a problem applying all rules together. I don't know
|
18
|
-
# in what order Parslet run rules, but it's not in order. I ended up
|
19
|
-
# making two separate transform and feed one output to the other.
|
20
|
-
def first_transform
|
21
|
-
Parslet::Transform.new do
|
22
|
-
rule(:msgstr_plural => subtree(:plural)) do
|
23
|
-
if plural.is_a? Array
|
24
|
-
{ "msgstr\[#{plural[0][:plural_id]}\]".to_sym => plural }
|
25
|
-
else
|
26
|
-
{ "msgstr\[#{plural[:plural_id]}\]".to_sym => plural }
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
rule(:text => simple(:txt)) { txt.to_s.chomp }
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def second_transform
|
35
|
-
Parslet::Transform.new do
|
36
|
-
rule(:plural_id => simple(:id), :text => simple(:txt)) { txt }
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def apply_transforms(hash)
|
41
|
-
first = first_transform.apply(hash)
|
42
|
-
second_transform.apply(first)
|
43
|
-
end
|
44
|
-
|
45
|
-
# Merges two hashed together. If both hashes have common keys it
|
46
|
-
# will create an array of them
|
47
|
-
#
|
48
|
-
# @return [Hash]
|
49
|
-
def merge(newh)
|
50
|
-
@hash.merge!(newh) do |key, oldval, newval|
|
51
|
-
if oldval.is_a? Array
|
52
|
-
oldval << newval
|
53
|
-
else
|
54
|
-
Array.new [oldval, newval]
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require 'spec_helper'
|
3
|
-
|
4
|
-
describe PoParser::Parser do
|
5
|
-
let(:po) { PoParser::Parser.new }
|
6
|
-
|
7
|
-
context(:comments) do
|
8
|
-
let(:tc) { po.translator_comment }
|
9
|
-
let(:rc) { po.reference }
|
10
|
-
let(:ec) { po.extracted_comment }
|
11
|
-
let(:fc) { po.flag }
|
12
|
-
let(:pusc){ po.previous_untraslated_string }
|
13
|
-
|
14
|
-
it 'parses the translator comment' do
|
15
|
-
expect(tc).to parse("# Persian translation for damned-lies 123123\n")
|
16
|
-
expect(tc).to parse("# Copyright (C) 2012 damned-lies's COPYRIGHT HOLDER\n")
|
17
|
-
expect(tc).to parse("# Arash Mousavi <mousavi.arash@gmail.com>, 2014.\n")
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'parses refrence comment' do
|
21
|
-
expect(rc).to parse("#: database-content.py:1 database-content.py:129 settings.py:52\n")
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'parses extracted_comment' do
|
25
|
-
expect(ec).to parse("#. database-content.py:1 database-content.py:129 settings.py:52\n")
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'parses flag_comment' do
|
29
|
-
expect(fc).to parse("#, python-format\n")
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'parses previous_untraslated_string' do
|
33
|
-
expect(pusc).to parse("#| msgid \"\"\n")
|
34
|
-
expect(pusc).to parse("#| \"Hello,\\n\"\n")
|
35
|
-
expect(pusc).to parse("#| \"The new state of %(module)s - %(branch)s - %(domain)s (%(language)s) is \"\n")
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
context 'Entries' do
|
40
|
-
let(:msgid) { po.msgid }
|
41
|
-
let(:msgstr){ po.msgstr }
|
42
|
-
let(:pofile){ Pathname.new('spec/poparser/fixtures/multiline.po').realpath }
|
43
|
-
|
44
|
-
it 'parses msgid' do
|
45
|
-
expect(msgid).to parse "msgid \"The new state of %(module)s - %(branch)s - %(domain)s (%(language)s) is now \"\n"
|
46
|
-
expect(msgid).to parse "msgid \"The new \"state\" of %(module)s - %(branch)s - %(domain)s (%(language)s) is now \"\n"
|
47
|
-
expect(msgid).to parse "msgid \"The new \"state\" of %(module)s - %(branch)s - %(domain)s (%(language)s) is now \"\n"
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'parses msgstr' do
|
51
|
-
expect(msgstr).to parse "msgstr \"The new state of %(module)s - %(branch)s - %(domain)s (%(language)s) is now \"\n"
|
52
|
-
expect(msgstr).to parse "msgstr \"فعالیت نامعتبر. شاید یک نفر دیگر دقیقا قبل از شما یک فعالیت دیگر ارسال کرده ۱۲۳۱۲۳۱safda \"\n"
|
53
|
-
expect(msgstr).to parse "msgstr \"The new state of %(module)s - %(branch)s - %(domain)s (%(language)s) is now \"\n"
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'parses multiline entries' do
|
57
|
-
data = pofile.read
|
58
|
-
result = [{:msgid=>[{:text=>""}, {:text=>"first"}, {:text=>"second"}]}, {:msgstr=>[{:text=>""}, {:text=>"aval"}, {:text=>"dovom"}]}]
|
59
|
-
expect(po.parse data).to eq(result)
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'parses plural msgstr entries' do
|
63
|
-
str1 = "msgstr[0] \"\""
|
64
|
-
str2 = "msgstr[0] \"\""
|
65
|
-
str3 = "msgstr[0]\"\""
|
66
|
-
result = [{:msgstr_plural=>{:plural_id=>"0", :text=>""}}]
|
67
|
-
expect(po.parse(str1)).to eq(result)
|
68
|
-
expect(po.parse(str2)).to eq(result)
|
69
|
-
expect(po.parse(str3)).to eq(result)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require "spec_helper"
|
3
|
-
|
4
|
-
describe PoParser::Transformer do
|
5
|
-
let(:trans){ PoParser::Transformer.new }
|
6
|
-
|
7
|
-
it 'transforms the returned array from parslet to a usable hash' do
|
8
|
-
parslet_array = [{:translator_comment=>"Persian translation\n"}, {:translator_comment=>"Copyright\n"}, {:msgid=>"\"test\"\n"}]
|
9
|
-
transformed_hash = {:translator_comment=>["Persian translation\n", "Copyright\n"], :msgid=>"\"test\"\n"}
|
10
|
-
expect(trans.transform(parslet_array)).to eq(transformed_hash)
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'transforms plural msgstr forms correctly' do
|
14
|
-
data = [{:msgstr_plural=>{:plural_id=>"0", :text=>"this is a txt"}}]
|
15
|
-
result = { :'msgstr[0]' => "this is a txt" }
|
16
|
-
expect(trans.transform(data)).to eq(result)
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'transforms multiline plural msgstr forms correctly' do
|
20
|
-
data = [{:msgstr_plural=>[{:plural_id=>"0", :text=>"this is a txt"}, {:text => 'some text'}]}]
|
21
|
-
result = { :'msgstr[0]' => ["this is a txt", "some text"] }
|
22
|
-
expect(trans.transform(data)).to eq(result)
|
23
|
-
end
|
24
|
-
end
|