PoParser 3.2.0 → 3.2.5
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 +5 -5
- data/.github/workflows/ruby.yml +41 -0
- data/.rubocop.yml +21 -7
- data/CHANGELOG.md +20 -0
- data/CODE_OF_CONDUCT.md +76 -0
- data/Gemfile +6 -4
- data/README.md +8 -2
- data/lib/poparser.rb +2 -0
- data/lib/poparser/comment.rb +11 -10
- data/lib/poparser/constants.rb +27 -25
- data/lib/poparser/entry.rb +95 -73
- data/lib/poparser/header.rb +27 -19
- data/lib/poparser/message.rb +6 -2
- data/lib/poparser/po.rb +63 -63
- data/lib/poparser/tokenizer.rb +2 -0
- data/lib/poparser/version.rb +3 -1
- data/poparser.gemspec +15 -14
- data/spec/poparser/po_spec.rb +8 -1
- data/spec/spec_helper.rb +14 -8
- metadata +8 -11
- data/.travis.yml +0 -8
- data/Guardfile +0 -9
- data/spec/utils/random_pofile_generator.rb +0 -175
data/lib/poparser/header.rb
CHANGED
@@ -1,37 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PoParser
|
4
|
+
# The very first entry of the PO file is considered the header
|
2
5
|
class Header
|
3
6
|
attr_reader :entry, :original_configs, :flag
|
4
7
|
attr_accessor :comments, :pot_creation_date, :po_revision_date, :project_id,
|
5
|
-
|
6
|
-
|
8
|
+
:report_to, :last_translator, :team, :language, :charset,
|
9
|
+
:encoding, :plural_forms
|
7
10
|
|
8
11
|
def initialize(entry)
|
9
12
|
@entry = entry
|
10
|
-
@comments = entry.translator_comment.value
|
13
|
+
@comments = entry.translator_comment.value unless entry.translator_comment.nil?
|
11
14
|
@original_configs = convert_msgstr_to_hash(entry.msgstr)
|
12
15
|
@flag = entry.flag
|
13
16
|
|
14
|
-
|
15
|
-
instance_variable_set "@#{k.to_s}".to_sym, @original_configs[v]
|
16
|
-
end
|
17
|
+
define_labels_instance_variables
|
17
18
|
end
|
18
19
|
|
19
20
|
def configs
|
20
|
-
|
21
|
-
HEADER_LABELS.each do |k, v|
|
21
|
+
configs = HEADER_LABELS.each_with_object({}) do |(k, v), hash|
|
22
22
|
hash[v] = instance_variable_get "@#{k}".to_sym
|
23
23
|
end
|
24
|
-
@original_configs.merge(
|
24
|
+
@original_configs.merge(configs)
|
25
25
|
end
|
26
26
|
|
27
27
|
# Checks if the entry is fuzzy
|
28
28
|
#
|
29
29
|
# @return [Boolean]
|
30
30
|
def fuzzy?
|
31
|
-
@flag.to_s.match('fuzzy') ? true : false
|
31
|
+
@flag.to_s.match?('fuzzy') ? true : false
|
32
32
|
end
|
33
33
|
|
34
34
|
# Flag the entry as Fuzzy
|
35
|
+
#
|
35
36
|
# @return [Header]
|
36
37
|
def flag_as_fuzzy
|
37
38
|
@flag = 'fuzzy'
|
@@ -41,6 +42,7 @@ module PoParser
|
|
41
42
|
# Set flag to a custom string
|
42
43
|
def flag_as(flag)
|
43
44
|
raise ArgumentError if flag.class != String
|
45
|
+
|
44
46
|
@flag = flag
|
45
47
|
end
|
46
48
|
|
@@ -57,7 +59,7 @@ module PoParser
|
|
57
59
|
else
|
58
60
|
string << "# #{@comments}".strip
|
59
61
|
end
|
60
|
-
string << "#, #{@flag
|
62
|
+
string << "#, #{@flag}" if @flag
|
61
63
|
string << "msgid \"\"\nmsgstr \"\""
|
62
64
|
configs.each do |k, v|
|
63
65
|
if v.nil? || v.empty?
|
@@ -79,18 +81,18 @@ module PoParser
|
|
79
81
|
else
|
80
82
|
string << "# #{@comments}".strip
|
81
83
|
end
|
82
|
-
string << "#, #{@flag
|
84
|
+
string << "#, #{@flag}" if @flag
|
83
85
|
string << "msgid \"\"\nmsgstr \"\""
|
84
86
|
configs.each do |k, v|
|
85
|
-
if v.nil? || v.empty?
|
86
|
-
|
87
|
-
end
|
87
|
+
next if v.nil? || v.empty?
|
88
|
+
|
88
89
|
string << "#{k}: #{v}\n".dump
|
89
90
|
end
|
90
91
|
string.join("\n")
|
91
92
|
end
|
92
93
|
|
93
94
|
private
|
95
|
+
|
94
96
|
def convert_msgstr_to_hash(msgstr)
|
95
97
|
options_array = msgstr.value.map do |options|
|
96
98
|
options.split(':', 2).each do |k|
|
@@ -108,10 +110,16 @@ module PoParser
|
|
108
110
|
# [['a', 'b'], ['c']] #=> [['a', 'bc']]
|
109
111
|
def merge_to_previous_string(array)
|
110
112
|
array.each_with_index do |key, index|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
113
|
+
next unless key.length == 1
|
114
|
+
|
115
|
+
array[index - 1][1] += key[0]
|
116
|
+
array.delete_at(index)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def define_labels_instance_variables
|
121
|
+
HEADER_LABELS.each do |k, v|
|
122
|
+
instance_variable_set("@#{k}".to_sym, @original_configs[v])
|
115
123
|
end
|
116
124
|
end
|
117
125
|
end
|
data/lib/poparser/message.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PoParser
|
2
4
|
class Message
|
3
5
|
attr_accessor :type, :value
|
4
6
|
|
5
7
|
def initialize(type, value)
|
6
8
|
@type = type
|
7
|
-
@value
|
9
|
+
@value = value
|
8
10
|
|
9
11
|
remove_empty_line
|
10
12
|
end
|
@@ -15,6 +17,7 @@ module PoParser
|
|
15
17
|
|
16
18
|
def to_s(with_label = false)
|
17
19
|
return to_str unless with_label
|
20
|
+
|
18
21
|
if @value.is_a? Array
|
19
22
|
remove_empty_line
|
20
23
|
# multiline messages should be started with an empty line
|
@@ -37,6 +40,7 @@ module PoParser
|
|
37
40
|
end
|
38
41
|
|
39
42
|
private
|
43
|
+
|
40
44
|
def remove_empty_line
|
41
45
|
if @value.is_a? Array
|
42
46
|
@value.shift if @value.first == ''
|
@@ -44,7 +48,7 @@ module PoParser
|
|
44
48
|
end
|
45
49
|
|
46
50
|
def label
|
47
|
-
if
|
51
|
+
if /msgstr\[[0-9]\]/.match?(@type.to_s)
|
48
52
|
@type
|
49
53
|
else
|
50
54
|
ENTRIES_LABELS[@type]
|
data/lib/poparser/po.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PoParser
|
2
4
|
# Po class keeps all entries of a Po file
|
3
5
|
class Po
|
@@ -7,7 +9,7 @@ module PoParser
|
|
7
9
|
|
8
10
|
def initialize(args = {})
|
9
11
|
@entries = []
|
10
|
-
@path = args
|
12
|
+
@path = args[:path]
|
11
13
|
end
|
12
14
|
|
13
15
|
# add new entries to po file
|
@@ -25,68 +27,66 @@ module PoParser
|
|
25
27
|
# @param entry [Hash, Array] a hash of entry contents or an array of hashes
|
26
28
|
# @return [Po]
|
27
29
|
def add(entry)
|
28
|
-
if entry.
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
return import_hash(entry) if entry.is_a?(Hash)
|
31
|
+
return import_array(entry) if entry.is_a?(Array)
|
32
|
+
|
33
|
+
raise ArgumentError, 'Must be a hash or an array of hashes'
|
34
|
+
end
|
35
|
+
alias << add
|
36
|
+
|
37
|
+
# Delete entry from po file
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
#
|
41
|
+
# delete(entry)
|
42
|
+
#
|
43
|
+
# @param entry [Entry] to be deleted
|
44
|
+
# @return [Entry]
|
45
|
+
def delete(entry)
|
46
|
+
raise(ArgumentError, 'Must be an Entry') unless entry.is_a?(PoParser::Entry)
|
47
|
+
|
48
|
+
@entries.delete(entry)
|
36
49
|
end
|
37
|
-
alias_method :<<, :add
|
38
50
|
|
39
51
|
# Returns an array of all entries in po file
|
40
52
|
#
|
41
53
|
# @param include_obsolete [Boolean] Whether include obsolete entries or not
|
42
54
|
# @return [Array]
|
43
|
-
def entries(include_obsolete=false)
|
44
|
-
if include_obsolete
|
45
|
-
|
46
|
-
|
47
|
-
find_all do |entry|
|
48
|
-
!entry.obsolete?
|
49
|
-
end
|
50
|
-
end
|
55
|
+
def entries(include_obsolete = false)
|
56
|
+
return @entries if include_obsolete
|
57
|
+
|
58
|
+
find_all { |entry| !entry.obsolete? }
|
51
59
|
end
|
52
|
-
|
60
|
+
alias all entries
|
53
61
|
|
54
62
|
# Finds all entries that are flaged as fuzzy
|
55
63
|
#
|
56
64
|
# @return [Array] an array of fuzzy entries
|
57
65
|
def fuzzy
|
58
|
-
find_all
|
59
|
-
entry.fuzzy?
|
60
|
-
end
|
66
|
+
find_all(&:fuzzy?)
|
61
67
|
end
|
62
68
|
|
63
69
|
# Finds all entries that are untranslated
|
64
70
|
#
|
65
71
|
# @return [Array] an array of untranslated entries
|
66
72
|
def untranslated
|
67
|
-
find_all
|
68
|
-
entry.untranslated?
|
69
|
-
end
|
73
|
+
find_all(&:untranslated?)
|
70
74
|
end
|
71
75
|
|
72
76
|
# Finds all entries that are translated
|
73
77
|
#
|
74
78
|
# @return [Array] an array of translated entries
|
75
79
|
def translated
|
76
|
-
find_all
|
77
|
-
entry.translated?
|
78
|
-
end
|
80
|
+
find_all(&:translated?)
|
79
81
|
end
|
80
82
|
|
81
83
|
# Finds all obsolete entries
|
82
84
|
#
|
83
85
|
# @return [Array] an array of obsolete entries
|
84
86
|
def obsolete
|
85
|
-
find_all
|
86
|
-
entry.obsolete?
|
87
|
-
end
|
87
|
+
find_all(&:obsolete?)
|
88
88
|
end
|
89
|
-
|
89
|
+
alias cached obsolete
|
90
90
|
|
91
91
|
# Count of all entries without counting obsolete entries
|
92
92
|
#
|
@@ -94,7 +94,7 @@ module PoParser
|
|
94
94
|
def size
|
95
95
|
entries.length
|
96
96
|
end
|
97
|
-
|
97
|
+
alias length size
|
98
98
|
|
99
99
|
# Search for entries with provided string
|
100
100
|
#
|
@@ -102,9 +102,7 @@ module PoParser
|
|
102
102
|
# @param string [String] String to search for
|
103
103
|
# @return [Array] Array of matched entries
|
104
104
|
def search_in(label, string)
|
105
|
-
|
106
|
-
raise ArgumentError, "Unknown key: #{label}"
|
107
|
-
end
|
105
|
+
raise(ArgumentError, "Unknown key: #{label}") unless LABELS.include?(label.to_sym)
|
108
106
|
|
109
107
|
find_all do |entry|
|
110
108
|
text = entry.send(label).str
|
@@ -121,9 +119,9 @@ module PoParser
|
|
121
119
|
fuzzy_size = fuzzy.size
|
122
120
|
|
123
121
|
{
|
124
|
-
translated:
|
122
|
+
translated: percentage(translated_size),
|
125
123
|
untranslated: percentage(untranslated_size),
|
126
|
-
fuzzy:
|
124
|
+
fuzzy: percentage(fuzzy_size),
|
127
125
|
}
|
128
126
|
end
|
129
127
|
|
@@ -131,11 +129,8 @@ module PoParser
|
|
131
129
|
#
|
132
130
|
# @return [Array] array of hashes of entries
|
133
131
|
def to_h
|
134
|
-
array =
|
135
|
-
array
|
136
|
-
@entries.each do |entry|
|
137
|
-
array << entry.to_h
|
138
|
-
end
|
132
|
+
array = @entries.map(&:to_h)
|
133
|
+
array.unshift(@header.to_h) if @header
|
139
134
|
array
|
140
135
|
end
|
141
136
|
|
@@ -143,22 +138,17 @@ module PoParser
|
|
143
138
|
#
|
144
139
|
# @return [String]
|
145
140
|
def to_s
|
146
|
-
array =
|
147
|
-
array << @header.to_s if @header
|
141
|
+
array = @entries.map(&:to_s)
|
148
142
|
# add a blank line after header
|
149
|
-
array
|
150
|
-
@entries.each do |entry|
|
151
|
-
array << entry.to_s
|
152
|
-
end
|
143
|
+
array.unshift(@header.to_s, '') if @header
|
153
144
|
array.join("\n")
|
154
145
|
end
|
155
146
|
|
156
147
|
# Saves the file to the provided path
|
157
148
|
def save_file
|
158
149
|
raise ArgumentError, 'Need a Path to save the file' if @path.nil?
|
159
|
-
|
160
|
-
|
161
|
-
end
|
150
|
+
|
151
|
+
File.open(@path, 'w') { |file| file.write(to_s) }
|
162
152
|
end
|
163
153
|
|
164
154
|
def each
|
@@ -168,35 +158,45 @@ module PoParser
|
|
168
158
|
end
|
169
159
|
|
170
160
|
def inspect
|
171
|
-
"<#{self.class.name}, Translated: #{translated.length}
|
161
|
+
"<#{self.class.name}, Translated: #{translated.length}"\
|
162
|
+
"(#{stats[:translated]}%) Untranslated: #{untranslated.length}"\
|
163
|
+
"(#{stats[:untranslated]}%) Fuzzy: #{fuzzy.length}(#{stats[:fuzzy]}%)>"
|
172
164
|
end
|
173
165
|
|
174
166
|
private
|
167
|
+
|
175
168
|
# calculates percentages based on total number of entries
|
176
169
|
#
|
177
170
|
# @param [Integer] number of entries
|
178
171
|
# @return [Float] percentage of the provided entries
|
179
172
|
def percentage(count)
|
180
|
-
((count.to_f /
|
173
|
+
((count.to_f / size) * 100).round(1)
|
181
174
|
end
|
182
175
|
|
183
176
|
def import_hash(entry)
|
184
177
|
add_entry(entry)
|
178
|
+
|
179
|
+
self
|
185
180
|
end
|
186
181
|
|
187
182
|
def import_array(entry)
|
188
|
-
entry.each
|
189
|
-
|
190
|
-
|
183
|
+
entry.each { |en| add_entry(en) }
|
184
|
+
|
185
|
+
self
|
191
186
|
end
|
192
187
|
|
188
|
+
# rubocop:disable Style/SafeNavigation
|
193
189
|
def add_entry(entry)
|
194
|
-
if entry[:msgid] && entry[:msgid].
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
190
|
+
return add_header_entry(entry) if entry[:msgid] && entry[:msgid].empty?
|
191
|
+
|
192
|
+
@entries << Entry.new(entry)
|
193
|
+
end
|
194
|
+
# rubocop:enable Style/SafeNavigation
|
195
|
+
|
196
|
+
def add_header_entry(entry)
|
197
|
+
raise('Duplicate entry, header was already instantiated') if @header
|
198
|
+
|
199
|
+
@header = Header.new(Entry.new(entry))
|
200
200
|
end
|
201
201
|
end
|
202
202
|
end
|
data/lib/poparser/tokenizer.rb
CHANGED
data/lib/poparser/version.rb
CHANGED
data/poparser.gemspec
CHANGED
@@ -1,27 +1,28 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'poparser/version'
|
5
6
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
8
|
+
spec.name = 'PoParser'
|
8
9
|
spec.version = PoParser::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
10
|
+
spec.authors = ['Arash Mousavi']
|
11
|
+
spec.email = ['mousavi.arash@gmail.com']
|
12
|
+
spec.summary = 'A PO file parser, editor and generator.'
|
13
|
+
spec.description = 'A PO file parser, editor and generator. PO files are translation files generated by GNU/Gettext tool.'
|
14
|
+
spec.homepage = 'http://github.com/arashm/poparser'
|
15
|
+
spec.license = 'MIT'
|
15
16
|
|
16
|
-
spec.files = `git ls-files`.split(
|
17
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
18
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
19
|
spec.test_files = spec.files.grep(%r{^spec/})
|
19
|
-
spec.require_paths = [
|
20
|
+
spec.require_paths = ['lib']
|
20
21
|
|
21
22
|
# Runtime deps
|
22
|
-
spec.add_runtime_dependency
|
23
|
+
spec.add_runtime_dependency 'simple_po_parser', '~> 1.1.2'
|
23
24
|
|
24
25
|
# Development deps
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
26
|
+
spec.add_development_dependency 'bundler', '>= 0'
|
27
|
+
spec.add_development_dependency 'rake', '>= 0'
|
27
28
|
end
|
data/spec/poparser/po_spec.rb
CHANGED
@@ -20,6 +20,14 @@ describe PoParser::Po do
|
|
20
20
|
expect(@po << entry).to be_a_kind_of PoParser::Po
|
21
21
|
end
|
22
22
|
|
23
|
+
it 'should be able to remove an entry from Po' do
|
24
|
+
entries = [entry, entry.dup]
|
25
|
+
@po << entries
|
26
|
+
e = @po.entries.first
|
27
|
+
expect(@po.delete(e)).to eq e
|
28
|
+
expect(@po.delete(e)).to be_nil
|
29
|
+
end
|
30
|
+
|
23
31
|
it 'should be able to add multiple entries' do
|
24
32
|
entries = [entry, entry.dup]
|
25
33
|
expect(@po << entries).to be_a_kind_of PoParser::Po
|
@@ -125,5 +133,4 @@ describe PoParser::Po do
|
|
125
133
|
}.to raise_error(RuntimeError, "Duplicate entry, header was already instantiated")
|
126
134
|
end
|
127
135
|
end
|
128
|
-
|
129
136
|
end
|