yury-twine 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -0
  3. data/LICENSE +30 -0
  4. data/README.md +230 -0
  5. data/bin/twine +7 -0
  6. data/lib/twine.rb +36 -0
  7. data/lib/twine/cli.rb +200 -0
  8. data/lib/twine/encoding.rb +22 -0
  9. data/lib/twine/formatters.rb +20 -0
  10. data/lib/twine/formatters/abstract.rb +187 -0
  11. data/lib/twine/formatters/android.rb +254 -0
  12. data/lib/twine/formatters/apple.rb +328 -0
  13. data/lib/twine/output_processor.rb +57 -0
  14. data/lib/twine/placeholders.rb +54 -0
  15. data/lib/twine/plugin.rb +62 -0
  16. data/lib/twine/runner.rb +332 -0
  17. data/lib/twine/twine_file.rb +266 -0
  18. data/lib/twine/version.rb +3 -0
  19. data/test/command_test.rb +14 -0
  20. data/test/fixtures/consume_loc_drop.zip +0 -0
  21. data/test/fixtures/enc_utf16be.dummy +0 -0
  22. data/test/fixtures/enc_utf16be_bom.dummy +0 -0
  23. data/test/fixtures/enc_utf16le.dummy +0 -0
  24. data/test/fixtures/enc_utf16le_bom.dummy +0 -0
  25. data/test/fixtures/enc_utf8.dummy +2 -0
  26. data/test/fixtures/formatter_android.xml +15 -0
  27. data/test/fixtures/formatter_apple.strings +20 -0
  28. data/test/fixtures/formatter_django.po +30 -0
  29. data/test/fixtures/formatter_flash.properties +15 -0
  30. data/test/fixtures/formatter_gettext.po +26 -0
  31. data/test/fixtures/formatter_jquery.json +7 -0
  32. data/test/fixtures/formatter_tizen.xml +15 -0
  33. data/test/fixtures/gettext_multiline.po +10 -0
  34. data/test/fixtures/twine_accent_values.txt +13 -0
  35. data/test/test_abstract_formatter.rb +165 -0
  36. data/test/test_cli.rb +304 -0
  37. data/test/test_consume_loc_drop.rb +27 -0
  38. data/test/test_consume_localization_file.rb +119 -0
  39. data/test/test_formatters.rb +363 -0
  40. data/test/test_generate_all_localization_files.rb +102 -0
  41. data/test/test_generate_loc_drop.rb +80 -0
  42. data/test/test_generate_localization_file.rb +91 -0
  43. data/test/test_output_processor.rb +85 -0
  44. data/test/test_placeholders.rb +84 -0
  45. data/test/test_twine_definition.rb +111 -0
  46. data/test/test_twine_file.rb +58 -0
  47. data/test/test_validate_twine_file.rb +61 -0
  48. data/test/twine_file_dsl.rb +46 -0
  49. data/test/twine_test.rb +48 -0
  50. metadata +179 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b5e4de6204261bceed91cc9d750fd293febe2922
