twine 0.5.0 → 0.6.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 +25 -0
- data/bin/twine +1 -2
- data/lib/twine.rb +1 -0
- data/lib/twine/cli.rb +2 -2
- data/lib/twine/formatters.rb +19 -2
- data/lib/twine/formatters/abstract.rb +7 -2
- data/lib/twine/formatters/android.rb +3 -0
- data/lib/twine/formatters/jquery.rb +10 -19
- data/lib/twine/formatters/tizen.rb +175 -0
- data/lib/twine/plugin.rb +62 -0
- data/lib/twine/runner.rb +5 -3
- data/lib/twine/version.rb +1 -1
- data/test/fixtures/en-1.json +0 -7
- data/test/fixtures/en-3.xml +8 -0
- data/test/fixtures/test-json-line-breaks/consumed.txt +5 -0
- data/test/fixtures/test-json-line-breaks/generated.json +3 -0
- data/test/fixtures/test-json-line-breaks/line-breaks.json +3 -0
- data/test/fixtures/test-json-line-breaks/line-breaks.txt +4 -0
- data/test/fixtures/test-output-10.txt +9 -0
- data/test/fixtures/test-output-11.txt +9 -0
- data/test/fixtures/test-output-12.txt +12 -0
- data/test/fixtures/test-output-5.txt +1 -8
- data/test/twine_test.rb +40 -0
- metadata +27 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c52c16544077b748fb773dd7cd3f8d7f88172eeb
|
4
|
+
data.tar.gz: a4db219ebbef41d69c00a59e46d09971be26ba4a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18423f5df5e0feda3ebd2e5e74c65ccb1bea506022ec79ee0d180f609e7acb2402348e1c37f78e02e00eee02933e6f6ba0f308b23e846d7e5e4e8896ad49b9c3
|
7
|
+
data.tar.gz: 010dca262cae3a0766d99d5a34aede2c05dba4ad5489d03c4798808cea3902fe3c5c443302e38712af26be12c3f8dedc442f3a25da2d483fc00adce9f5c36b4a
|
data/README.md
CHANGED
@@ -77,6 +77,7 @@ Twine currently supports the following formats for outputting strings:
|
|
77
77
|
* [Gettext PO Files][gettextpo] (format: gettext)
|
78
78
|
* [jquery-localize Language Files][jquerylocalize] (format: jquery)
|
79
79
|
* [Django PO Files][djangopo] (format: django)
|
80
|
+
* [Tizen String Resources][tizen] (format: tizen)
|
80
81
|
|
81
82
|
If you would like to enable twine to create language files in another format, create an appropriate formatter in `lib/twine/formatters`.
|
82
83
|
|
@@ -163,6 +164,28 @@ Now, whenever you build your application, Xcode will automatically invoke Twine
|
|
163
164
|
* [Twine TextMate 2 Bundle](https://github.com/mobiata/twine.tmbundle) — This [TextMate 2](https://github.com/textmate/textmate) bundle will make it easier for you to work with Twine strings files. In particular, it lets you use code folding to easily collapse and expand both strings and sections.
|
164
165
|
* [twine_ui](https://github.com/Daij-Djan/twine_ui) — A user interface for Twine written by [Dominik Pich](https://github.com/Daij-Djan/). Consider using this if you would prefer to use Twine without dropping to a command line.
|
165
166
|
|
167
|
+
## Plugin Support
|
168
|
+
|
169
|
+
Twine supports a basic plugin infrastructure, allowing third-party code to provide support for additional formatters. Twine will read a yaml config file specifying which plugins to load from three locations.
|
170
|
+
|
171
|
+
0. `./twine.yml` The current working directory
|
172
|
+
0. `~/.twine` The home directory
|
173
|
+
0. `/etc/twine.yml` The etc directory
|
174
|
+
|
175
|
+
Plugins are specified as values for the `gems` key. The following is an example config:
|
176
|
+
|
177
|
+
```
|
178
|
+
gems: appium_twine
|
179
|
+
```
|
180
|
+
|
181
|
+
Multiple gems can also be specfied in the yaml file.
|
182
|
+
|
183
|
+
```
|
184
|
+
gems: [appium_twine, some_other_plugin]
|
185
|
+
```
|
186
|
+
|
187
|
+
[appium_twine](https://github.com/appium/appium_twine) is a sample plugin used to provide a C# formatter.
|
188
|
+
|
166
189
|
## Contributors
|
167
190
|
|
168
191
|
Many thanks to all of the contributors to the Twine project, including:
|
@@ -174,6 +197,7 @@ Many thanks to all of the contributors to the Twine project, including:
|
|
174
197
|
* [Kevin Wood](https://github.com/kwood)
|
175
198
|
* [Mohammad Hejazi](https://github.com/MohammadHejazi)
|
176
199
|
* [Robert Guo](http://www.robertguo.me/)
|
200
|
+
* [Sergey Pisarchik](https://github.com/SergeyPisarchik)
|
177
201
|
* [Shai Shamir](https://github.com/pichirichi)
|
178
202
|
|
179
203
|
|
@@ -185,3 +209,4 @@ Many thanks to all of the contributors to the Twine project, including:
|
|
185
209
|
[gettextpo]: http://www.gnu.org/savannah-checkouts/gnu/gettext/manual/html_node/PO-Files.html
|
186
210
|
[jquerylocalize]: https://github.com/coderifous/jquery-localize
|
187
211
|
[djangopo]: https://docs.djangoproject.com/en/dev/topics/i18n/translation/
|
212
|
+
[tizen]: https://developer.tizen.org/documentation/articles/localization
|
data/bin/twine
CHANGED
data/lib/twine.rb
CHANGED
data/lib/twine/cli.rb
CHANGED
@@ -45,7 +45,7 @@ module Twine
|
|
45
45
|
@options[:untagged] = true
|
46
46
|
end
|
47
47
|
formats = []
|
48
|
-
Formatters
|
48
|
+
Formatters.formatters.each do |formatter|
|
49
49
|
formats << formatter::FORMAT_NAME
|
50
50
|
end
|
51
51
|
opts.on('-f', '--format FORMAT', "The file format to read or write (#{formats.join(', ')}). Additional formatters can be placed in the formats/ directory.") do |format|
|
@@ -93,7 +93,7 @@ module Twine
|
|
93
93
|
opts.separator '> twine generate-string-file strings.txt ko.xml --tags FT'
|
94
94
|
opts.separator '> twine generate-all-string-files strings.txt Resources/Locales/ --tags FT,FB'
|
95
95
|
opts.separator '> twine consume-string-file strings.txt ja.strings'
|
96
|
-
opts.separator '> twine consume-all-string-files strings.txt Resources/Locales/ --developer-language en'
|
96
|
+
opts.separator '> twine consume-all-string-files strings.txt Resources/Locales/ --developer-language en --tags DefaultTag1,DefaultTag2'
|
97
97
|
opts.separator '> twine generate-loc-drop strings.txt LocDrop5.zip --tags FT,FB --format android --lang de,en,en-GB,ja,ko'
|
98
98
|
opts.separator '> twine consume-loc-drop strings.txt LocDrop5.zip'
|
99
99
|
opts.separator '> twine generate-report strings.txt'
|
data/lib/twine/formatters.rb
CHANGED
@@ -5,9 +5,26 @@ require 'twine/formatters/flash'
|
|
5
5
|
require 'twine/formatters/gettext'
|
6
6
|
require 'twine/formatters/jquery'
|
7
7
|
require 'twine/formatters/django'
|
8
|
+
require 'twine/formatters/tizen'
|
8
9
|
|
9
10
|
module Twine
|
10
11
|
module Formatters
|
11
|
-
|
12
|
+
@formatters = [Formatters::Apple, Formatters::Android, Formatters::Gettext, Formatters::JQuery, Formatters::Flash, Formatters::Django, Formatters::Tizen]
|
13
|
+
|
14
|
+
class << self
|
15
|
+
attr_reader :formatters
|
16
|
+
|
17
|
+
###
|
18
|
+
# registers a new formatter
|
19
|
+
#
|
20
|
+
# formatter_class - the class of the formatter to register
|
21
|
+
#
|
22
|
+
# returns array of active formatters
|
23
|
+
#
|
24
|
+
def register_formatter formatter_class
|
25
|
+
raise "#{formatter_class} already registered" if @formatters.include? formatter_class
|
26
|
+
@formatters << formatter_class
|
27
|
+
end
|
28
|
+
end
|
12
29
|
end
|
13
|
-
end
|
30
|
+
end
|
@@ -66,7 +66,7 @@ module Twine
|
|
66
66
|
return str
|
67
67
|
end
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
def set_translation_for_key(key, lang, value)
|
71
71
|
if @strings.strings_map.include?(key)
|
72
72
|
@strings.strings_map[key].translations[lang] = value
|
@@ -80,6 +80,11 @@ module Twine
|
|
80
80
|
end
|
81
81
|
current_row = StringsRow.new(key)
|
82
82
|
current_section.rows << current_row
|
83
|
+
|
84
|
+
if @options[:tags] && @options[:tags].length > 0
|
85
|
+
current_row.tags = @options[:tags]
|
86
|
+
end
|
87
|
+
|
83
88
|
@strings.strings_map[key] = current_row
|
84
89
|
@strings.strings_map[key].translations[lang] = value
|
85
90
|
else
|
@@ -133,7 +138,7 @@ module Twine
|
|
133
138
|
end
|
134
139
|
end
|
135
140
|
if langs_written.empty?
|
136
|
-
raise Twine::Error.new("Failed to
|
141
|
+
raise Twine::Error.new("Failed to generate any files: No languages found at #{path}")
|
137
142
|
end
|
138
143
|
end
|
139
144
|
end
|
@@ -71,6 +71,7 @@ module Twine
|
|
71
71
|
value.gsub!('\\\'', '\'')
|
72
72
|
value.gsub!('\\"', '"')
|
73
73
|
value = iosify_substitutions(value)
|
74
|
+
value.gsub!(/(\\u0020)*|(\\u0020)*\z/) { |spaces| ' ' * (spaces.length / 6) }
|
74
75
|
else
|
75
76
|
value = ""
|
76
77
|
end
|
@@ -129,6 +130,8 @@ module Twine
|
|
129
130
|
value = CGI.escapeHTML(value)
|
130
131
|
# 3) fix substitutions (e.g. %s/%@)
|
131
132
|
value = androidify_substitutions(value)
|
133
|
+
# 4) replace beginning and end spaces with \0020. Otherwise Android strips them.
|
134
|
+
value.gsub!(/\A *| *\z/) { |spaces| '\u0020' * spaces.length }
|
132
135
|
|
133
136
|
comment = row.comment
|
134
137
|
if comment
|
@@ -35,6 +35,7 @@ module Twine
|
|
35
35
|
open(path) do |io|
|
36
36
|
json = JSON.load(io)
|
37
37
|
json.each do |key, value|
|
38
|
+
value.gsub!("\n","\\n")
|
38
39
|
set_translation_for_key(key, lang, value)
|
39
40
|
end
|
40
41
|
end
|
@@ -47,21 +48,22 @@ module Twine
|
|
47
48
|
raise Twine::Error.new "You must run 'gem install json' in order to read or write jquery-localize files."
|
48
49
|
end
|
49
50
|
|
51
|
+
printed_string = false
|
50
52
|
default_lang = @strings.language_codes[0]
|
51
53
|
encoding = @options[:output_encoding] || 'UTF-8'
|
52
54
|
File.open(path, "w:#{encoding}") do |f|
|
53
|
-
f.
|
54
|
-
f.puts "{"
|
55
|
+
f.print "{"
|
55
56
|
|
56
57
|
@strings.sections.each_with_index do |section, si|
|
57
58
|
printed_section = false
|
58
59
|
section.rows.each_with_index do |row, ri|
|
59
60
|
if row.matches_tags?(@options[:tags], @options[:untagged])
|
61
|
+
if printed_string
|
62
|
+
f.print ",\n"
|
63
|
+
end
|
64
|
+
|
60
65
|
if !printed_section
|
61
|
-
f.
|
62
|
-
if section.name && section.name.length > 0
|
63
|
-
f.puts "/* #{section.name} */"
|
64
|
-
end
|
66
|
+
f.print "\n"
|
65
67
|
printed_section = true
|
66
68
|
end
|
67
69
|
|
@@ -71,22 +73,11 @@ module Twine
|
|
71
73
|
value = row.translated_string_for_lang(lang, default_lang)
|
72
74
|
value = value.gsub('"', '\\\\"')
|
73
75
|
|
74
|
-
|
75
|
-
|
76
|
-
comment = comment.gsub('*/', '* /')
|
77
|
-
end
|
78
|
-
|
79
|
-
f.print "\"#{key}\":\"#{value}\","
|
80
|
-
|
81
|
-
if comment && comment.length > 0
|
82
|
-
f.print " /* #{comment} */\n"
|
83
|
-
else
|
84
|
-
f.print "\n"
|
85
|
-
end
|
76
|
+
f.print "\"#{key}\":\"#{value}\""
|
77
|
+
printed_string = true
|
86
78
|
end
|
87
79
|
end
|
88
80
|
end
|
89
|
-
f.seek(-2, IO::SEEK_CUR)
|
90
81
|
f.puts "\n}"
|
91
82
|
|
92
83
|
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'cgi'
|
3
|
+
require 'rexml/document'
|
4
|
+
|
5
|
+
module Twine
|
6
|
+
module Formatters
|
7
|
+
class Tizen < Abstract
|
8
|
+
FORMAT_NAME = 'tizen'
|
9
|
+
EXTENSION = '.xml'
|
10
|
+
DEFAULT_FILE_NAME = 'strings.xml'
|
11
|
+
LANG_CODES = Hash[
|
12
|
+
'eng-GB' => 'en',
|
13
|
+
'rus-RU' => 'ru',
|
14
|
+
'fra-FR' => 'fr',
|
15
|
+
'deu-DE' => 'de',
|
16
|
+
'spa-ES' => 'es',
|
17
|
+
'ita-IT' => 'it',
|
18
|
+
'ces-CZ' => 'cs',
|
19
|
+
'pol-PL' => 'pl',
|
20
|
+
'por-PT' => 'pt',
|
21
|
+
'ukr-UA' => 'uk'
|
22
|
+
]
|
23
|
+
DEFAULT_LANG_CODES = Hash[
|
24
|
+
]
|
25
|
+
|
26
|
+
def self.can_handle_directory?(path)
|
27
|
+
Dir.entries(path).any? { |item| /^values.*$/.match(item) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def default_file_name
|
31
|
+
return DEFAULT_FILE_NAME
|
32
|
+
end
|
33
|
+
|
34
|
+
def write_all_files(path)
|
35
|
+
if !File.directory?(path)
|
36
|
+
raise Twine::Error.new("Directory does not exist: #{path}")
|
37
|
+
end
|
38
|
+
|
39
|
+
langs_written = []
|
40
|
+
Dir.foreach(path) do |item|
|
41
|
+
if item == "." or item == ".."
|
42
|
+
next
|
43
|
+
end
|
44
|
+
item = File.join(path, item)
|
45
|
+
if !File.directory?(item)
|
46
|
+
lang = determine_language_given_path(item)
|
47
|
+
if lang
|
48
|
+
write_file(item, lang)
|
49
|
+
langs_written << lang
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
if langs_written.empty?
|
54
|
+
raise Twine::Error.new("Failed to genertate any files: No languages found at #{path}")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def determine_language_given_path(path)
|
59
|
+
path_arr = path.split(File::SEPARATOR)
|
60
|
+
path_arr.each do |segment|
|
61
|
+
match = /^(.*-.*)\.xml$/.match(segment)
|
62
|
+
if match
|
63
|
+
lang = match[1]
|
64
|
+
lang = LANG_CODES.fetch(lang, nil)
|
65
|
+
return lang
|
66
|
+
end
|
67
|
+
end
|
68
|
+
return
|
69
|
+
end
|
70
|
+
|
71
|
+
def read_file(path, lang)
|
72
|
+
resources_regex = /<resources(?:[^>]*)>(.*)<\/resources>/m
|
73
|
+
key_regex = /<string name="(\w+)">/
|
74
|
+
comment_regex = /<!-- (.*) -->/
|
75
|
+
value_regex = /<string name="\w+">(.*)<\/string>/
|
76
|
+
key = nil
|
77
|
+
value = nil
|
78
|
+
comment = nil
|
79
|
+
|
80
|
+
File.open(path, 'r:UTF-8') do |f|
|
81
|
+
content_match = resources_regex.match(f.read)
|
82
|
+
if content_match
|
83
|
+
for line in content_match[1].split(/\r?\n/)
|
84
|
+
key_match = key_regex.match(line)
|
85
|
+
if key_match
|
86
|
+
key = key_match[1]
|
87
|
+
value_match = value_regex.match(line)
|
88
|
+
if value_match
|
89
|
+
value = value_match[1]
|
90
|
+
value = CGI.unescapeHTML(value)
|
91
|
+
value.gsub!('\\\'', '\'')
|
92
|
+
value.gsub!('\\"', '"')
|
93
|
+
value = iosify_substitutions(value)
|
94
|
+
value.gsub!(/(\\u0020)*|(\\u0020)*\z/) { |spaces| ' ' * (spaces.length / 6) }
|
95
|
+
else
|
96
|
+
value = ""
|
97
|
+
end
|
98
|
+
set_translation_for_key(key, lang, value)
|
99
|
+
if comment and comment.length > 0 and !comment.start_with?("SECTION:")
|
100
|
+
set_comment_for_key(key, comment)
|
101
|
+
end
|
102
|
+
comment = nil
|
103
|
+
end
|
104
|
+
|
105
|
+
comment_match = comment_regex.match(line)
|
106
|
+
if comment_match
|
107
|
+
comment = comment_match[1]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def write_file(path, lang)
|
115
|
+
default_lang = nil
|
116
|
+
if DEFAULT_LANG_CODES.has_key?(lang)
|
117
|
+
default_lang = DEFAULT_LANG_CODES[lang]
|
118
|
+
end
|
119
|
+
File.open(path, 'w:UTF-8') do |f|
|
120
|
+
f.puts "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Tizen Strings File -->\n<!-- Generated by Twine #{Twine::VERSION} -->\n<!-- Language: #{lang} -->"
|
121
|
+
f.write '<string_table Bversion="2.0.0.201311071819" Dversion="20120315">'
|
122
|
+
@strings.sections.each do |section|
|
123
|
+
printed_section = false
|
124
|
+
section.rows.each do |row|
|
125
|
+
if row.matches_tags?(@options[:tags], @options[:untagged])
|
126
|
+
if !printed_section
|
127
|
+
f.puts ''
|
128
|
+
if section.name && section.name.length > 0
|
129
|
+
section_name = section.name.gsub('--', '—')
|
130
|
+
f.puts "\t<!-- SECTION: #{section_name} -->"
|
131
|
+
end
|
132
|
+
printed_section = true
|
133
|
+
end
|
134
|
+
|
135
|
+
key = row.key
|
136
|
+
|
137
|
+
value = row.translated_string_for_lang(lang, default_lang)
|
138
|
+
if !value && @options[:include_untranslated]
|
139
|
+
value = row.translated_string_for_lang(@strings.language_codes[0])
|
140
|
+
end
|
141
|
+
|
142
|
+
if value # if values is nil, there was no appropriate translation, so let Tizen handle the defaulting
|
143
|
+
value = String.new(value) # use a copy to prevent modifying the original
|
144
|
+
|
145
|
+
# Tizen enforces the following rules on the values
|
146
|
+
# 1) apostrophes and quotes must be escaped with a backslash
|
147
|
+
value.gsub!('\'', '\\\\\'')
|
148
|
+
value.gsub!('"', '\\\\"')
|
149
|
+
# 2) HTML escape the string
|
150
|
+
value = CGI.escapeHTML(value)
|
151
|
+
# 3) fix substitutions (e.g. %s/%@)
|
152
|
+
value = androidify_substitutions(value)
|
153
|
+
# 4) replace beginning and end spaces with \0020. Otherwise Tizen strips them.
|
154
|
+
value.gsub!(/\A *| *\z/) { |spaces| '\u0020' * spaces.length }
|
155
|
+
|
156
|
+
comment = row.comment
|
157
|
+
if comment
|
158
|
+
comment = comment.gsub('--', '—')
|
159
|
+
end
|
160
|
+
|
161
|
+
if comment && comment.length > 0
|
162
|
+
f.puts "\t<!-- #{comment} -->\n"
|
163
|
+
end
|
164
|
+
f.puts "\t<text id=\"IDS_#{key.upcase}\">#{value}</text>"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
f.puts '</string_table>'
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
data/lib/twine/plugin.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'safe_yaml/load'
|
2
|
+
|
3
|
+
SafeYAML::OPTIONS[:suppress_warnings] = true
|
4
|
+
|
5
|
+
module Twine
|
6
|
+
class Plugin
|
7
|
+
attr_reader :debug, :config
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@debug = false
|
11
|
+
require_gems
|
12
|
+
end
|
13
|
+
|
14
|
+
###
|
15
|
+
# require gems from the yaml config.
|
16
|
+
#
|
17
|
+
# gems: [twine-plugin1, twine-2]
|
18
|
+
#
|
19
|
+
# also works with single gem
|
20
|
+
#
|
21
|
+
# gems: twine-plugin1
|
22
|
+
#
|
23
|
+
def require_gems
|
24
|
+
# ./twine.yml # current working directory
|
25
|
+
# ~/.twine # home directory
|
26
|
+
# /etc/twine.yml # etc
|
27
|
+
cwd_config = join_path Dir.pwd, 'twine.yml'
|
28
|
+
home_config = join_path Dir.home, '.twine'
|
29
|
+
etc_config = '/etc/twine.yml'
|
30
|
+
|
31
|
+
config_order = [cwd_config, home_config, etc_config]
|
32
|
+
|
33
|
+
puts "Config order: #{config_order}" if debug
|
34
|
+
|
35
|
+
config_order.each do |config_file|
|
36
|
+
next unless valid_file config_file
|
37
|
+
puts "Loading: #{config_file}" if debug
|
38
|
+
@config = SafeYAML.load_file config_file
|
39
|
+
puts "Config yaml: #{config}" if debug
|
40
|
+
break
|
41
|
+
end
|
42
|
+
|
43
|
+
return unless config
|
44
|
+
|
45
|
+
# wrap gems in an array. if nil then array will be empty
|
46
|
+
Kernel.Array(config['gems']).each do |gem_path|
|
47
|
+
puts "Requiring: #{gem_path}" if debug
|
48
|
+
require gem_path
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def valid_file path
|
55
|
+
File.exist?(path) && File.readable?(path) && !File.directory?(path)
|
56
|
+
end
|
57
|
+
|
58
|
+
def join_path *paths
|
59
|
+
File.expand_path File.join *paths
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/twine/runner.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'tmpdir'
|
2
2
|
|
3
|
+
Twine::Plugin.new # Initialize plugins first in Runner.
|
4
|
+
|
3
5
|
module Twine
|
4
6
|
VALID_COMMANDS = ['generate-string-file', 'generate-all-string-files', 'consume-string-file', 'consume-all-string-files', 'generate-loc-drop', 'consume-loc-drop', 'generate-report']
|
5
7
|
|
@@ -269,7 +271,7 @@ module Twine
|
|
269
271
|
|
270
272
|
def determine_format_given_path(path)
|
271
273
|
ext = File.extname(path)
|
272
|
-
Formatters
|
274
|
+
Formatters.formatters.each do |formatter|
|
273
275
|
if formatter::EXTENSION == ext
|
274
276
|
return formatter::FORMAT_NAME
|
275
277
|
end
|
@@ -279,7 +281,7 @@ module Twine
|
|
279
281
|
end
|
280
282
|
|
281
283
|
def determine_format_given_directory(directory)
|
282
|
-
Formatters
|
284
|
+
Formatters.formatters.each do |formatter|
|
283
285
|
if formatter.can_handle_directory?(directory)
|
284
286
|
return formatter::FORMAT_NAME
|
285
287
|
end
|
@@ -289,7 +291,7 @@ module Twine
|
|
289
291
|
end
|
290
292
|
|
291
293
|
def formatter_for_format(format)
|
292
|
-
Formatters
|
294
|
+
Formatters.formatters.each do |formatter|
|
293
295
|
if formatter::FORMAT_NAME == format
|
294
296
|
return formatter.new(@strings, @options)
|
295
297
|
end
|
data/lib/twine/version.rb
CHANGED
data/test/fixtures/en-1.json
CHANGED
@@ -0,0 +1,8 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!-- Android Strings File -->
|
3
|
+
<!-- Generated by Twine 0.5.0 -->
|
4
|
+
<!-- Language: en -->
|
5
|
+
<resources>
|
6
|
+
<!-- SECTION: My Strings -->
|
7
|
+
<string name="string_with_spaces">\u0020string with spaces\u0020\u0020</string>
|
8
|
+
</resources>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!-- Android Strings File -->
|
3
|
+
<!-- Generated by Twine 0.5.0 -->
|
4
|
+
<!-- Language: en -->
|
5
|
+
<resources>
|
6
|
+
<!-- SECTION: My Strings -->
|
7
|
+
<!-- String ends with space -->
|
8
|
+
<string name="key with space ">string with space\u0020</string>
|
9
|
+
</resources>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!-- Tizen Strings File -->
|
3
|
+
<!-- Generated by Twine <%= Twine::VERSION %> -->
|
4
|
+
<!-- Language: fr -->
|
5
|
+
<string_table Bversion="2.0.0.201311071819" Dversion="20120315">
|
6
|
+
<!-- SECTION: My Strings -->
|
7
|
+
<!-- This is a comment -->
|
8
|
+
<text id="IDS_KEY1">key1-french</text>
|
9
|
+
<text id="IDS_KEY2">key2-french</text>
|
10
|
+
<text id="IDS_KEY3">key3-english</text>
|
11
|
+
<text id="IDS_KEY4">key4-english</text>
|
12
|
+
</string_table>
|
data/test/twine_test.rb
CHANGED
@@ -52,6 +52,22 @@ class TwineTest < Test::Unit::TestCase
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
def test_generate_string_file_7
|
56
|
+
Dir.mktmpdir do |dir|
|
57
|
+
output_path = File.join(dir, 'en.xml')
|
58
|
+
Twine::Runner.run(%W(generate-string-file test/fixtures/strings-2.txt #{output_path} -t tag1))
|
59
|
+
assert_equal(ERB.new(File.read('test/fixtures/test-output-10.txt')).result, File.read(output_path))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_generate_string_file_8
|
64
|
+
Dir.mktmpdir do |dir|
|
65
|
+
output_path = File.join(dir, 'fr.xml')
|
66
|
+
Twine::Runner.run(%W(generate-string-file --format tizen test/fixtures/strings-1.txt #{output_path} --include-untranslated))
|
67
|
+
assert_equal(ERB.new(File.read('test/fixtures/test-output-12.txt')).result, File.read(output_path))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
55
71
|
def test_consume_string_file_1
|
56
72
|
Dir.mktmpdir do |dir|
|
57
73
|
output_path = File.join(dir, 'strings.txt')
|
@@ -92,7 +108,31 @@ class TwineTest < Test::Unit::TestCase
|
|
92
108
|
end
|
93
109
|
end
|
94
110
|
|
111
|
+
def test_consume_string_file_6
|
112
|
+
Dir.mktmpdir do |dir|
|
113
|
+
output_path = File.join(dir, 'strings.txt')
|
114
|
+
Twine::Runner.run(%W(consume-string-file test/fixtures/strings-2.txt test/fixtures/en-3.xml -o #{output_path} -l en -a))
|
115
|
+
assert_equal(File.read('test/fixtures/test-output-11.txt'), File.read(output_path))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
95
119
|
def test_generate_report_1
|
96
120
|
Twine::Runner.run(%w(generate-report test/fixtures/strings-1.txt))
|
97
121
|
end
|
122
|
+
|
123
|
+
def test_json_line_breaks_consume
|
124
|
+
Dir.mktmpdir do |dir|
|
125
|
+
output_path = File.join(dir, 'strings.txt')
|
126
|
+
Twine::Runner.run(%W(consume-string-file test/fixtures/test-json-line-breaks/line-breaks.txt test/fixtures/test-json-line-breaks/line-breaks.json -l fr -o #{output_path}))
|
127
|
+
assert_equal(File.read('test/fixtures/test-json-line-breaks/consumed.txt'), File.read(output_path))
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_json_line_breaks_generate
|
132
|
+
Dir.mktmpdir do |dir|
|
133
|
+
output_path = File.join(dir, 'en.json')
|
134
|
+
Twine::Runner.run(%W(generate-string-file test/fixtures/test-json-line-breaks/line-breaks.txt #{output_path}))
|
135
|
+
assert_equal(File.read('test/fixtures/test-json-line-breaks/generated.json'), File.read(output_path))
|
136
|
+
end
|
137
|
+
end
|
98
138
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Celis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubyzip
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.9.5
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: safe_yaml
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.3
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.0.3
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rake
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,7 +74,9 @@ files:
|
|
60
74
|
- lib/twine/formatters/flash.rb
|
61
75
|
- lib/twine/formatters/gettext.rb
|
62
76
|
- lib/twine/formatters/jquery.rb
|
77
|
+
- lib/twine/formatters/tizen.rb
|
63
78
|
- lib/twine/formatters.rb
|
79
|
+
- lib/twine/plugin.rb
|
64
80
|
- lib/twine/runner.rb
|
65
81
|
- lib/twine/stringsfile.rb
|
66
82
|
- lib/twine/version.rb
|
@@ -70,11 +86,19 @@ files:
|
|
70
86
|
- test/fixtures/en-1.po
|
71
87
|
- test/fixtures/en-1.strings
|
72
88
|
- test/fixtures/en-2.po
|
89
|
+
- test/fixtures/en-3.xml
|
73
90
|
- test/fixtures/fr-1.xml
|
74
91
|
- test/fixtures/strings-1.txt
|
75
92
|
- test/fixtures/strings-2.txt
|
76
93
|
- test/fixtures/strings-3.txt
|
94
|
+
- test/fixtures/test-json-line-breaks/consumed.txt
|
95
|
+
- test/fixtures/test-json-line-breaks/generated.json
|
96
|
+
- test/fixtures/test-json-line-breaks/line-breaks.json
|
97
|
+
- test/fixtures/test-json-line-breaks/line-breaks.txt
|
77
98
|
- test/fixtures/test-output-1.txt
|
99
|
+
- test/fixtures/test-output-10.txt
|
100
|
+
- test/fixtures/test-output-11.txt
|
101
|
+
- test/fixtures/test-output-12.txt
|
78
102
|
- test/fixtures/test-output-2.txt
|
79
103
|
- test/fixtures/test-output-3.txt
|
80
104
|
- test/fixtures/test-output-4.txt
|
@@ -103,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
127
|
version: '0'
|
104
128
|
requirements: []
|
105
129
|
rubyforge_project:
|
106
|
-
rubygems_version: 2.0.
|
130
|
+
rubygems_version: 2.0.14
|
107
131
|
signing_key:
|
108
132
|
specification_version: 4
|
109
133
|
summary: Manage strings and their translations for your iOS and Android projects.
|