PoParser 2.0.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4001750c5298956f310f421c8f9cfe8d8c64283c
4
- data.tar.gz: bff6cd76882df6d406cc2f993a010a48b41320b9
3
+ metadata.gz: 32f20604e8c93db11ec6985ba1080532234efb33
4
+ data.tar.gz: 43ffda461e75249098e7e4b3fd2fc5cbe8918359
5
5
  SHA512:
6
- metadata.gz: a67f9b02929802776b34717d0f4d3f3144bf500a9df17a4f9811f43446f15b64f964ccb0736486e44c73bc22760a3687a98fe0414c92e70843ef5247b7b8821e
7
- data.tar.gz: 2ffcdb67d60a39d43d49f55222e1dbae130a852522105a1452adebe57285332c68741ac60aefa8c5fbcedeed61a34cc66c183b7bace7588f62993296a7182db4
6
+ metadata.gz: e038dce601f0c92ce204a5bfb79f3298c6f1d048447515a373d9fb4fce007a548b1701b4d9f45ab9303f8f2f4d953772baa55baa2eabfa99c2f280bafee1d9c1
7
+ data.tar.gz: 02c28740f60996c1b1b3d1989a99f14cf97e50bf93aac8ff22df3691c3c43ee40ae1aa3ad408461d2704ef752ed93fe135b3bcfb0e634be3e364674ef74672fa
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ 3.0.0 / 2017-03-03
2
+ ==================
3
+ * replaced parslet with simple_po_parser. Speedup parsing by up to 500x.
4
+ Courtesy of @dfherr
1
5
 
2
6
  2.0.1 / 2016-12-29
3
7
  ==================
data/Gemfile CHANGED
@@ -2,14 +2,17 @@ source 'https://rubygems.org'
2
2
 
3
3
  group :test do
4
4
  gem 'coveralls', :require => false
5
- gem 'pry-byebug', :platforms => :mri
6
5
  gem 'rspec', '~> 3.5.0'
7
6
  gem 'awesome_print'
8
7
  end
9
8
 
10
9
  group :development do
11
- gem 'pry-byebug', :platforms => :mri
12
10
  gem 'guard-rspec'
11
+ gem 'ruby-prof'
12
+ end
13
+
14
+ group :test, :development do
15
+ gem 'pry-byebug', :platforms => :mri
13
16
  end
14
17
 
15
18
  # Specify your gem's dependencies in poparser.gemspec
data/README.md CHANGED
@@ -103,7 +103,9 @@ translator_comment
103
103
  reference
104
104
  extracted_comment
105
105
  flag
106
- previous_untraslated_string
106
+ previous_msgctxt
107
+ previous_msgid
108
+ previous_msgid_plural
107
109
  cached # obsolete entries
108
110
  msgid
109
111
  msgid_plural
@@ -140,6 +142,16 @@ entry.msgstr.to_s
140
142
  #=> "This entry is translated"
141
143
  ```
142
144
 
145
+ But be careful with plural messages, there msgstr is an array
146
+ ```ruby
147
+ if entry.plural?
148
+ entry.msgstr.each do |msgstr|
149
+ msgstr.to_s
150
+ #=> This is one of the plural translations
151
+ end
152
+ end
153
+ ```
154
+
143
155
  You can mark an entry as fuzzy:
144
156
 
145
157
  ```ruby
@@ -220,6 +232,16 @@ You can get and set following variables from `header`:
220
232
  * Update header after changing/saving po
221
233
  * add `before_save` and `after_save` callbacks
222
234
 