4
+ data.tar.gz: 64334676ef727599a2e6e4dc49d9b4de10ff5f15
5
+ SHA512:
6
+ metadata.gz: 13c11084a4c44d8371dceb0667fa627f30f800fce2bfad9a342aa5f098d595a2c61343959c89a5966bbbf2a6a3a5028070baa40a972dd90bc8ef1695bd22636e
7
+ data.tar.gz: 8b85cfc24587d28cc2986d0e87cb890bb07409db391dc01823c26dccc6e5a6ccc30e5835870b621319c5db65b9b0e670d430bf1a46c90944d8c4ba5531e5845b
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,30 @@
1
+ Software License Agreement (BSD License)
2
+
3
+ Copyright (c) 2012, Mobiata, LLC
4
+ All rights reserved.
5
+
6
+ Redistribution and use of this software in source and binary forms, with or
7
+ without modification, are permitted provided that the following conditions are
8
+ met:
9
+
10
+ * Redistributions of source code must retain the above copyright notice, this
11
+ list of conditions and the following disclaimer.
12
+
13
+ * Redistributions in binary form must reproduce the above copyright notice,
14
+ this list of conditions and the following disclaimer in the documentation
15
+ and/or other materials provided with the distribution.
16
+
17
+ * Neither the name of the organization nor the names of its contributors may be
18
+ used to endorse or promote products derived from this software without
19
+ specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
25
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,230 @@
1
+ # Twine
2
+
3
+ Twine is a command line tool for managing your strings and their translations. These are all stored in a master text file and then Twine uses this file to import and export localization files in a variety of types, including iOS and Mac OS X `.strings` files, Android `.xml` files, gettext `.po` files, and [jquery-localize][jquerylocalize] `.json` files. This allows individuals and companies to easily share translations across multiple projects, as well as export localization files in any format the user wants.
4
+
5
+ ## Install
6
+
7
+ ### As a Gem
8
+
9
+ Twine is most easily installed as a Gem.
10
+
11
+ $ gem install twine
12
+
13
+ ### From Source
14
+
15
+ You can also run Twine directly from source. However, it requires [rubyzip][rubyzip] in order to create and read standard zip files.
16
+
17
+ $ gem install rubyzip
18
+ $ git clone git://github.com/mobiata/twine.git
19
+ $ cd twine
20
+ $ ./twine --help
21
+
22
+ Make sure you run the `twine` executable at the root of the project as it properly sets up your Ruby library path. The `bin/twine` executable does not.
23
+
24
+ ## Twine File Format
25
+
26
+ Twine stores everything in a single file, the Twine data file. The format of this file is a slight variant of the [Git][git] config file format, which itself is based on the old [Windows INI file][INI] format. The entire file is broken up into sections, which are created by placing the section name between two pairs of square brackets. Sections are optional, but they are the recommended way of grouping your definitions into smaller, more manageable chunks.
27
+
28
+ Each grouping section contains N definitions. These definitions start with the key placed within a single pair of square brackets. It then contains a number of key-value pairs, including a comment, a comma-separated list of tags and all of the translations.
29
+
30
+ ### Placeholders
31
+
32
+ Twine supports [`printf` style placeholders][printf] with one peculiarity: `@` is used for strings instead of `s`. This is because Twine started out as a tool for iOS and OS X projects.
33
+
34
+ ### Tags
35
+
36
+ Tags are used by Twine as a way to only work with a subset of your definitions at any given point in time. Each definition can be assigned zero or more tags which are separated by commas. Tags are optional, though highly recommended. You can get a list of all definitions currently missing tags by executing the [`validate-twine-file`](#validate-twine-file) command with the `--pedantic` option.
37
+
38
+ When generating a localization file, you can specify which definitions should be included using the `--tags` option. Provide a comma separated list of tags to match all definitions that contain any of the tags (`--tags tag1,tag2` matches all definitions tagged with `tag1` _or_ `tag2`). Provide multiple `--tags` options to match defintions containing all specified tags (`--tags tag1 --tags tag2` matches all definitions tagged with `tag1` _and_ `tag2`). You can match definitions _not_ containing a tag by prefixing the tag with a tilde (`--tags ~tag1` matches all definitions _not_ tagged with `tag1`.). All three options are combinable.
39
+
40
+ ### Whitespace
41
+
42
+ Whitepace in this file is mostly ignored. If you absolutely need to put spaces at the beginning or end of your translated string, you can wrap the entire string in a pair of `` ` `` characters. If your actual string needs to start *and* end with a grave accent, you can wrap it in another pair of `` ` `` characters. See the example, below.
43
+
44
+ ### References
45
+
46
+ If you want a definition to inherit the values of another definition, you can use a reference. Any property not specified for a definition will be taken from the reference.
47
+
48
+ ### Example
49
+
50
+ ```ini
51
+ [[General]]
52
+ [yes]
53
+ en = Yes
54
+ es = Sí
55
+ fr = Oui
56
+ ja = はい
57
+ [no]
58
+ en = No
59
+ fr = Non
60
+ ja = いいえ
61
+
62
+ [[Errors]]
63
+ [path_not_found_error]
64
+ en = The file '%@' could not be found.
65
+ tags = app1,app6
66
+ comment = An error describing when a path on the filesystem could not be found.
67
+ [network_unavailable_error]
68
+ en = The network is currently unavailable.
69
+ tags = app1
70
+ comment = An error describing when the device can not connect to the internet.
71
+ [dismiss_error]
72
+ ref = yes
73
+ en = Dismiss
74
+
75
+ [[Escaping Example]]
76
+ [list_item_separator]
77
+ en = `, `
78
+ tags = mytag
79
+ comment = A string that should be placed between multiple items in a list. For example: Red, Green, Blue
80
+ [grave_accent_quoted_string]
81
+ en = ``%@``
82
+ tags = myothertag
83
+ comment = This string will evaluate to `%@`.
84
+ ```
85
+
86
+ ## Supported Output Formats
87
+
88
+ Twine currently supports the following output formats:
89
+
90
+ * [iOS and OS X String Resources][applestrings] (format: apple)
91
+ * [Android String Resources][androidstrings] (format: android)
92
+ * [Gettext PO Files][gettextpo] (format: gettext)
93
+ * [jquery-localize Language Files][jquerylocalize] (format: jquery)
94
+ * [Django PO Files][djangopo] (format: django)
95
+ * [Tizen String Resources][tizen] (format: tizen)
96
+
97
+ If you would like to enable Twine to create localization files in another format, read the wiki page on how to create an appropriate formatter.
98
+
99
+ ## Usage
100
+
101
+ Usage: twine COMMAND TWINE_FILE [INPUT_OR_OUTPUT_PATH] [--lang LANG1,LANG2...] [--tags TAG1,TAG2,TAG3...] [--format FORMAT]
102
+
103
+ ### Commands
104
+
105
+ #### `generate-localization-file`
106
+
107
+ This command creates a localization file from the Twine data file. If the output file would not contain any translations, Twine will exit with an error.
108
+
109
+ $ twine generate-localization-file /path/to/twine.txt values-ja.xml --tags common,app1
110
+ $ twine generate-localization-file /path/to/twine.txt Localizable.strings --lang ja --tags mytag
111
+ $ twine generate-localization-file /path/to/twine.txt all-english.strings --lang en
112
+
113
+ #### `generate-all-localization-files`
114
+
115
+ This command is a convenient way to call [`generate-localization-file`](#generate-localization-file) multiple times. It uses standard conventions to figure out exactly which files to create given a parent directory. For example, if you point it to a parent directory containing `en.lproj`, `fr.lproj`, and `ja.lproj` subdirectories, Twine will create a `Localizable.strings` file of the appropriate language in each of them. However, files that would not contain any translations will not be created; instead warnings will be logged to `stderr`. This is often the command you will want to execute during the build phase of your project.
116
+
117
+ $ twine generate-all-localization-files /path/to/twine.txt /path/to/project/locales/directory --tags common,app1
118
+
119
+ #### `consume-localization-file`
120
+
121
+ This command slurps all of the translations from a localization file and incorporates the translated strings into the Twine data file. This is a simple way to incorporate any changes made to a single file by one of your translators. It will only identify definitions that already exist in the data file.
122
+
123
+ $ twine consume-localization-file /path/to/twine.txt fr.strings
124
+ $ twine consume-localization-file /path/to/twine.txt Localizable.strings --lang ja
125
+ $ twine consume-localization-file /path/to/twine.txt es.xml
126
+
127
+ #### `consume-all-localization-files`
128
+
129
+ This command reads in a folder containing many localization files. These files should be in a standard folder hierarchy so that Twine knows the language of each file. When combined with the `--developer-language`, `--consume-comments`, and `--consume-all` flags, this command is a great way to create your initial Twine data file from an existing project. Just make sure that you create a blank Twine data file first!
130
+
131
+ $ twine consume-all-localization-files twine.txt Resources/Locales --developer-language en --consume-all --consume-comments
132
+
133
+ #### `generate-loc-drop`
134
+
135
+ This command is a convenient way to generate a zip file containing files created by the [`generate-localization-file`](#generate-localization-file) command. If a file would not contain any translated strings, it is skipped and a warning is logged to `stderr`. This command can be used to create a single zip containing a large number of translations in all languages which you can then hand off to your translation team.
136
+
137
+ $ twine generate-loc-drop /path/to/twine.txt LocDrop1.zip
138
+ $ twine generate-loc-drop /path/to/twine.txt LocDrop2.zip --lang en,fr,ja,ko --tags common,app1
139
+
140
+ #### `consume-loc-drop`
141
+
142
+ This command is a convenient way of taking a zip file and executing the [`consume-localization-file`](#consume-localization-file) command on each file within the archive. It is most often used to incorporate all of the changes made by the translation team after they have completed work on a localization drop.
143
+
144
+ $ twine consume-loc-drop /path/to/twine.txt LocDrop2.zip
145
+
146
+ #### `validate-twine-file`
147
+
148
+ This command validates that the Twine data file can be parsed, contains no duplicate keys, and that no key contains invalid characters. It will exit with a non-zero status code if any of those criteria are not met.
149
+
150
+ $ twine validate-twine-file /path/to/twine.txt
151
+
152
+ ## Creating Your First Twine Data File
153
+
154
+ The easiest way to create your first Twine data file is to run the [`consume-all-localization-files`](#consume-all-localization-files) command. The one caveat is to first create a blank file to use as your starting point. Then, just point the `consume-all-localization-files` command at a directory in your project containing all of your localization files.
155
+
156
+ $ touch twine.txt
157
+ $ twine consume-all-localization-files twine.txt Resources/Locales --developer-language en --consume-all --consume-comments
158
+
159
+ ## Twine and Your Build Process
160
+
161
+ ### Xcode
162
+
163
+ It is easy to incorporate Twine right into your iOS and OS X app build processes.
164
+
165
+ 1. In your project folder, create all of the `.lproj` directories that you need. It does not really matter where they are. We tend to put them in `Resources/Locales/`.
166
+ 2. Run the [`generate-all-localization-files`](#generate-all-localization-files) command to create all of the `.strings` files you need in these directories. For example,
167
+
168
+ $ twine generate-all-localization-files twine.txt Resources/Locales/ --tags tag1,tag2
169
+
170
+ Make sure you point Twine at your data file, the directory that contains all of your `.lproj` directories, and the tags that describe the definitions you want to use for this project.
171
+ 3. Drag the `Resources/Locales/` directory to the Xcode project navigator so that Xcode knows to include all of these `.strings` files in your build.
172
+ 4. In Xcode, navigate to the "Build Phases" tab of your target.
173
+ 5. Click on the "Add Build Phase" button and select "Add Run Script".
174
+ 6. Drag the new "Run Script" build phase up so that it runs earlier in the build process. It doesn't really matter where, as long as it happens before the resources are copied to your bundle.
175
+ 7. Edit your script to run the exact same command you ran in step (2) above.
176
+
177
+ Now, whenever you build your application, Xcode will automatically invoke Twine to make sure that your `.strings` files are up-to-date.
178
+
179
+ ### Android Studio/Gradle
180
+
181
+ Add the following task at the top level in app/build.gradle:
182
+ ```
183
+ task generateLocalizations {
184
+ String script = 'if hash twine 2>/dev/null; then twine generate-localization-file twine.txt ./src/main/res/values/generated_strings.xml; fi'
185
+ exec {
186
+ executable "sh"
187
+ args '-c', script
188
+ }
189
+ }
190
+ ```
191
+
192
+ Now every time you build your app the localization files are generated from the Twine file.
193
+
194
+
195
+ ## User Interface
196
+
197
+ * [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 files. In particular, it lets you use code folding to easily collapse and expand both definitions and sections.
198
+ * [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.
199
+
200
+ ## Extending Twine
201
+
202
+ If there's a format Twine does not yet support and you're keen to change that, check out the [documentation](documentation/formatters.md).
203
+
204
+ ## Contributors
205
+
206
+ Many thanks to all of the contributors to the Twine project, including:
207
+
208
+ * [Blake Watters](https://github.com/blakewatters)
209
+ * [bootstraponline](https://github.com/bootstraponline)
210
+ * [Ishitoya Kentaro](https://github.com/kent013)
211
+ * [Joseph Earl](https://github.com/JosephEarl)
212
+ * [Kevin Everets](https://github.com/keverets)
213
+ * [Kevin Wood](https://github.com/kwood)
214
+ * [Mohammad Hejazi](https://github.com/MohammadHejazi)
215
+ * [Robert Guo](http://www.robertguo.me/)
216
+ * [Sebastian Ludwig](https://github.com/sebastianludwig)
217
+ * [Sergey Pisarchik](https://github.com/SergeyPisarchik)
218
+ * [Shai Shamir](https://github.com/pichirichi)
219
+
220
+
221
+ [rubyzip]: http://rubygems.org/gems/rubyzip
222
+ [git]: http://git-scm.org/
223
+ [INI]: http://en.wikipedia.org/wiki/INI_file
224
+ [applestrings]: http://developer.apple.com/documentation/Cocoa/Conceptual/LoadingResources/Strings/Strings.html
225
+ [androidstrings]: http://developer.android.com/guide/topics/resources/string-resource.html
226
+ [gettextpo]: http://www.gnu.org/savannah-checkouts/gnu/gettext/manual/html_node/PO-Files.html
227
+ [jquerylocalize]: https://github.com/coderifous/jquery-localize
228
+ [djangopo]: https://docs.djangoproject.com/en/dev/topics/i18n/translation/
229
+ [tizen]: https://developer.tizen.org/documentation/articles/localization
230
+ [printf]: https://en.wikipedia.org/wiki/Printf_format_string
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ require 'twine'
3
+ begin
4
+ Twine::Runner.run(ARGV)
5
+ rescue Twine::Error => e
6
+ abort e.message
7
+ end
@@ -0,0 +1,36 @@
1
+ module Twine
2
+ @@stdout = STDOUT
3
+ @@stderr = STDERR
4
+
5
+ def self.stdout
6
+ @@stdout
7
+ end
8
+
9
+ def self.stdout=(out)
10
+ @@stdout = out
11
+ end
12
+
13
+ def self.stderr
14
+ @@stderr
15
+ end
16
+
17
+ def self.stderr=(err)
18
+ @@stderr = err
19
+ end
20
+
21
+ class Error < StandardError
22
+ end
23
+
24
+ require 'twine/plugin'
25
+ require 'twine/cli'
26
+ require 'twine/twine_file'
27
+ require 'twine/encoding'
28
+ require 'twine/output_processor'
29
+ require 'twine/placeholders'
30
+ require 'twine/formatters'
31
+ require 'twine/formatters/abstract'
32
+ require 'twine/formatters/android'
33
+ require 'twine/formatters/apple'
34
+ require 'twine/runner'
35
+ require 'twine/version'
36
+ end
@@ -0,0 +1,200 @@
1
+ require 'optparse'
2
+
3
+ module Twine
4
+ module CLI
5
+ NEEDED_COMMAND_ARGUMENTS = {
6
+ 'generate-localization-file' => 3,
7
+ 'generate-all-localization-files' => 3,
8
+ 'consume-localization-file' => 3,
9
+ 'consume-all-localization-files' => 3,
10
+ 'generate-loc-drop' => 3,
11
+ 'consume-loc-drop' => 3,
12
+ 'validate-twine-file' => 2
13
+ }
14
+
15
+ def self.parse(args)
16
+ options = { include: :all }
17
+
18
+ parser = OptionParser.new do |opts|
19
+ opts.banner = 'Usage: twine COMMAND TWINE_FILE [INPUT_OR_OUTPUT_PATH] [--lang LANG1,LANG2...] [--tags TAG1,TAG2,TAG3...] [--format FORMAT]'
20
+ opts.separator ''
21
+ opts.separator 'The purpose of this script is to convert back and forth between multiple data formats, allowing us to treat our strings (and translations) as data stored in a text file. We can then use the data file to create drops for the localization team, consume similar drops returned by the localization team, and create formatted localization files to ship with your products.'
22
+ opts.separator ''
23
+ opts.separator 'Commands:'
24
+ opts.separator ''
25
+ opts.separator '- generate-localization-file'
26
+ opts.separator ' Generates a localization file in a certain LANGUAGE given a particular FORMAT. This script will attempt to guess both the language and the format given the filename and extension. For example, "ko.xml" will generate a Korean language file for Android.'
27
+ opts.separator ''
28
+ opts.separator '- generate-all-localization-files'
29
+ opts.separator ' Generates all the localization files necessary for a given project. The parent directory to all of the locale-specific directories in your project should be specified as the INPUT_OR_OUTPUT_PATH. This command will most often be executed by your build script so that each build always contains the most recent translations.'
30
+ opts.separator ''
31
+ opts.separator '- consume-localization-file'
32
+ opts.separator ' Slurps all of the translations from a localization file into the specified TWINE_FILE. If you have some files returned to you by your translators you can use this command to incorporate all of their changes. This script will attempt to guess both the language and the format given the filename and extension. For example, "ja.strings" will assume that the file is a Japanese iOS strings file.'
33
+ opts.separator ''
34
+ opts.separator '- consume-all-localization-files'
35
+ opts.separator ' Slurps all of the translations from a directory into the specified TWINE_FILE. If you have some files returned to you by your translators you can use this command to incorporate all of their changes. This script will attempt to guess both the language and the format given the filename and extension. For example, "ja.strings" will assume that the file is a Japanese iOS strings file.'
36
+ opts.separator ''
37
+ opts.separator '- generate-loc-drop'
38
+ opts.separator ' Generates a zip archive of localization files in a given format. The purpose of this command is to create a very simple archive that can be handed off to a translation team. The translation team can unzip the archive, translate all of the strings in the archived files, zip everything back up, and then hand that final archive back to be consumed by the consume-loc-drop command.'
39
+ opts.separator ''
40
+ opts.separator '- consume-loc-drop'
41
+ opts.separator ' Consumes an archive of translated files. This archive should be in the same format as the one created by the generate-loc-drop command.'
42
+ opts.separator ''
43
+ opts.separator '- validate-twine-file'
44
+ opts.separator ' Validates that the given Twine file is parseable, contains no duplicates, and that no key contains invalid characters. Exits with a non-zero exit code if those criteria are not met.'
45
+ opts.separator ''
46
+ opts.separator 'General Options:'
47
+ opts.separator ''
48
+ opts.on('-l', '--lang LANGUAGES', Array, 'The language code(s) to use for the specified action.') do |l|
49
+ options[:languages] = l
50
+ end
51
+ opts.on('-t', '--tags TAG1,TAG2,TAG3', Array, 'The tag(s) to use for the specified action. Only definitions with ANY of the specified tags will be processed.',
52
+ ' Specify this option multiple times to only include definitions with ALL of the specified tags. Prefix a tag',
53
+ ' with ~ to include definitions NOT containing that tag. Omit this option to match all definitions in the Twine',
54
+ ' data file.') do |t|
55
+ options[:tags] = (options[:tags] || []) << t
56
+ end
57
+ opts.on('-u', '--[no-]untagged', 'If you have specified tags using the --tags flag, then only those tags will be selected. If you also want to select',
58
+ ' all definitions that are untagged, then you can specify this option to do so.') do |u|
59
+ options[:untagged] = u
60
+ end
61
+ formats = Formatters.formatters.map(&:format_name).map(&:downcase)
62
+ opts.on('-f', '--format FORMAT', formats, "The file format to read or write: (#{formats.join(', ')}).",
63
+ " Additional formatters can be placed in the formats/ directory.") do |f|
64
+ options[:format] = f
65
+ end
66
+ opts.on('-a', '--[no-]consume-all', 'Normally, when consuming a localization file, Twine will ignore any translation keys that do not exist in your Twine file.') do |a|
67
+ options[:consume_all] = true
68
+ end
69
+ opts.on('-i', '--include SET', [:all, :translated, :untranslated],
70
+ "This flag will determine which definitions are included when generating localization files. It's possible values are:",
71
+ " all: All definitions both translated and untranslated for the specified language are included. This is the default value.",
72
+ " translated: Only definitions with translation for the specified language are included.",
73
+ " untranslated: Only definitions without translation for the specified language are included.") do |i|
74
+ options[:include] = i
75
+ end
76
+ opts.on('-o', '--output-file OUTPUT_FILE', 'Write a new Twine file at this location instead of replacing the original file. This flag is only useful when',
77
+ ' running the consume-localization-file or consume-loc-drop commands.') do |o|
78
+ options[:output_path] = o
79
+ end
80
+ opts.on('-n', '--file-name FILE_NAME', 'When running the generate-all-localization-files command, this flag may be used to overwrite the default file name of',
81
+ ' the format.') do |n|
82
+ options[:file_name] = n
83
+ end
84
+ opts.on('-r', '--[no-]create-folders', "When running the generate-all-localization-files command, this flag may be used to create output folders for all languages,",
85
+ " if they don't exist yet. As a result all languages will be exported, not only the ones where an output folder already",
86
+ " exists.") do |r|
87
+ options[:create_folders] = r
88
+ end
89
+ opts.on('-d', '--developer-language LANG', 'When writing the Twine data file, set the specified language as the "developer language". In practice, this just',
90
+ ' means that this language will appear first in the Twine data file. When generating files this language will be',
91
+ ' used as default language and its translations will be used if a definition is not localized for the output language.') do |d|
92
+ options[:developer_language] = d
93
+ end
94
+ opts.on('-c', '--[no-]consume-comments', 'Normally, when consuming a localization file, Twine will ignore all comments in the file. With this flag set, any comments',
95
+ ' encountered will be read and parsed into the Twine data file. This is especially useful when creating your first',
96
+ ' Twine data file from an existing project.') do |c|
97
+ options[:consume_comments] = c
98
+ end
99
+ opts.on('-e', '--encoding ENCODING', 'Twine defaults to encoding all output files in UTF-8. This flag will tell Twine to use an alternate encoding for these',
100
+ ' files. For example, you could use this to write Apple .strings files in UTF-16. When reading files, Twine does its best',
101
+ " to determine the encoding automatically. However, if the files are UTF-16 without BOM, you need to specify if it's",
102
+ ' UTF-16LE or UTF16-BE.') do |e|
103
+ options[:output_encoding] = e
104
+ end
105
+ opts.on('--[no-]validate', 'Validate the Twine file before formatting it.') do |validate|
106
+ options[:validate] = validate
107
+ end
108
+ opts.on('-p', '--[no-]pedantic', 'When validating a Twine file, perform additional checks that go beyond pure validity (like presence of tags).') do |p|
109
+ options[:pedantic] = p
110
+ end
111
+ opts.on('-h', '--help', 'Show this message.') do |h|
112
+ puts opts.help
113
+ exit
114
+ end
115
+ opts.on('--version', 'Print the version number and exit.') do
116
+ puts "Twine version #{Twine::VERSION}"
117
+ exit
118
+ end
119
+ opts.separator ''
120
+ opts.separator 'Examples:'
121
+ opts.separator ''
122
+ opts.separator '> twine generate-localization-file twine.txt ko.xml --tags FT'
123
+ opts.separator '> twine generate-all-localization-files twine.txt Resources/Locales/ --tags FT,FB'
124
+ opts.separator '> twine consume-localization-file twine.txt ja.strings'
125
+ opts.separator '> twine consume-all-localization-files twine.txt Resources/Locales/ --developer-language en --tags DefaultTag1,DefaultTag2'
126
+ opts.separator '> twine generate-loc-drop twine.txt LocDrop5.zip --tags FT,FB --format android --lang de,en,en-GB,ja,ko'
127
+ opts.separator '> twine consume-loc-drop twine.txt LocDrop5.zip'
128
+ opts.separator '> twine validate-twine-file twine.txt'
129
+ end
130
+ begin
131
+ parser.parse! args
132
+ rescue OptionParser::ParseError => e
133
+ Twine::stderr.puts e.message
134
+ exit false
135
+ end
136
+
137
+ if args.length == 0
138
+ puts parser.help
139
+ exit false
140
+ end
141
+
142
+ # TODO: Remove this mapping of deprecated commands some time in the future - added on 31.03.
143
+ deprecated_command_mappings = {
144
+ 'generate-string-file' => 'generate-localization-file',
145
+ 'generate-all-string-file' => 'generate-all-localization-files',
146
+ 'consume-string-file' => 'consume-localization-file',
147
+ 'consume-all-string-files' => 'consume-all-localization-files'
148
+ }
149
+ mapped_command = deprecated_command_mappings[args[0]]
150
+ if mapped_command
151
+ Twine::stderr.puts "WARNING: Twine commands names have changed. `#{args[0]}` is now `#{mapped_command}`. The old command is deprecated will soon stop working. For more information please check the documentation at https://github.com/mobiata/twine"
152
+ args[0] = mapped_command
153
+ end
154
+
155
+ number_of_needed_arguments = NEEDED_COMMAND_ARGUMENTS[args[0]]
156
+ unless number_of_needed_arguments
157
+ raise Twine::Error.new "Invalid command: #{args[0]}"
158
+ end
159
+ options[:command] = args[0]
160
+
161
+ if args.length < 2
162
+ raise Twine::Error.new 'You must specify your twine file.'
163
+ end
164
+ options[:twine_file] = args[1]
165
+
166
+ if args.length < number_of_needed_arguments
167
+ raise Twine::Error.new 'Not enough arguments.'
168
+ elsif args.length > number_of_needed_arguments
169
+ raise Twine::Error.new "Unknown argument: #{args[number_of_needed_arguments]}"
170
+ end
171
+
172
+ case options[:command]
173
+ when 'generate-localization-file'
174
+ options[:output_path] = args[2]
175
+ if options[:languages] and options[:languages].length > 1
176
+ raise Twine::Error.new 'Please only specify a single language for the generate-localization-file command.'
177
+ end
178
+ when 'generate-all-localization-files'
179
+ options[:output_path] = args[2]
180
+ when 'consume-localization-file'
181
+ options[:input_path] = args[2]
182
+ if options[:languages] and options[:languages].length > 1
183
+ raise Twine::Error.new 'Please only specify a single language for the consume-localization-file command.'
184
+ end
185
+ when 'consume-all-localization-files'
186
+ options[:input_path] = args[2]
187
+ when 'generate-loc-drop'
188
+ options[:output_path] = args[2]
189
+ if !options[:format]
190
+ raise Twine::Error.new 'You must specify a format.'
191
+ end
192
+ when 'consume-loc-drop'
193
+ options[:input_path] = args[2]
194
+ when 'validate-twine-file'
195
+ end
196
+
197
+ return options
198
+ end
199
+ end
200
+ end