poesie 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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: []