PoParser 3.2.2 → 3.2.3
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/.rubocop.yml +21 -7
- data/.travis.yml +3 -3
- data/CHANGELOG.md +7 -1
- data/Gemfile +5 -3
- data/README.md +6 -0
- data/bin/rspec +29 -0
- 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 +26 -18
- data/lib/poparser/message.rb +6 -2
- data/lib/poparser/po.rb +62 -62
- 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
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da904ab0d854e46b77269f997ef79680df4de08762f96fa0a67443f0c68d931c
|
4
|
+
data.tar.gz: cbfe2b90c9ae91420f745ffb023fcd966df7c9d2c04cbdfc6b5ea99ba8ae550f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52bbe60150f1d217a625695984c6aad16dbf220f66c4cba5b4e1d158603711ce5424fcc4e46c51c7147c92c233b7a3fa61d42d968f6531f050a6727097e07a04
|
7
|
+
data.tar.gz: 7b983cc9036bb9020d17d854651821bc19cfbe99d14309fe1bf5352e8edf46e26cc6141206698d5bd684da891109d93733bf5918b0e53d452cef18a6c0c56d73
|
data/.rubocop.yml
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
AllCops:
|
2
|
-
TargetRubyVersion: 2.
|
2
|
+
TargetRubyVersion: 2.6
|
3
3
|
Exclude:
|
4
4
|
- 'spec/**/*'
|
5
|
-
- 'db/**/*'
|
6
|
-
- 'app/views/**/*'
|
7
|
-
- 'config/**/*'
|
8
5
|
- 'bin/*'
|
9
|
-
- 'Rakefile'
|
10
|
-
- 'node_modules/**/*'
|
11
6
|
|
12
7
|
Bundler/OrderedGems:
|
13
8
|
Enabled: false
|
@@ -27,9 +22,28 @@ Layout/AlignParameters:
|
|
27
22
|
EnforcedStyle: with_fixed_indentation
|
28
23
|
|
29
24
|
Style/FrozenStringLiteralComment:
|
30
|
-
Enabled:
|
25
|
+
Enabled: true
|
31
26
|
|
32
27
|
Style/PercentLiteralDelimiters:
|
33
28
|
PreferredDelimiters:
|
34
29
|
'%i': '()'
|
35
30
|
'%w': '()'
|
31
|
+
|
32
|
+
Style/TrailingCommaInArrayLiteral:
|
33
|
+
Enabled: true
|
34
|
+
EnforcedStyleForMultiline: comma
|
35
|
+
|
36
|
+
Style/TrailingCommaInHashLiteral:
|
37
|
+
Enabled: true
|
38
|
+
EnforcedStyleForMultiline: comma
|
39
|
+
|
40
|
+
Style/TrailingCommaInArguments:
|
41
|
+
Enabled: true
|
42
|
+
EnforcedStyleForMultiline: comma
|
43
|
+
|
44
|
+
Layout/EmptyLines:
|
45
|
+
Enabled: true
|
46
|
+
|
47
|
+
Metrics/LineLength:
|
48
|
+
Max: 100
|
49
|
+
IgnoreCopDirectives: True
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
5
|
group :test do
|
4
|
-
gem 'coveralls', :
|
5
|
-
gem 'rspec', '~> 3.
|
6
|
+
gem 'coveralls', require: false
|
7
|
+
gem 'rspec', '~> 3.8'
|
6
8
|
gem 'awesome_print'
|
7
9
|
end
|
8
10
|
|
@@ -12,7 +14,7 @@ group :development do
|
|
12
14
|
end
|
13
15
|
|
14
16
|
group :test, :development do
|
15
|
-
gem 'pry-byebug', :
|
17
|
+
gem 'pry-byebug', platforms: :mri
|
16
18
|
end
|
17
19
|
|
18
20
|
# Specify your gem's dependencies in poparser.gemspec
|
data/README.md
CHANGED
@@ -175,6 +175,12 @@ entry.to_h
|
|
175
175
|
entry.to_s
|
176
176
|
```
|
177
177
|
|
178
|
+
To remove an entry from the PO, use `PO#delete`
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
po.delete(entry)
|
182
|
+
```
|
183
|
+
|
178
184
|
### Searching
|
179
185
|
|
180
186
|
`PO` is an `Enumerable`. All exciting methods from `Enumerable` are available in `PO`. The `PO` yields `Entry`.
|
data/bin/rspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rspec-core", "rspec")
|
data/lib/poparser.rb
CHANGED
data/lib/poparser/comment.rb
CHANGED
@@ -1,20 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PoParser
|
2
4
|
class Comment
|
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
|
-
|
10
|
-
|
11
|
-
end
|
11
|
+
# these behave more like messages
|
12
|
+
remove_empty_line if /^previous_/.match?(@type.to_s)
|
12
13
|
end
|
13
14
|
|
14
15
|
def to_s(with_label = false)
|
15
16
|
return to_str unless with_label
|
17
|
+
|
16
18
|
if @value.is_a? Array
|
17
|
-
if @type.to_s
|
19
|
+
if /^previous_/.match?(@type.to_s) # these behave more like messages
|
18
20
|
string = ["#{COMMENTS_LABELS[@type]} \"\"\n"]
|
19
21
|
@value.each do |str|
|
20
22
|
string << "#| \"#{str}\"\n".gsub(/[\p{Blank}]+$/, '')
|
@@ -27,7 +29,7 @@ module PoParser
|
|
27
29
|
end
|
28
30
|
return string.join
|
29
31
|
else
|
30
|
-
if @type.to_s
|
32
|
+
if /^previous_/.match?(@type.to_s) # these behave more like messages
|
31
33
|
"#{COMMENTS_LABELS[@type]} \"#{@value}\"\n".gsub(/[\p{Blank}]+$/, '')
|
32
34
|
else
|
33
35
|
# removes the space but not newline at the end
|
@@ -38,7 +40,7 @@ module PoParser
|
|
38
40
|
|
39
41
|
def to_str
|
40
42
|
if @value.is_a?(Array)
|
41
|
-
if @type.to_s
|
43
|
+
if /^previous_/.match?(@type.to_s) # these behave more like messages
|
42
44
|
@value.join
|
43
45
|
else
|
44
46
|
@value.join("\n")
|
@@ -53,10 +55,9 @@ module PoParser
|
|
53
55
|
end
|
54
56
|
|
55
57
|
private
|
58
|
+
|
56
59
|
def remove_empty_line
|
57
|
-
if @value.is_a?
|
58
|
-
@value.shift if @value.first == ''
|
59
|
-
end
|
60
|
+
@value.shift if @value.is_a?(Array) && @value.first == ''
|
60
61
|
end
|
61
62
|
end
|
62
63
|
end
|
data/lib/poparser/constants.rb
CHANGED
@@ -1,34 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PoParser
|
2
4
|
COMMENTS_LABELS = {
|
3
|
-
:
|
4
|
-
:
|
5
|
-
:
|
6
|
-
:
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
}
|
5
|
+
translator_comment: '#',
|
6
|
+
extracted_comment: '#.',
|
7
|
+
reference: '#:',
|
8
|
+
flag: '#,',
|
9
|
+
previous_msgctxt: '#| msgctxt',
|
10
|
+
previous_msgid: '#| msgid',
|
11
|
+
previous_msgid_plural: '#| msgid_plural',
|
12
|
+
obsolete: '#~',
|
13
|
+
}.freeze
|
12
14
|
|
13
15
|
ENTRIES_LABELS = {
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
18
|
-
}
|
16
|
+
msgctxt: 'msgctxt',
|
17
|
+
msgid: 'msgid',
|
18
|
+
msgid_plural: 'msgid_plural',
|
19
|
+
msgstr: 'msgstr',
|
20
|
+
}.freeze
|
19
21
|
|
20
22
|
LABELS = COMMENTS_LABELS.merge(ENTRIES_LABELS).keys
|
21
23
|
|
22
24
|
HEADER_LABELS = {
|
23
|
-
:
|
24
|
-
:
|
25
|
-
:
|
26
|
-
:
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
33
|
-
}
|
25
|
+
pot_creation_date: 'POT-Creation-Date',
|
26
|
+
po_revision_date: 'PO-Revision-Date',
|
27
|
+
project_id: 'Project-Id-Version',
|
28
|
+
report_to: 'Project-Id-Version',
|
29
|
+
last_translator: 'Last-Translator',
|
30
|
+
team: 'Language-Team',
|
31
|
+
language: 'Language',
|
32
|
+
charset: 'Content-Type',
|
33
|
+
encoding: 'Content-Transfer-Encoding',
|
34
|
+
plural_forms: 'Plural-Forms',
|
35
|
+
}.freeze
|
34
36
|
end
|
data/lib/poparser/entry.rb
CHANGED
@@ -1,66 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PoParser
|
2
|
-
|
3
|
-
|
4
|
+
# A single translation entity in a PO file
|
5
|
+
class Entry # rubocop:disable Metrics/ClassLength
|
4
6
|
def initialize(args = {})
|
5
7
|
# Defining all instance variables to prevent warnings
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
|
10
|
-
# Set passed arguments
|
11
|
-
args.each do |name, value|
|
12
|
-
raise(ArgumentError, "Unknown label #{name}") if !valid_label? name
|
13
|
-
set_instance_variable(name, value)
|
14
|
-
end
|
15
|
-
|
8
|
+
define_labels_instance_variables
|
9
|
+
define_args_instance_variables(args)
|
16
10
|
define_writer_methods(COMMENTS_LABELS, 'Comment')
|
17
11
|
define_writer_methods(ENTRIES_LABELS, 'Message')
|
18
12
|
define_reader_methods
|
19
|
-
|
20
|
-
|
21
|
-
self.class.send(:alias_method, :cached, :obsolete)
|
22
|
-
self.class.send(:alias_method, :cached=, :obsolete=)
|
23
|
-
# alias for backward compatibility of this typo
|
24
|
-
self.class.send(:alias_method, :refrence, :reference)
|
25
|
-
self.class.send(:alias_method, :refrence=, :reference=)
|
26
|
-
if self.obsolete?
|
27
|
-
obsolete_content = SimplePoParser.parse_message(obsolete.value.join("\n").gsub(/^\|/, "#|"))
|
28
|
-
obsolete_content.each do |name, value|
|
29
|
-
raise(ArgumentError, "Unknown label #{name}") if !valid_label? name
|
30
|
-
set_instance_variable(name, value)
|
31
|
-
end
|
32
|
-
end
|
13
|
+
define_aliases
|
14
|
+
define_obsolete_instance_variables
|
33
15
|
end
|
34
16
|
|
35
17
|
# If entry doesn't have any msgid, it's probably a obsolete entry that is
|
36
|
-
# kept by the program for later use. These entries will usually start
|
18
|
+
# kept by the program for later use. These entries will usually start
|
19
|
+
# with: #~
|
37
20
|
#
|
38
21
|
# @return [Boolean]
|
39
22
|
def obsolete?
|
40
23
|
!@obsolete.nil?
|
41
24
|
end
|
42
|
-
|
25
|
+
alias cached? obsolete?
|
43
26
|
|
44
27
|
# Checks if the entry is untraslated
|
45
28
|
#
|
46
29
|
# @return [Boolean]
|
47
30
|
def untranslated?
|
48
31
|
return false if obsolete? || fuzzy?
|
49
|
-
if @msgstr.is_a? Array
|
50
|
-
|
51
|
-
end
|
32
|
+
return @msgstr.map(&:str).join.empty? if @msgstr.is_a? Array
|
33
|
+
|
52
34
|
@msgstr.nil? || @msgstr.str.empty?
|
53
35
|
end
|
54
|
-
|
36
|
+
alias incomplete? untranslated?
|
55
37
|
|
56
38
|
# Checks if the entry is translated
|
57
39
|
#
|
58
40
|
# @return [Boolean]
|
59
41
|
def translated?
|
60
42
|
return false if obsolete? || fuzzy?
|
61
|
-
|
43
|
+
|
44
|
+
!untranslated?
|
62
45
|
end
|
63
|
-
|
46
|
+
alias complete? translated?
|
64
47
|
|
65
48
|
# Checks if the entry is plural
|
66
49
|
#
|
@@ -74,10 +57,12 @@ module PoParser
|
|
74
57
|
# @return [Boolean]
|
75
58
|
def fuzzy?
|
76
59
|
return false if obsolete?
|
77
|
-
|
60
|
+
|
61
|
+
@flag.to_s.match?('fuzzy') ? true : false
|
78
62
|
end
|
79
63
|
|
80
64
|
# Flag the entry as Fuzzy
|
65
|
+
#
|
81
66
|
# @return [Entry]
|
82
67
|
def flag_as_fuzzy
|
83
68
|
@flag = 'fuzzy'
|
@@ -87,58 +72,54 @@ module PoParser
|
|
87
72
|
# Set flag to a custom string
|
88
73
|
def flag_as(flag)
|
89
74
|
raise ArgumentError if flag.class != String
|
75
|
+
|
90
76
|
@flag = flag
|
91
77
|
end
|
92
78
|
|
93
79
|
# Convert entry to a hash key value
|
80
|
+
#
|
94
81
|
# @return [Hash]
|
95
82
|
def to_h
|
96
|
-
|
97
|
-
instance_variables.each do |label|
|
83
|
+
instance_variables.each_with_object({}) do |label, hash|
|
98
84
|
object = instance_variable_get(label)
|
99
85
|
# If it's a plural msgstr
|
100
|
-
if object.is_a?
|
86
|
+
if object.is_a?(Array)
|
101
87
|
object.each do |entry|
|
102
|
-
hash[entry.type] = entry.to_s
|
88
|
+
hash[entry.type] = entry.to_s unless entry.nil?
|
103
89
|
end
|
104
90
|
else
|
105
|
-
hash[object.type] = object.to_s
|
91
|
+
hash[object.type] = object.to_s unless object.nil?
|
106
92
|
end
|
107
93
|
end
|
108
|
-
hash
|
109
94
|
end
|
110
95
|
|
111
96
|
# Convert entry to a string
|
97
|
+
#
|
112
98
|
# @return [String]
|
113
99
|
def to_s
|
114
|
-
|
115
|
-
LABELS.each do |label|
|
100
|
+
LABELS.each_with_object([]) do |label, arr|
|
116
101
|
object = instance_variable_get("@#{label}".to_sym)
|
117
102
|
# If it's a plural msgstr
|
118
|
-
if object.is_a?
|
119
|
-
object.
|
120
|
-
lines << entry.to_s(true) if not entry.nil?
|
121
|
-
end
|
103
|
+
if object.is_a?(Array)
|
104
|
+
arr.push(*object.map { |entry| entry.to_s(true) }.compact)
|
122
105
|
else
|
123
|
-
|
106
|
+
arr << object.to_s(true) unless object.nil?
|
124
107
|
end
|
125
|
-
end
|
126
|
-
|
127
|
-
lines.join
|
108
|
+
end.join
|
128
109
|
end
|
129
110
|
|
130
111
|
def inspect
|
131
112
|
to_s
|
132
113
|
end
|
133
114
|
|
134
|
-
|
115
|
+
private
|
135
116
|
|
136
117
|
def set_instance_variable(name, value)
|
137
118
|
if COMMENTS_LABELS.include? name
|
138
|
-
instance_variable_set "@#{name
|
119
|
+
instance_variable_set "@#{name}".to_sym, Comment.new(name, value)
|
139
120
|
elsif ENTRIES_LABELS.include? name
|
140
|
-
instance_variable_set "@#{name
|
141
|
-
elsif
|
121
|
+
instance_variable_set "@#{name}".to_sym, Message.new(name, value)
|
122
|
+
elsif /^msgstr\[[0-9]\]/.match?(name.to_s)
|
142
123
|
# If it's a plural msgstr
|
143
124
|
@msgstr ||= []
|
144
125
|
@msgstr << Message.new(name, value)
|
@@ -147,29 +128,34 @@ module PoParser
|
|
147
128
|
|
148
129
|
def define_writer_methods(labels, object)
|
149
130
|
object = PoParser.const_get(object)
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
klass.type = type
|
156
|
-
klass.value = val
|
157
|
-
else
|
158
|
-
instance_variable_set "@#{type}".to_sym, object.new(type, val)
|
159
|
-
end
|
160
|
-
# return value
|
161
|
-
instance_variable_get "@#{type}".to_sym
|
162
|
-
})
|
163
|
-
end
|
131
|
+
|
132
|
+
labels.each do |type, _mark|
|
133
|
+
next if Entry.method_defined?("#{type}=".to_sym)
|
134
|
+
|
135
|
+
define_writer_method(type, object)
|
164
136
|
end
|
165
137
|
end
|
166
138
|
|
139
|
+
def define_writer_method(type, object)
|
140
|
+
self.class.send(:define_method, "#{type}=".to_sym, lambda { |val|
|
141
|
+
if instance_variable_get("@#{type}".to_sym).is_a? object
|
142
|
+
klass = instance_variable_get "@#{type}".to_sym
|
143
|
+
klass.type = type
|
144
|
+
klass.value = val
|
145
|
+
else
|
146
|
+
instance_variable_set "@#{type}".to_sym, object.new(type, val)
|
147
|
+
end
|
148
|
+
# return value
|
149
|
+
instance_variable_get "@#{type}".to_sym
|
150
|
+
})
|
151
|
+
end
|
152
|
+
|
167
153
|
def define_reader_methods
|
168
154
|
LABELS.each do |label|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
155
|
+
next if Entry.method_defined? label.to_s.to_sym
|
156
|
+
|
157
|
+
self.class.send(:define_method, label.to_sym) do
|
158
|
+
instance_variable_get "@#{label}".to_sym
|
173
159
|
end
|
174
160
|
end
|
175
161
|
end
|
@@ -177,5 +163,41 @@ module PoParser
|
|
177
163
|
def valid_label?(label)
|
178
164
|
!(label =~ /^msgstr\[[0-9]\]/).nil? || LABELS.include?(label)
|
179
165
|
end
|
166
|
+
|
167
|
+
def define_labels_instance_variables
|
168
|
+
LABELS.each { |label| instance_variable_set("@#{label}".to_sym, nil) }
|
169
|
+
end
|
170
|
+
|
171
|
+
def define_obsolete_instance_variables
|
172
|
+
return unless obsolete?
|
173
|
+
|
174
|
+
obsolete_content = SimplePoParser.parse_message(
|
175
|
+
obsolete.value.join("\n").gsub(/^\|/, '#|'),
|
176
|
+
)
|
177
|
+
|
178
|
+
obsolete_content.each do |name, value|
|
179
|
+
raise(ArgumentError, "Unknown label #{name}") unless valid_label? name
|
180
|
+
|
181
|
+
set_instance_variable(name, value)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def define_args_instance_variables(args)
|
186
|
+
# Set passed arguments
|
187
|
+
args.each do |name, value|
|
188
|
+
raise(ArgumentError, "Unknown label #{name}") unless valid_label? name
|
189
|
+
|
190
|
+
set_instance_variable(name, value)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def define_aliases
|
195
|
+
self.class.send(:alias_method, :translate, :msgstr=)
|
196
|
+
self.class.send(:alias_method, :cached, :obsolete)
|
197
|
+
self.class.send(:alias_method, :cached=, :obsolete=)
|
198
|
+
# alias for backward compatibility of this typo
|
199
|
+
self.class.send(:alias_method, :refrence, :reference)
|
200
|
+
self.class.send(:alias_method, :refrence=, :reference=)
|
201
|
+
end
|
180
202
|
end
|
181
203
|
end
|
data/lib/poparser/header.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
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
|
@@ -11,27 +14,25 @@ module PoParser
|
|
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
|
@@ -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
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: PoParser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.3
|
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: 2019-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: simple_po_parser
|
@@ -56,7 +56,8 @@ description: A PO file parser, editor and generator. PO files are translation fi
|
|
56
56
|
generated by GNU/Gettext tool.
|
57
57
|
email:
|
58
58
|
- mousavi.arash@gmail.com
|
59
|
-
executables:
|
59
|
+
executables:
|
60
|
+
- rspec
|
60
61
|
extensions: []
|
61
62
|
extra_rdoc_files: []
|
62
63
|
files:
|
@@ -70,6 +71,7 @@ files:
|
|
70
71
|
- LICENSE.txt
|
71
72
|
- README.md
|
72
73
|
- Rakefile
|
74
|
+
- bin/rspec
|
73
75
|
- lib/poparser.rb
|
74
76
|
- lib/poparser/comment.rb
|
75
77
|
- lib/poparser/constants.rb
|
@@ -120,8 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
122
|
- !ruby/object:Gem::Version
|
121
123
|
version: '0'
|
122
124
|
requirements: []
|
123
|
-
|
124
|
-
rubygems_version: 2.7.6
|
125
|
+
rubygems_version: 3.0.3
|
125
126
|
signing_key:
|
126
127
|
specification_version: 4
|
127
128
|
summary: A PO file parser, editor and generator.
|