poesie 1.4.0 → 1.5.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: 3faa652a9f6ad87e650ba88a394d2f5d577e66b3
4
- data.tar.gz: 40ede2cb29bea6fd4abc16d0b27bb13daf00a308
3
+ metadata.gz: 147a5398c7444cb641b250e3b38a8394bf335d02
4
+ data.tar.gz: 944bde3b16366fa7ebf8cf1fba0721fc14bb5561
5
5
  SHA512:
6
- metadata.gz: 3d20a015a7232e8973d5a86ff956c5bb35fa1295889db5d3d70af44eee44077aa7d0b5dd9ec238a5a44b14457964baf4db7daeca4cef56a0531e2417b6389548
7
- data.tar.gz: dc1cfc402b131d401c0f0c0384ec5e06246f7882ce9d87002bc41cf59c19bd705d9a2fd1c7bae5f3d18a3d270e8fe50710106fcc58f20f820a8fff0e30dd79db
6
+ metadata.gz: 759e06722d8d15a7a73b728abe2cff5e07acbcecd0c00a9a2ffdd3cbdda6f8695ec1245e3b2fef37f6afd0b52821d76a8edbe576184c7aa62269852dcee99fc7
7
+ data.tar.gz: 5644643aaca8bcf56e24ea9989b2959c426b2eccaabd21dd935e90afd570da48db547595dd8e35d03a8ac38004ec9bb735d855a4135fbdb8392774c894ed73cc
data/README.md CHANGED
@@ -77,7 +77,8 @@ Of course, only list in POEditor the strings that needs a translation (user-faci
77
77
  ### Naming your terms
78
78
 
79
79
  * Find a name for your term that is consistent with existing keys
80
- * As a convention, for Niji projects, we structure the name of terms in a reverse-dns hierarchical text, using `_` as a separator. For example `home_banner_text` and `home_weather_temperature` (use `_` and not `.` because `.` causes issues in Android)
80
+ * As a convention, for Niji projects, we structure the name of terms in a reverse-dns hierarchical text, using `_` as a separator. For example `home_banner_text` and `home_weather_temperature`.
81
+ * For Android, if you have `.` in term names, they will be replaced with `_` (as `R.string.foo.bar` won't work in Android but `R.string.foo_bar` will)
81
82
  * If a key should only be exported for Android, use the `_android` suffix. If a key should only be exported for iOS, use the `_ios` suffix.
82
83
 
83
84
  ### Using `%…` placeholders
data/bin/poesie CHANGED
@@ -52,11 +52,11 @@ opts = OptionParser.new do |opts|
52
52
  options[:print_date] = true
53
53
  end
54
54
  opts.on('-s FILE', '--subst FILE', %q(Path to a YAML file listing all substitutions)) do |path|
55
- Poesie.exit_with_error("The substitutions file #{path} was not found") unless File.exists?(path)
55
+ Poesie.exit_with_error("The substitutions file #{path} was not found") unless File.exists?(path)
56
56
  begin
57
57
  subst = YAML.load_file(path)
58
58
  rescue Psych::SyntaxError => e
59
- Poesie.exit_with_error("Invalid YAML file #{e.message}")
59
+ Poesie.exit_with_error("Invalid YAML file #{e.message}")
60
60
  end
61
61
  subst = [subst] if subst.is_a?(Hash)
62
62
  valid = subst.all? { |hash| hash.keys.all? { |k| k.is_a?(String) } && hash.values.all? { |k| k.is_a?(String) } }
@@ -81,12 +81,14 @@ Poesie.exit_with_error('You need to specify your POEditor project identifier usi
81
81
  exporter = Poesie::Exporter.new(options[:api_token], options[:project_id])
82
82
  Poesie.exit_with_error('You need to specify your POEditor project language using --lang option (see --help for more info)') if options[:lang].nil?
83
83
 
84
- # iOS
85
- unless options[:localizable_strings].nil?
86
- Poesie::Log::title('== iOS ==')
87
- exporter.run(options[:lang]) do |terms|
84
+ exporter.run(options[:lang]) do |terms|
85
+ Poesie::Log::title("== Language #{options[:lang]} ==")
86
+
87
+ # iOS
88
+ unless options[:localizable_strings].nil?
89
+ Poesie::Log::subtitle('== iOS ==')
90
+
88
91
  # Localizable.strings
89
- Poesie::Log::subtitle("== Language #{options[:lang]} ==")
90
92
  Poesie::AppleFormatter::write_strings_file(
91
93
  terms,
92
94
  options[:localizable_strings],
@@ -102,21 +104,13 @@ unless options[:localizable_strings].nil?
102
104
  substitutions: options[:substitutions],
103
105
  print_date: options[:print_date]
104
106
  )
105
-
106
- # Context.json (if specified)
107
- if options[:context_file]
108
- Poesie::Log::subtitle("== Context #{options[:context_file]} ==")
109
- Poesie::AppleFormatter::write_context_json(terms, options[:context_file])
110
- end
111
107
  end
112
- end
113
108
 
114
- # Android
115
- unless options[:strings_xml].nil?
116
- Poesie::Log::title('== Android ==')
117
- exporter.run(options[:lang]) do |terms|
109
+ # Android
110
+ unless options[:strings_xml].nil?
111
+ Poesie::Log::subtitle('== Android ==')
112
+
118
113
  # Strings.xml
119
- Poesie::Log::subtitle("== Language #{options[:lang]} ==")
120
114
  Poesie::AndroidFormatter::write_strings_xml(
121
115
  terms,
122
116
  options[:strings_xml],
@@ -124,4 +118,13 @@ unless options[:strings_xml].nil?
124
118
  print_date: options[:print_date]
125
119
  )
126
120
  end
121
+
122
+ # Context.json (if specified)
123
+ if options[:context_file]
124
+ filters = nil
125
+ filters = Poesie::Filters::EXCLUDE_IOS if options[:localizable_strings].nil?
126
+ filters = Poesie::Filters::EXCLUDE_ANDROID if options[:strings_xml].nil?
127
+ Poesie::Log::subtitle("== Context ==")
128
+ Poesie::ContextFormatter::write_context_json(terms, options[:context_file], exclude: filters)
129
+ end
127
130
  end
@@ -13,9 +13,12 @@ module Poesie
13
13
  # The list of substitutions to apply to the translations
14
14
  # @param [Bool] print_date
15
15
  # Should we print the date in the header of the generated file
16
+ # @param [Regexp] exclude
17
+ # A regular expression to filter out terms.
18
+ # Terms matching this Regexp will be ignored and won't be part of the generated file
16
19
  #
17
- def self.write_strings_xml(terms, file, substitutions: nil, print_date: false)
18
- stats = { :ios => 0, :nil => [], :count => 0 }
20
+ def self.write_strings_xml(terms, file, substitutions: nil, print_date: false, exclude: Poesie::Filters::EXCLUDE_IOS)
21
+ stats = { :excluded => 0, :nil => [], :count => 0 }
19
22
 
20
23
  Log::info(" - Save to file: #{file}")
21
24
  File.open(file, "w") do |fh|
@@ -30,9 +33,13 @@ module Poesie
30
33
 
31
34
  # Filter terms and update stats
32
35
  next if (term.nil? || term.empty? || definition.nil?) && stats[:nil] << term
33
- next if (term =~ /_ios$/) && stats[:ios] += 1
36
+ next if (term =~ exclude) && stats[:excluded] += 1
34
37
  stats[:count] += 1
35
38
 
39
+ # Terms with dots are invalid in Android ("R.string.foo.bar" won't work), so replace dots with underscores
40
+ term.gsub!('.', '_')
41
+ plurals.gsub!('.', '_')
42
+
36
43
  xml_builder.comment!(context) unless context.empty?
37
44
  if plurals.empty?
38
45
  definition = Poesie::process(definition, substitutions).gsub('"', '\\"')
@@ -49,7 +56,10 @@ module Poesie
49
56
  end
50
57
  end
51
58
 
52
- Log::info(" [Stats] #{stats[:count]} strings processed (Filtered out #{stats[:ios]} iOS strings)")
59
+ Log::info(" [Stats] #{stats[:count]} strings processed")
60
+ unless exclude.nil?
61
+ Log::info(" Filtered out #{stats[:excluded]} strings matching #{exclude.inspect})")
62
+ end
53
63
  unless stats[:nil].empty?
54
64
  Log::error(" Found #{stats[:nil].count} empty value(s) for the following term(s):")
55
65
  stats[:nil].each { |key| Log::error(" - #{key.inspect}") }
@@ -13,20 +13,23 @@ module Poesie
13
13
  # The list of substitutions to apply to the translations
14
14
  # @param [Bool] print_date
15
15
  # Should we print the date in the header of the generated file
16
+ # @param [Regexp] exclude
17
+ # A regular expression to filter out terms.
18
+ # Terms matching this Regexp will be ignored and won't be part of the generated file
16
19
  #
17
- def self.write_strings_file(terms, file, substitutions: nil, print_date: false)
20
+ def self.write_strings_file(terms, file, substitutions: nil, print_date: false, exclude: Poesie::Filters::EXCLUDE_ANDROID)
18
21
  out_lines = ['/'+'*'*79, ' * Exported from POEditor - https://poeditor.com']
19
22
  out_lines << " * #{Time.now}" if print_date
20
23
  out_lines += [' '+'*'*79+'/', '']
21
24
  last_prefix = ''
22
- stats = { :android => 0, :nil => [], :count => 0 }
25
+ stats = { :excluded => 0, :nil => [], :count => 0 }
23
26
 
24
27
  terms.each do |term|
25
28
  (term, definition, comment, context) = ['term', 'definition', 'comment', 'context'].map { |k| term[k] }
26
29
 
27
30
  # Filter terms and update stats
28
31
  next if (term.nil? || term.empty? || definition.nil? || definition.empty?) && stats[:nil] << term
29
- next if (term =~ /_android$/) && stats[:android] += 1 # Remove android-specific strings
32
+ next if (term =~ exclude) && stats[:excluded] += 1
30
33
  stats[:count] += 1
31
34
 
32
35
  # Generate MARK from prefixes
@@ -57,7 +60,10 @@ module Poesie
57
60
  File.open(file, "w") do |fh|
58
61
  fh.write(content)
59
62
  end
60
- Log::info(" [Stats] #{stats[:count]} strings processed (Filtered out #{stats[:android]} android strings)")
63
+ Log::info(" [Stats] #{stats[:count]} strings processed")
64
+ unless exclude.nil?
65
+ Log::info(" Filtered out #{stats[:excluded]} strings matching #{exclude.inspect})")
66
+ end
61
67
  unless stats[:nil].empty?
62
68
  Log::error(" Found #{stats[:nil].count} empty value(s) for the following term(s):")
63
69
  stats[:nil].each { |key| Log::error(" - #{key.inspect}") }
@@ -74,9 +80,12 @@ module Poesie
74
80
  # The list of substitutions to apply to the translations
75
81
  # @param [Bool] print_date
76
82
  # Should we print the date in the header of the generated file
83
+ # @param [Regexp] exclude
84
+ # A regular expression to filter out terms.
85
+ # Terms matching this Regexp will be ignored and won't be part of the generated file
77
86
  #
78
- def self.write_stringsdict_file(terms, file, substitutions: nil, print_date: false)
79
- stats = { :android => 0, :nil => [], :count => 0 }
87
+ def self.write_stringsdict_file(terms, file, substitutions: nil, print_date: false, exclude: Poesie::Filters::EXCLUDE_ANDROID)
88
+ stats = { :excluded => 0, :nil => [], :count => 0 }
80
89
 
81
90
  Log::info(" - Save to file: #{file}")
82
91
  File.open(file, "w") do |fh|
@@ -92,10 +101,10 @@ module Poesie
92
101
 
93
102
  # Filter terms and update stats
94
103
  next if (term.nil? || term.empty? || definition.nil?) && stats[:nil] << term
95
- next if (term =~ /_android$/) && stats[:android] += 1 # Remove android-specific strings
104
+ next if (term =~ exclude) && stats[:excluded] += 1
96
105
  next unless definition.is_a? Hash
97
106
  stats[:count] += 1
98
-
107
+
99
108
  key = term_plural || term
100
109
 
101
110
  root_node.key(key)
@@ -124,55 +133,15 @@ module Poesie
124
133
  end
125
134
  end
126
135
  end
127
- Log::info(" [Stats] #{stats[:count]} strings processed (Filtered out #{stats[:android]} android strings)")
136
+
137
+ Log::info(" [Stats] #{stats[:count]} strings processed")
138
+ unless exclude.nil?
139
+ Log::info(" Filtered out #{stats[:excluded]} strings matching #{exclude.inspect})")
140
+ end
128
141
  unless stats[:nil].empty?
129
142
  Log::error(" Found #{stats[:nil].count} empty value(s) for the following term(s):")
130
143
  stats[:nil].each { |key| Log::error(" - #{key.inspect}") }
131
144
  end
132
145
  end
133
-
134
- # Write the JSON output file containing all context keys
135
- #
136
- # @param [Array<Hash<String, Any>>] terms
137
- # JSON returned by the POEditor API
138
- # @param [String] file
139
- # The path of the file to write
140
- #
141
- def self.write_context_json(terms, file)
142
- json_hash = { "date" => "#{Time.now}" }
143
-
144
- stats = { :android => 0, :nil => 0, :count => 0 }
145
-
146
- #switch on term / context
147
- array_context = Array.new
148
- terms.each do |term|
149
- (term, definition, comment, context) = ['term', 'definition', 'comment', 'context'].map { |k| term[k] }
150
-
151
- # Filter terms and update stats
152
- next if (term.nil? || term.empty? || context.nil? || context.empty?) && stats[:nil] += 1
153
- next if (term =~ /_android$/) && stats[:android] += 1 # Remove android-specific strings
154
- stats[:count] += 1
155
-
156
- # Escape some chars
157
- context = context
158
- .gsub("\u2028", '') # Sometimes inserted by the POEditor exporter
159
- .gsub("\\", "\\\\\\") # Replace actual \ with \\
160
- .gsub('\\\\"', '\\"') # Replace actual \\" with \"
161
- .gsub(/%(\d+\$)?s/, '%\1@') # replace %s with %@ for iOS
162
-
163
- array_context << { "term" => "#{term}", "context" => "#{context}" }
164
- end
165
-
166
- json_hash[:"contexts"] = array_context
167
-
168
- context_json = JSON.pretty_generate(json_hash)
169
-
170
- Log::info(" - Save to file: #{file}")
171
- File.open(file, "w") do |fh|
172
- fh.write(context_json)
173
- end
174
- Log::info(" [Stats] #{stats[:count]} contexts processed (Filtered out #{stats[:android]} android entries, #{stats[:nil]} nil contexts)")
175
- end
176
-
177
146
  end
178
147
  end
@@ -0,0 +1,55 @@
1
+ module Poesie
2
+ module ContextFormatter
3
+
4
+ # Write the JSON output file containing all context keys
5
+ #
6
+ # @param [Array<Hash<String, Any>>] terms
7
+ # JSON returned by the POEditor API
8
+ # @param [String] file
9
+ # The path of the file to write
10
+ # @param [Regexp] exclude
11
+ # A regular expression to filter out terms.
12
+ # Terms matching this Regexp will be ignored and won't be part of the generated file
13
+ #
14
+ def self.write_context_json(terms, file, exclude: nil)
15
+
16
+ json_hash = { "date" => "#{Time.now}" }
17
+
18
+ stats = { :excluded => 0, :nil => 0, :count => 0 }
19
+
20
+ #switch on term / context
21
+ array_context = Array.new
22
+ terms.each do |term|
23
+ (term, definition, comment, context) = ['term', 'definition', 'comment', 'context'].map { |k| term[k] }
24
+
25
+ # Filter terms and update stats
26
+ next if (term.nil? || term.empty? || context.nil? || context.empty?) && stats[:nil] += 1
27
+ next if (term =~ exclude) && stats[:excluded] += 1 # Remove android-specific strings
28
+
29
+ stats[:count] += 1
30
+
31
+ # Escape some chars
32
+ context = context
33
+ .gsub("\u2028", '') # Sometimes inserted by the POEditor exporter
34
+ .gsub("\\", "\\\\\\") # Replace actual \ with \\
35
+ .gsub('\\\\"', '\\"') # Replace actual \\" with \"
36
+ .gsub(/%(\d+\$)?s/, '%\1@') # replace %s with %@ for iOS
37
+
38
+ array_context << { "term" => "#{term}", "context" => "#{context}" }
39
+ end
40
+
41
+ json_hash[:"contexts"] = array_context
42
+
43
+ context_json = JSON.pretty_generate(json_hash)
44
+
45
+ Log::info(" - Save to file: #{file}")
46
+ File.open(file, "w") do |fh|
47
+ fh.write(context_json)
48
+ end
49
+ Log::info(" [Stats] #{stats[:count]} strings processed")
50
+ unless exclude.nil?
51
+ Log::info(" Filtered out #{stats[:excluded]} strings matching #{exclude.inspect})")
52
+ end
53
+ end
54
+ end
55
+ end
data/lib/filters.rb ADDED
@@ -0,0 +1,6 @@
1
+ module Poesie
2
+ module Filters
3
+ EXCLUDE_IOS = /_ios$/
4
+ EXCLUDE_ANDROID = /_android$/
5
+ end
6
+ end
data/lib/poesie.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  require File.expand_path('log', File.dirname(__FILE__))
2
2
  require File.expand_path('exporter', File.dirname(__FILE__))
3
+ require File.expand_path('filters', File.dirname(__FILE__))
3
4
  require File.expand_path('android_formatter', File.dirname(__FILE__))
4
5
  require File.expand_path('apple_formatter', File.dirname(__FILE__))
6
+ require File.expand_path('context_formatter', File.dirname(__FILE__))
5
7
 
6
8
  require 'json'
7
9
 
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Poesie
2
- VERSION = '1.4.0'
2
+ VERSION = '1.5.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poesie
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Olivier Halligon
@@ -9,48 +9,48 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-02-08 00:00:00.000000000 Z
12
+ date: 2017-02-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: net
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ~>
18
+ - - "~>"
19
19
  - !ruby/object:Gem::Version
20
20
  version: '0.3'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - ~>
25
+ - - "~>"
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0.3'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: activesupport
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ~>
32
+ - - "~>"
33
33
  - !ruby/object:Gem::Version
34
34
  version: '4.2'
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - ~>
39
+ - - "~>"
40
40
  - !ruby/object:Gem::Version
41
41
  version: '4.2'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: builder
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - ~>
46
+ - - "~>"
47
47
  - !ruby/object:Gem::Version
48
48
  version: '3.0'
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - ~>
53
+ - - "~>"
54
54
  - !ruby/object:Gem::Version
55
55
  version: '3.0'
56
56
  description: This script automates the export of POEditor strings to iOS and Android
@@ -66,7 +66,9 @@ files:
66
66
  - bin/poesie
67
67
  - lib/android_formatter.rb
68
68
  - lib/apple_formatter.rb
69
+ - lib/context_formatter.rb
69
70
  - lib/exporter.rb
71
+ - lib/filters.rb
70
72
  - lib/log.rb
71
73
  - lib/poesie.rb
72
74
  - lib/version.rb
@@ -80,12 +82,12 @@ require_paths:
80
82
  - lib
81
83
  required_ruby_version: !ruby/object:Gem::Requirement
82
84
  requirements:
83
- - - '>='
85
+ - - ">="
84
86
  - !ruby/object:Gem::Version
85
87
  version: 2.0.0
86
88
  required_rubygems_version: !ruby/object:Gem::Requirement
87
89
  requirements:
88
- - - '>='
90
+ - - ">="
89
91
  - !ruby/object:Gem::Version
90
92
  version: '0'
91
93
  requirements: []