235
+ ##Authors
236
+
237
+ [Arash Mousavi](https://github.com/arashm)
238
+
239
+ ### [Contributors](https://github.com/arashm/PoParser/contributors)
240
+ - [Dennis-Florian Herr](https://github.com/dfherr)
241
+ - [Roland Gropmair](https://github.com/roland9)
242
+
243
+ License: [MIT](https://github.com/arashm/PoParser/blob/master/LICENSE.txt)
244
+
223
245
  ## Contributing
224
246
 
225
247
  1. Fork it ( http://github.com/arashm/poparser/fork )
data/Rakefile CHANGED
@@ -1 +1,65 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :default => :spec
9
+
10
+ desc "Generate a random po file. Takes optional rake args for number of entries"
11
+ task 'generate_random_pofile', :messages, :obsoletes do |t, args|
12
+ args.with_defaults(:messages => "200", :obsoletes => "10")
13
+ require_relative 'spec/utils/random_pofile_generator'
14
+ PoParser::RandomPoFileGenerator.generate_file(
15
+ File.expand_path("test/benchmark.po", __dir__), args[:messages].to_i, args[:obsoletes].to_i
16
+ )
17
+ end
18
+
19
+ namespace :debug do
20
+ require 'benchmark'
21
+ require_relative 'lib/poparser'
22
+
23
+ desc "Benchmark of 10 full PoParser runs of test/benchmark.po"
24
+ task "benchmark" do
25
+ pofile = File.expand_path("test/benchmark.po", __dir__)
26
+ Benchmark.bmbm do |x|
27
+ x.report("Parser:") {10.times { PoParser.new.parse(pofile) }}
28
+ end
29
+ end
30
+
31
+ desc "Generate 5 random PO files with 100 to 500 messages and benchmark each full PoParser run"
32
+ task 'five_random_po_full' do
33
+ include Benchmark
34
+ require_relative 'spec/utils/random_pofile_generator'
35
+ pofile = File.expand_path("test/benchmark.po.tmp", __dir__)
36
+ Benchmark.benchmark(CAPTION, 6, FORMAT, "total:") do |x|
37
+ total = nil
38
+ total_length = 0
39
+ for i in 0..5 do
40
+ length = (Random.new.rand * 400.0 + 100).to_i
41
+ total_length += length
42
+ puts "Benchmarking file of length #{length}"
43
+ SimplePoParser::RandomPoFileGenerator.generate_file(pofile, length)
44
+ t = x.report("try#{i}:") {PoParser.new.parse(pofile)}
45
+ File.unlink(pofile)
46
+ total = total ? total+t : t
47
+ end
48
+ puts "Total message length #{total_length}"
49
+ [total]
50
+ end
51
+ end
52
+
53
+ desc "Show ruby-prof profiler for spec/fixtures/complex_entry.po"
54
+ task "profile_parser" do
55
+ require 'ruby-prof'
56
+ RubyProf.start
57
+ po_message = File.read(File.expand_path("spec/simple_po_parser/fixtures/complex_entry.po", __dir__))
58
+ PoParser.new.parse(po_message)
59
+ result = RubyProf.stop
60
+
61
+ printer = RubyProf::FlatPrinter.new(result)
62
+ printer.print(STDOUT)
63
+ end
64
+
65
+ end
@@ -10,23 +10,50 @@ module PoParser
10
10
  def to_s(with_label = false)
11
11
  return to_str unless with_label
12
12
  if @value.is_a? Array
13
- string = []
14
- @value.each do |str|
15
- string << "#{COMMENTS_LABELS[@type]} #{str}\n".gsub(/[^\S\n]+$/, '')
13
+ if @type.to_s =~ /^previous_/ # these behave more like messages
14
+ remove_empty_line
15
+ string = ["#{COMMENTS_LABELS[@type]} \"\"\n"]
16
+ @value.each do |str|
17
+ string << "#| \"#{str}\"\n".gsub(/[\p{Blank}]+$/, '')
18
+ end
19
+ else
20
+ string = []
21
+ @value.each do |str|
22
+ string << "#{COMMENTS_LABELS[@type]} #{str}\n".gsub(/[\p{Blank}]+$/, '')
23
+ end
16
24
  end
17
25
  return string.join
18
26
  else
19
- # removes the space but not newline at the end
20
- "#{COMMENTS_LABELS[@type]} #{@value}\n".gsub(/[^\S\n]+$/, '')
27
+ if @type.to_s =~ /^previous_/ # these behave more like messages
28
+ "#{COMMENTS_LABELS[@type]} \"#{@value}\"\n".gsub(/[\p{Blank}]+$/, '')
29
+ else
30
+ # removes the space but not newline at the end
31
+ "#{COMMENTS_LABELS[@type]} #{@value}\n".gsub(/[\p{Blank}]+$/, '')
32
+ end
21
33
  end
22
34
  end
23
35
 
24
36
  def to_str
25
- @value.is_a?(Array) ? @value.join : @value
37
+ if @value.is_a?(Array)
38
+ if @type.to_s =~ /^previous_/ # these behave more like messages
39
+ @value.join
40
+ else
41
+ @value.join("\n")
42
+ end
43
+ else
44
+ @value
45
+ end
26
46
  end
27
47
 
28
48
  def inspect
29
49
  @value
30
50
  end
51
+
52
+ private
53
+ def remove_empty_line
54
+ if @value.is_a? Array
55
+ @value.shift if @value.first == ''
56
+ end
57
+ end
31
58
  end
32
59
  end
@@ -4,8 +4,10 @@ module PoParser
4
4
  :extracted_comment => '#.',
5
5
  :reference => '#:',
6
6
  :flag => '#,',
7
- :previous_untraslated_string => '#|',
8
- :cached => '#~'
7
+ :previous_msgctxt => '#| msgctxt',
8
+ :previous_msgid => '#| msgid',
9
+ :previous_msgid_plural => '#| msgid_plural',
10
+ :obsolete => '#~'
9
11
  }
10
12
 
11
13
  ENTRIES_LABELS = {
@@ -18,27 +18,27 @@ module PoParser
18
18
  define_reader_methods
19
19
 
20
20
  self.class.send(:alias_method, :translate, :msgstr=)
21
- self.class.send(:alias_method, :obsolete, :cached)
22
- self.class.send(:alias_method, :obsolete=, :cached=)
21
+ self.class.send(:alias_method, :cached, :obsolete)
22
+ self.class.send(:alias_method, :cached=, :obsolete=)
23
23
  # alias for backward compatibility of this typo
24
24
  self.class.send(:alias_method, :refrence, :reference)
25
- self.class.send(:alias_method, :refrence=, :reference)
25
+ self.class.send(:alias_method, :refrence=, :reference=)
26
26
  end
27
27
 
28
- # If entry doesn't have any msgid, it's probably a cached entry that is
28
+ # If entry doesn't have any msgid, it's probably a obsolete entry that is
29
29
  # kept by the program for later use. These entries will usually start with: #~
30
30
  #
31
31
  # @return [Boolean]
32
- def cached?
33
- !@cached.nil?
32
+ def obsolete?
33
+ !@obsolete.nil?
34
34
  end
35
- alias_method :obsolete?, :cached?
35
+ alias_method :cached?, :obsolete?
36
36
 
37
37
  # Checks if the entry is untraslated
38
38
  #
39
39
  # @return [Boolean]
40
40
  def untranslated?
41
- return false if cached? || fuzzy?
41
+ return false if obsolete? || fuzzy?
42
42
  if @msgstr.is_a? Array
43
43
  return @msgstr.map {|ms| ms.str}.join.empty?
44
44
  end
@@ -50,7 +50,7 @@ module PoParser
50
50
  #
51
51
  # @return [Boolean]
52
52
  def translated?
53
- return false if cached? || fuzzy?
53
+ return false if obsolete? || fuzzy?
54
54
  not untranslated?
55
55
  end
56
56
  alias_method :complete? , :translated?
@@ -66,7 +66,7 @@ module PoParser
66
66
  #
67
67
  # @return [Boolean]
68
68
  def fuzzy?
69
- return false if cached?
69
+ return false if obsolete?
70
70
  @flag.to_s.match('fuzzy') ? true : false
71
71
  end
72
72
 
@@ -70,6 +70,26 @@ module PoParser
70
70
  string.join("\n")
71
71
  end
72
72
 
73
+ def inspect
74
+ string = []
75
+ if @comments.is_a?(Array)
76
+ @comments.each do |comment|
77
+ string << "# #{comment}".strip
78
+ end
79
+ else
80
+ string << "# #{@comments}".strip
81
+ end
82
+ string << "#, #{@flag.to_s}" if @flag
83
+ string << "msgid \"\"\nmsgstr \"\""
84
+ configs.each do |k, v|
85
+ if v.nil? || v.empty?
86
+ next
87
+ end
88
+ string << "#{k}: #{v}\n".dump
89
+ end
90
+ string.join("\n")
91
+ end
92
+
73
93
  private
74
94
  def convert_msgstr_to_hash(msgstr)
75
95
  options_array = msgstr.value.map do |options|
data/lib/poparser/po.rb CHANGED
@@ -38,14 +38,14 @@ module PoParser
38
38
 
39
39
  # Returns an array of all entries in po file
40
40
  #
41
- # @param include_cached [Boolean] Whether include cached entries or not
41
+ # @param include_obsolete [Boolean] Whether include obsolete entries or not
42
42
  # @return [Array]
43
- def entries(include_cached=false)
44
- if include_cached
43
+ def entries(include_obsolete=false)
44
+ if include_obsolete
45
45
  @entries
46
46
  else
47
47
  find_all do |entry|
48
- !entry.cached?
48
+ !entry.obsolete?
49
49
  end
50
50
  end
51
51
  end
@@ -78,17 +78,17 @@ module PoParser
78
78
  end
79
79
  end
80
80
 
81
- # Finds all cached entries
81
+ # Finds all obsolete entries
82
82
  #
83
- # @return [Array] an array of cached entries
84
- def cached
83
+ # @return [Array] an array of obsolete entries
84
+ def obsolete
85
85
  find_all do |entry|
86
- entry.cached?
86
+ entry.obsolete?
87
87
  end
88
88
  end
89
- alias_method :obsolete, :cached
89
+ alias_method :obsolete, :obsolete
90
90
 
91
- # Count of all entries without counting cached entries
91
+ # Count of all entries without counting obsolete entries
92
92
  #
93
93
  # @return [String]
94
94
  def size
@@ -2,33 +2,21 @@ module PoParser
2
2
  # Feed each block of PO file to Parser.
3
3
  class Tokenizer
4
4
  def initialize
5
- @parser = Parser.new
6
- @po = Po.new
5
+ @po = Po.new
7
6
  end
8
7
 
9
8
  def extract_entries(path)
10
9
  @po.path = path
11
- block = ''
12
- File.open(path, 'r') do |f|
13
- f.each_line do |line|
14
- if line.match(/^\n$/)
15
- @po << parse_block(block) if block != ''
16
- block = ''
17
- elsif f.eof?
18
- block += line
19
- @po << parse_block(block)
20
- else
21
- block += line
22
- end
23
- end
10
+ File.open(path, 'r').each_line("\n\n") do |block|
11
+ block.strip!
12
+ @po << parse_block(block) if block != ''
24
13
  end
25
14
  @po
26
15
  end
27
16
 
28
17
  private
29
18
  def parse_block(block)
30
- parsed_hash = @parser.parse(block)
31
- Transformer.new.transform(parsed_hash)
19
+ hash = SimplePoParser.parse_message(block)
32
20
  end
33
21
  end
34
22
  end
@@ -1,3 +1,3 @@
1
1
  module PoParser
2
- VERSION = "2.0.1"
2
+ VERSION = "3.0.0"
3
3
  end
data/lib/poparser.rb CHANGED
@@ -1,17 +1,15 @@
1
1
  # External Libs
2
- require 'parslet'
2
+ require 'simple_po_parser'
3
3
 
4
4
  # Local files
5
- require 'poparser/constants'
6
- require 'poparser/parser'
7
- require 'poparser/transformer'
8
- require 'poparser/tokenizer'
9
- require 'poparser/comment'
10
- require 'poparser/message'
11
- require 'poparser/header'
12
- require 'poparser/entry'
13
- require 'poparser/po'
14
- require 'poparser/version'
5
+ require_relative 'poparser/constants'
6
+ require_relative 'poparser/tokenizer'
7
+ require_relative 'poparser/comment'
8
+ require_relative 'poparser/message'
9
+ require_relative 'poparser/header'
10
+ require_relative 'poparser/entry'
11
+ require_relative 'poparser/po'
12
+ require_relative 'poparser/version'
15
13
 
16
14
  module PoParser
17
15
  class << self
data/poparser.gemspec CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  # Runtime deps
22
- spec.add_runtime_dependency "parslet", "~> 1.7"
22
+ spec.add_runtime_dependency "simple_po_parser", "~> 1.1"
23
23
 
24
24
  # Development deps
25
25
  spec.add_development_dependency "bundler", ">= 0"
@@ -10,7 +10,9 @@ describe PoParser::Comment do
10
10
 
11
11
  it 'converts array of same comment to string' do
12
12
  comment = PoParser::Comment.new(:translator_comment, ["this is a line", "this is another line"])
13
- result = "# this is a line\n# this is another line\n"
14
- expect(comment.to_s(true)).to eq(result)
13
+ result = "this is a line\nthis is another line"
14
+ result_with_label = "# this is a line\n# this is another line\n"
15
+ expect(comment.to_s).to eq(result)
16
+ expect(comment.to_s(true)).to eq(result_with_label)
15
17
  end
16
18
  end
@@ -8,8 +8,7 @@ describe PoParser::Entry do
8
8
  end
9
9
 
10
10
  let(:labels) do
11
- [:reference, :refrence, :extracted_comment, :flag, :previous_untraslated_string,
12
- :translator_comment, :msgid, :msgid_plural, :msgstr, :msgctxt]
11
+ PoParser::LABELS + [:refrence] # backward typos
13
12
  end
14
13
 
15
14
  it 'should respond to labels' do
@@ -90,16 +89,34 @@ describe PoParser::Entry do
90
89
  end
91
90
  end
92
91
 
93
- context 'Cached' do
92
+ context 'Previous' do
93
+ it 'should be able to show content of previous_msgid' do
94
+ @entry.previous_msgid = 'Hello'
95
+ result = "Hello"
96
+ result_with_label = "#| msgid \"Hello\"\n"
97
+ expect(@entry.previous_msgid.to_s).to eq result
98
+ expect(@entry.previous_msgid.to_s(true)).to eq result_with_label
99
+ end
100
+
101
+ it 'convert multiline entries to string' do
102
+ @entry.previous_msgid = ['first line\n', 'second line']
103
+ result = "first line\\nsecond line"
104
+ result_with_label = "#| msgid \"\"\n#| \"first line\\n\"\n#| \"second line\"\n"
105
+ expect(@entry.previous_msgid.to_s).to eq result
106
+ expect(@entry.previous_msgid.to_s(true)).to eq result_with_label
107
+ end
108
+ end
109
+
110
+ context 'obsolete' do
94
111
  before do
95
112
  @entry = PoParser::Entry.new
96
- @entry.cached = '#~ msgid "a cached entry"'
113
+ @entry.obsolete = '#~ msgid "a obsolete entry"'
97
114
  @entry.flag = 'Fuzzy'
98
115
  end
99
116
 
100
- it 'checks for chached entries' do
101
- expect(@entry.cached?).to be_truthy
117
+ it 'checks for obsolete entries' do
102
118
  expect(@entry.obsolete?).to be_truthy
119
+ expect(@entry.cached?).to be_truthy
103
120
  end
104
121
 
105
122
  it 'shouldn be counted as untranslated' do
@@ -39,11 +39,11 @@ describe PoParser::Po do
39
39
  expect(@po.untranslated.size).to eq 2
40
40
  end
41
41
 
42
- it 'returns all cached strings' do
42
+ it 'returns all obsolete strings' do
43
43
  entry2, entry3 = entry.dup, entry.dup
44
- [entry2, entry3].each { |en| en[:cached] = 'test' }
44
+ [entry2, entry3].each { |en| en[:obsolete] = 'test' }
45
45
  @po << [entry, entry2, entry3]
46
- expect(@po.cached.size).to eq 2
46
+ expect(@po.obsolete.size).to eq 2
47
47
  end
48
48
 
49
49
  it 'shows stats' do
@@ -58,10 +58,10 @@ describe PoParser::Po do
58
58
  expect(result[:fuzzy]).to eq 25
59
59
  end
60
60
 
61
- it 'shouldn\'t count cached entries' do
61
+ it 'shouldn\'t count obsolete entries' do
62
62
  @po << entry
63
- cached = { cached: 'sth', flag: 'Fuzzy' }
64
- @po << cached
63
+ obsolete = { obsolete: 'sth', flag: 'Fuzzy' }
64
+ @po << obsolete
65
65
  expect(@po.size).to eq(1)
66
66
  end
67
67
 
@@ -3,8 +3,134 @@ require "spec_helper"
3
3
 
4
4
  describe PoParser do
5
5
  let(:po_file) { Pathname.new('spec/poparser/fixtures/tokenizer.po').realpath }
6
+ let(:header_fixture) { Pathname.new('spec/poparser/fixtures/header.po').realpath }
7
+ let(:multiline_fixture) { Pathname.new('spec/poparser/fixtures/multiline.po').realpath }
8
+ let(:plural_fixture) { Pathname.new('spec/poparser/fixtures/plural.po').realpath }
9
+ let(:test_fixture) { Pathname.new('spec/poparser/fixtures/test.po').realpath }
6
10
 
7
11
  it 'parses a file' do
8
12
  expect(PoParser.parse(po_file)).to be_a_kind_of PoParser::Po
9
13
  end
14
+
15
+ it 'correclty parses header fixture' do
16
+ entry = PoParser::Entry.new(
17
+ {
18
+ :translator_comment => [
19
+ "Arash Mousavi <mousavi.arash@gmail.com>, 2014.",
20
+ ""],
21
+ :flag => "fuzzy",
22
+ :msgid => "",
23
+ :msgstr => [
24
+ "",
25
+ "Project-Id-Version: damned-lies master\\n",
26
+ "Report-Msgid-Bugs-To: \\n"]
27
+ })
28
+ expected_result = PoParser::Header.new(entry)
29
+ expect(PoParser.parse(header_fixture).header.inspect).to eql(expected_result.inspect)
30
+ end
31
+
32
+ it 'correclty parses multiline fixture' do
33
+ expected_result = PoParser::Entry.new(
34
+ {
35
+ :msgid => [
36
+ "",
37
+ "first",
38
+ "second"],
39
+ :msgstr => [
40
+ "",
41
+ "aval",
42
+ "dovom"]
43
+ })
44
+ expect(PoParser.parse(multiline_fixture).entries[0].inspect).to eq(expected_result.inspect)
45
+ end
46
+
47
+ it 'correclty parses plural fixture' do
48
+ expected_result = PoParser::Entry.new(
49
+ {
50
+ :msgid => " including <a href=\\\"%(img_url)s\\\">%(stats)s image</a>",
51
+ :msgid_plural => " including <a href=\\\"%(img_url)s\\\">%(stats)s images</a>",
52
+ "msgstr[0]" => [
53
+ "",
54
+ "sad ads fdsaf ds fdfs dsa "
55
+ ],
56
+ "msgstr[1]" => [
57
+ "",
58
+ "sad ads fdsaf ds fdfs dsa "
59
+ ]
60
+ })
61
+ expect(PoParser.parse(plural_fixture).entries[0].inspect).to eq(expected_result.inspect)
62
+ end
63
+
64
+ it 'correclty parses test fixture' do
65
+ expected_result = PoParser::Po.new
66
+ expected_result << { :translator_comment => [
67
+ "Persian translation for damned-lies.",
68
+ "Copyright (C) 2012 damned-lies's COPYRIGHT HOLDER",
69
+ "This file is distributed under the same license as the damned-lies package.",
70
+ "Arash Mousavi <mousavi.arash@gmail.com>, 2014.",
71
+ ""
72
+ ],
73
+ :msgid => "",
74
+ :msgstr => [
75
+ "",
76
+ "Project-Id-Version: damned-lies master\\n",
77
+ "Report-Msgid-Bugs-To: \\n",
78
+ "POT-Creation-Date: 2012-05-04 12:56+0000\\n",
79
+ "PO-Revision-Date: 2014-05-15 22:24+0330\\n",
80
+ "Last-Translator: Arash Mousavi <mousavi.arash@gmail.com>\\n",
81
+ "Language-Team: Persian <fa@li.org>\\n",
82
+ "MIME-Version: 1.0\\n",
83
+ "Content-Type: text/plain; charset=UTF-8\\n",
84
+ "Content-Transfer-Encoding: 8bit\\n",
85
+ "Plural-Forms: nplurals=1; plural=0;\\n",
86
+ "X-Generator: Poedit 1.6.4\\n"
87
+ ]
88
+ }
89
+ expected_result << {
90
+ :reference => "database-content.py:1 database-content.py:129 settings.py:52",
91
+ :msgid => "Afrikaans",
92
+ :msgstr => "آفریقایی"
93
+ }
94
+ expected_result << { :reference => "templates/vertimus/vertimus_detail.html:105",
95
+ :flag => "python-format",
96
+ :msgid => " including <a href=\\\"%(img_url)s\\\">%(stats)s image</a>",
97
+ :msgid_plural => " including <a href=\\\"%(img_url)s\\\">%(stats)s images</a>",
98
+ "msgstr[0]" => "",
99
+ "msgstr[1]" => ""
100
+ }
101
+ expected_result << {
102
+ :reference => "templates/vertimus/vertimus_detail.html:136 vertimus/forms.py:79",
103
+ :msgid => "Invalid action. Someone probably posted another action just before you.",
104
+ :msgstr => [
105
+ "",
106
+ "فعالیت نامعتبر. شاید یک نفر دیگر دقیقا قبل از شما یک فعالیت دیگر ارسال کرده ",
107
+ "است."
108
+ ]
109
+ }
110
+ expected_result << { :reference => "vertimus/models.py:470",
111
+ :flag => "python-format",
112
+ :previous_msgid => [
113
+ "",
114
+ "Hello,\\n",
115
+ "\\n",
116
+ "The new state of %(module)s - %(branch)s - %(domain)s (%(language)s) is ",
117
+ "now '%(new_state)s'.\\n",
118
+ "%(url)s\\n",
119
+ "\\n"
120
+ ],
121
+ :msgid => [
122
+ "",
123
+ "The new state of %(module)s - %(branch)s - %(domain)s (%(language)s) is now ",
124
+ "'%(new_state)s'."
125
+ ],
126
+ :msgstr => [
127
+ "",
128
+ "وضعیت جدید %(module)s - %(branch)s - %(domain)s (%(language)s) هم‌اکنون ",
129
+ "«%(new_state)s» است."
130
+ ]
131
+ }
132
+ allow_any_instance_of(PoParser::Header).to receive(:puts)
133
+ expect(PoParser.parse(test_fixture).to_s).to eq(expected_result.to_s)
134
+ end
135
+
10
136
  end