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 +4 -4
- data/README.md +2 -1
- data/bin/poesie +22 -19
- data/lib/android_formatter.rb +14 -4
- data/lib/apple_formatter.rb +22 -53
- data/lib/context_formatter.rb +55 -0
- data/lib/filters.rb +6 -0
- data/lib/poesie.rb +2 -0
- data/lib/version.rb +1 -1
- metadata +12 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 147a5398c7444cb641b250e3b38a8394bf335d02
|
4
|
+
data.tar.gz: 944bde3b16366fa7ebf8cf1fba0721fc14bb5561
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
-
|
117
|
-
|
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
|
data/lib/android_formatter.rb
CHANGED
@@ -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 = { :
|
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 =~
|
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
|
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}") }
|
data/lib/apple_formatter.rb
CHANGED
@@ -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 = { :
|
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 =~
|
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
|
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 = { :
|
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 =~
|
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
|
-
|
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
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
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
|
+
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-
|
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: []
|