twine 0.9.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +56 -69
  3. data/lib/twine.rb +11 -3
  4. data/lib/twine/cli.rb +375 -155
  5. data/lib/twine/formatters.rb +0 -5
  6. data/lib/twine/formatters/abstract.rb +43 -43
  7. data/lib/twine/formatters/android.rb +58 -59
  8. data/lib/twine/formatters/apple.rb +3 -3
  9. data/lib/twine/formatters/django.rb +15 -21
  10. data/lib/twine/formatters/flash.rb +17 -20
  11. data/lib/twine/formatters/gettext.rb +11 -15
  12. data/lib/twine/formatters/jquery.rb +8 -11
  13. data/lib/twine/formatters/tizen.rb +4 -4
  14. data/lib/twine/output_processor.rb +15 -15
  15. data/lib/twine/placeholders.rb +26 -6
  16. data/lib/twine/runner.rb +95 -95
  17. data/lib/twine/{stringsfile.rb → twine_file.rb} +53 -48
  18. data/lib/twine/version.rb +1 -1
  19. data/test/{command_test_case.rb → command_test.rb} +5 -5
  20. data/test/fixtures/{consume_loc_drop.zip → consume_localization_archive.zip} +0 -0
  21. data/test/fixtures/formatter_django.po +3 -1
  22. data/test/test_abstract_formatter.rb +40 -40
  23. data/test/test_cli.rb +313 -211
  24. data/test/test_consume_localization_archive.rb +27 -0
  25. data/test/{test_consume_string_file.rb → test_consume_localization_file.rb} +19 -19
  26. data/test/test_formatters.rb +108 -43
  27. data/test/{test_generate_all_string_files.rb → test_generate_all_localization_files.rb} +18 -18
  28. data/test/{test_generate_loc_drop.rb → test_generate_localization_archive.rb} +14 -14
  29. data/test/{test_generate_string_file.rb → test_generate_localization_file.rb} +18 -18
  30. data/test/test_output_processor.rb +26 -26
  31. data/test/test_placeholders.rb +44 -9
  32. data/test/test_twine_definition.rb +111 -0
  33. data/test/test_twine_file.rb +58 -0
  34. data/test/test_validate_twine_file.rb +61 -0
  35. data/test/twine_file_dsl.rb +12 -12
  36. data/test/{twine_test_case.rb → twine_test.rb} +1 -1
  37. metadata +23 -23
  38. data/test/test_consume_loc_drop.rb +0 -27
  39. data/test/test_strings_file.rb +0 -58
  40. data/test/test_strings_row.rb +0 -47
  41. data/test/test_validate_strings_file.rb +0 -61
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0e622767951d3e8af6ede3452a3b68bafb22637c
4
- data.tar.gz: e286fca13148bfcf733c6c023c7394e755a5653b
3
+ metadata.gz: 16380246b6372f45f09c1b9080a1401a9e422696
4
+ data.tar.gz: f756135db29d5bb33f32ca402ff267f351bd5042
5
5
  SHA512:
6
- metadata.gz: a036b7046ee8106c30bbeeed6d14d57cde28de0ec05f16c7bad4b341366add03083cdcdd802198831f3a863c7d3f473e7f1470287f7270f525ae07f614277f77
7
- data.tar.gz: bb7d85418791a6279486200eb60089867a9bb95ab2caf2acece58759afcbe62ae0ce0a858914aa3372994b496a6ae3a49eac5847fe123e83ff1311689dfea41c
6
+ metadata.gz: affb9e7964adb4c5800a7952879c4a99b7c1d2d3b1b5d2785c875d14e390b4f64c9751e056bc71d2c7ddb95d53735fb5359d9e7a16a62737fed3e64dee09e038
7
+ data.tar.gz: 818a9c8d2d6b26991d5a8360d7415c5c417d5d19b9bceffcba5f1d165781aedd0483d9a44ba6fd7bd5660f969e6a1b5c015ad76db750ba791d8576b45fbd89f3
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Twine
2
2
 
3
- Twine is a command line tool for managing your strings and their translations. These strings are all stored in a master text file and then Twine uses this file to import and export strings in a variety of file 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 strings across multiple projects, as well as export strings in any format the user wants.
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
4
 
5
5
  ## Install
6
6
 
@@ -21,19 +21,21 @@ You can also run Twine directly from source. However, it requires [rubyzip][ruby
21
21
 
22
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
23
 
24
- ## String File Format
24
+ ## Twine File Format
25
25
 
26
- Twine stores all of its strings in a single 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 a recommended way of breaking your strings into smaller, more manageable chunks.
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
27
 
28
- Each grouping section contains N string definitions. These string definitions start with the string key placed within a single pair of square brackets. This string definition then contains a number of key-value pairs, including a comment, a comma-separated list of tags (which are used by Twine to select a subset of strings), and all of the translations.
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
29
 
30
30
  ### Placeholders
31
31
 
32
- Twine supports [`printf` style placeholders](https://en.wikipedia.org/wiki/Printf_format_string) 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.
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
33
 
34
34
  ### Tags
35
35
 
36
- Tags are used by Twine as a way to only work with a subset of your strings at any given point in time. Each string 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 strings currently missing tags by executing the `validate-strings-file` command.
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.
37
39
 
38
40
  ### Whitespace
39
41
 
@@ -41,7 +43,7 @@ Whitepace in this file is mostly ignored. If you absolutely need to put spaces a
41
43
 
42
44
  ### References
43
45
 
44
- If you want a key to inherit the values of another key, you can use a reference. Any property not specified for a key will be taken from the reference.
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.
45
47
 
46
48
  ### Example
47
49
 
@@ -83,7 +85,7 @@ If you want a key to inherit the values of another key, you can use a reference.
83
85
 
84
86
  ## Supported Output Formats
85
87
 
86
- Twine currently supports the following formats for outputting strings:
88
+ Twine currently supports the following output formats:
87
89
 
88
90
  * [iOS and OS X String Resources][applestrings] (format: apple)
89
91
  * [Android String Resources][androidstrings] (format: android)
@@ -91,68 +93,69 @@ Twine currently supports the following formats for outputting strings:
91
93
  * [jquery-localize Language Files][jquerylocalize] (format: jquery)
92
94
  * [Django PO Files][djangopo] (format: django)
93
95
  * [Tizen String Resources][tizen] (format: tizen)
96
+ * [Flash/Flex Properties][flash] (format: flash)
94
97
 
95
- If you would like to enable twine to create language files in another format, create an appropriate formatter in `lib/twine/formatters`.
98
+ 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.
96
99
 
97
100
  ## Usage
98
101
 
99
- Usage: twine COMMAND STRINGS_FILE [INPUT_OR_OUTPUT_PATH] [--lang LANG1,LANG2...] [--tags TAG1,TAG2,TAG3...] [--format FORMAT]
102
+ Usage: twine COMMAND TWINE_FILE [INPUT_OR_OUTPUT_PATH] [--lang LANG1,LANG2...] [--tags TAG1,TAG2,TAG3...] [--format FORMAT]
100
103
 
101
104
  ### Commands
102
105
 
103
- #### `generate-string-file`
106
+ #### `generate-localization-file`
104
107
 
105
- This command creates an Apple or Android strings file from the master strings data file. If the output file would not contain any translations, twine will exit with an error.
108
+ 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.
106
109
 
107
- $ twine generate-string-file /path/to/strings.txt values-ja.xml --tags common,app1
108
- $ twine generate-string-file /path/to/strings.txt Localizable.strings --lang ja --tags mytag
109
- $ twine generate-string-file /path/to/strings.txt all-english.strings --lang en
110
+ $ twine generate-localization-file /path/to/twine.txt values-ja.xml --tags common,app1
111
+ $ twine generate-localization-file /path/to/twine.txt Localizable.strings --lang ja --tags mytag
112
+ $ twine generate-localization-file /path/to/twine.txt all-english.strings --lang en
110
113
 
111
- #### `generate-all-string-files`
114
+ #### `generate-all-localization-files`
112
115
 
113
- This command is a convenient way to call `generate-string-file` multiple times. It uses standard Mac OS X, iOS, and Android 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
+ 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.
114
117
 
115
- $ twine generate-all-string-files /path/to/strings.txt /path/to/project/locales/directory --tags common,app1
118
+ $ twine generate-all-localization-files /path/to/twine.txt /path/to/project/locales/directory --tags common,app1
116
119
 
117
- #### `consume-string-file`
120
+ #### `consume-localization-file`
118
121
 
119
- This command slurps all of the strings from a `.strings` or `.xml` file and incorporates the translated text into the master strings 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 strings that already exist in the master data file.
122
+ 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.
120
123
 
121
- $ twine consume-string-file /path/to/strings.txt fr.strings
122
- $ twine consume-string-file /path/to/strings.txt Localizable.strings --lang ja
123
- $ twine consume-string-file /path/to/strings.txt es.xml
124
+ $ twine consume-localization-file /path/to/twine.txt fr.strings
125
+ $ twine consume-localization-file /path/to/twine.txt Localizable.strings --lang ja
126
+ $ twine consume-localization-file /path/to/twine.txt es.xml
124
127
 
125
- #### `consume-all-string-files`
128
+ #### `consume-all-localization-files`
126
129
 
127
- This command reads in a folder containing many `.strings` or `.xml` 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 strings data file from an existing iOS or Android project. Just make sure that you create a blank strings.txt file, first!
130
+ 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!
128
131
 
129
- $ twine consume-all-string-files strings.txt Resources/Locales --developer-language en --consume-all --consume-comments
132
+ $ twine consume-all-localization-files twine.txt Resources/Locales --developer-language en --consume-all --consume-comments
130
133
 
131
- #### `generate-loc-drop`
134
+ #### `generate-localization-archive`
132
135
 
133
- This command is a convenient way to generate a zip file containing files created by the `generate-string-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 strings in all languages which you can then hand off to your translation team.
136
+ 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.
134
137
 
135
- $ twine generate-loc-drop /path/to/strings.txt LocDrop1.zip
136
- $ twine generate-loc-drop /path/to/strings.txt LocDrop2.zip --lang en,fr,ja,ko --tags common,app1
138
+ $ twine generate-localization-archive /path/to/twine.txt LocDrop1.zip
139
+ $ twine generate-localization-archive /path/to/twine.txt LocDrop2.zip --lang en,fr,ja,ko --tags common,app1
137
140
 
138
- #### `consume-loc-drop`
141
+ #### `consume-localization-archive`
139
142
 
140
- This command is a convenient way of taking a zip file and executing the `consume-string-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
+ 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 archive.
141
144
 
142
- $ twine consume-loc-drop /path/to/strings.txt LocDrop2.zip
145
+ $ twine consume-localization-archive /path/to/twine.txt LocDrop2.zip
143
146
 
144
- #### `validate-strings-file`
147
+ #### `validate-twine-file`
145
148
 
146
- This command validates that the strings file can be parsed, contains no duplicate keys, and that all strings have at least one tag. It will exit with a non-zero status code if any of those criteria are not met.
149
+ 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.
147
150
 
148
- $ twine validate-strings-file /path/to/strings.txt
151
+ $ twine validate-twine-file /path/to/twine.txt
149
152
 
150
- ## Creating Your First strings.txt File
153
+ ## Creating Your First Twine Data File
151
154
 
152
- The easiest way to create your first strings.txt file is to run the `consume-all-string-files` command. The one caveat is to first create a blank strings.txt file to use as your starting point. Then, just point the `consume-all-string-files` command at a directory in your project containing all of your iOS, OS X, or Android strings files.
155
+ 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.
153
156
 
154
- $ touch strings.txt
155
- $ twine consume-all-string-files strings.txt Resources/Locales --developer-language en --consume-all --consume-comments
157
+ $ touch twine.txt
158
+ $ twine consume-all-localization-files twine.txt Resources/Locales --developer-language en --consume-all --consume-comments
156
159
 
157
160
  ## Twine and Your Build Process
158
161
 
@@ -161,12 +164,12 @@ The easiest way to create your first strings.txt file is to run the `consume-all
161
164
  It is easy to incorporate Twine right into your iOS and OS X app build processes.
162
165
 
163
166
  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/`.
164
- 2. Run the `generate-all-string-files` command to create all of the string files you need in these directories. For example,
167
+ 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,
165
168
 
166
- $ twine generate-all-string-files strings.txt Resources/Locales/ --tags tag1,tag2
169
+ $ twine generate-all-localization-files twine.txt Resources/Locales/ --tags tag1,tag2
167
170
 
168
- Make sure you point Twine at your strings data file, the directory that contains all of your `.lproj` directories, and the tags that describe the strings you want to use for this project.
169
- 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.
171
+ 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.
172
+ 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.
170
173
  4. In Xcode, navigate to the "Build Phases" tab of your target.
171
174
  5. Click on the "Add Build Phase" button and select "Add Run Script".
172
175
  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.
@@ -178,8 +181,8 @@ Now, whenever you build your application, Xcode will automatically invoke Twine
178
181
 
179
182
  Add the following task at the top level in app/build.gradle:
180
183
  ```
181
- task generateStrings {
182
- String script = 'if hash twine 2>/dev/null; then twine generate-string-file strings.txt ./src/main/res/values/generated_strings.xml; fi'
184
+ task generateLocalizations {
185
+ String script = 'if hash twine 2>/dev/null; then twine generate-localization-file twine.txt ./src/main/res/values/generated_strings.xml; fi'
183
186
  exec {
184
187
  executable "sh"
185
188
  args '-c', script
@@ -187,35 +190,17 @@ task generateStrings {
187
190
  }
188
191
  ```
189
192
 
190
- Now every time you build your app the strings are generated from the twine file.
193
+ Now every time you build your app the localization files are generated from the Twine file.
191
194
 
192
195
 
193
196
  ## User Interface
194
197
 
195
- * [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.
198
+ * [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.
196
199
  * [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.
197
200
 
198
- ## Plugin Support
199
-
200
- 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.
201
-
202
- 0. `./twine.yml` The current working directory
203
- 0. `~/.twine` The home directory
204
- 0. `/etc/twine.yml` The etc directory
205
-
206
- Plugins are specified as values for the `gems` key. The following is an example config:
207
-
208
- ```
209
- gems: appium_twine
210
- ```
211
-
212
- Multiple gems can also be specfied in the yaml file.
213
-
214
- ```
215
- gems: [appium_twine, some_other_plugin]
216
- ```
201
+ ## Extending Twine
217
202
 
218
- [appium_twine](https://github.com/appium/appium_twine) is a sample plugin used to provide a C# formatter.
203
+ If there's a format Twine does not yet support and you're keen to change that, check out the [documentation](documentation/formatters.md).
219
204
 
220
205
  ## Contributors
221
206
 
@@ -229,7 +214,7 @@ Many thanks to all of the contributors to the Twine project, including:
229
214
  * [Kevin Wood](https://github.com/kwood)
230
215
  * [Mohammad Hejazi](https://github.com/MohammadHejazi)
231
216
  * [Robert Guo](http://www.robertguo.me/)
232
- * [sebastianludwig](https://github.com/sebastianludwig)
217
+ * [Sebastian Ludwig](https://github.com/sebastianludwig)
233
218
  * [Sergey Pisarchik](https://github.com/SergeyPisarchik)
234
219
  * [Shai Shamir](https://github.com/pichirichi)
235
220
 
@@ -243,3 +228,5 @@ Many thanks to all of the contributors to the Twine project, including:
243
228
  [jquerylocalize]: https://github.com/coderifous/jquery-localize
244
229
  [djangopo]: https://docs.djangoproject.com/en/dev/topics/i18n/translation/
245
230
  [tizen]: https://developer.tizen.org/documentation/articles/localization
231
+ [flash]: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/resources/IResourceManager.html#getString()
232
+ [printf]: https://en.wikipedia.org/wiki/Printf_format_string
@@ -21,13 +21,21 @@ module Twine
21
21
  class Error < StandardError
22
22
  end
23
23
 
24
+ require 'twine/version'
24
25
  require 'twine/plugin'
25
- require 'twine/cli'
26
- require 'twine/stringsfile'
26
+ require 'twine/twine_file'
27
27
  require 'twine/encoding'
28
28
  require 'twine/output_processor'
29
29
  require 'twine/placeholders'
30
30
  require 'twine/formatters'
31
+ require 'twine/formatters/abstract'
32
+ require 'twine/formatters/android'
33
+ require 'twine/formatters/apple'
34
+ require 'twine/formatters/django'
35
+ require 'twine/formatters/flash'
36
+ require 'twine/formatters/gettext'
37
+ require 'twine/formatters/jquery'
38
+ require 'twine/formatters/tizen'
31
39
  require 'twine/runner'
32
- require 'twine/version'
40
+ require 'twine/cli'
33
41
  end
@@ -1,184 +1,404 @@
1
1
  require 'optparse'
2
+ require 'io/console'
2
3
 
3
4
  module Twine
4
5
  module CLI
5
- NEEDED_COMMAND_ARGUMENTS = {
6
- 'generate-string-file' => 3,
7
- 'generate-all-string-files' => 3,
8
- 'consume-string-file' => 3,
9
- 'consume-all-string-files' => 3,
10
- 'generate-loc-drop' => 3,
11
- 'consume-loc-drop' => 3,
12
- 'validate-strings-file' => 2
6
+ ALL_FORMATS = Formatters.formatters.map(&:format_name).map(&:downcase)
7
+ OPTIONS = {
8
+ consume_all: {
9
+ switch: ['-a', '--[no-]consume-all'],
10
+ description: 'Normally Twine will ignore any translation keys that do not exist in your Twine file.',
11
+ boolean: true
12
+ },
13
+ consume_comments: {
14
+ switch: ['-c', '--[no-]consume-comments'],
15
+ description: <<-DESC,
16
+ Normally Twine will ignore all comments in the file. With this flag set, any
17
+ comments encountered will be read and parsed into the Twine data file. This is especially useful
18
+ when creating your first Twine data file from an existing project.
19
+ DESC
20
+ boolean: true
21
+ },
22
+ create_folders: {
23
+ switch: ['-r', '--[no-]create-folders'],
24
+ description: <<-DESC,
25
+ This flag may be used to create output folders for all languages, if they don't exist yet.
26
+ As a result all languages will be exported, not only the ones where an output folder already exists.
27
+ DESC
28
+ boolean: true
29
+ },
30
+ developer_language: {
31
+ switch: ['-d', '--developer-language LANG'],
32
+ description: <<-DESC,
33
+ When writing the Twine data file, set the specified language as the "developer language". In
34
+ practice, this just means that this language will appear first in the Twine data file. When
35
+ generating files this language will be used as default language and its translations will be
36
+ used if a definition is not localized for the output language.
37
+ DESC
38
+ },
39
+ encoding: {
40
+ switch: ['-e', '--encoding ENCODING'],
41
+ description: <<-DESC,
42
+ Twine defaults to encoding all output files in UTF-8. This flag will tell Twine to use an alternate
43
+ encoding for these files. For example, you could use this to write Apple .strings files in UTF-16.
44
+ When reading files, Twine does its best to determine the encoding automatically. However, if the
45
+ files are UTF-16 without BOM, you need to specify if it's UTF-16LE or UTF16-BE.
46
+ DESC
47
+ },
48
+ file_name: {
49
+ switch: ['-n', '--file-name FILE_NAME'],
50
+ description: 'This flag may be used to overwrite the default file name of the format.'
51
+ },
52
+ format: {
53
+ switch: ['-f', '--format FORMAT', ALL_FORMATS],
54
+ description: <<-DESC,
55
+ The file format to read or write: (#{ALL_FORMATS.join(', ')}). Additional formatters can be placed in the formats/ directory.
56
+ DESC
57
+ },
58
+ :include => {
59
+ switch: ['-i', '--include SET', [:all, :translated, :untranslated]],
60
+ description: <<-DESC,
61
+ This flag will determine which definitions are included. It's possible values are:
62
+ all: All definitions both translated and untranslated for the specified language are included.
63
+ This is the default value.
64
+ translated: Only definitions with translation for the specified language are included.
65
+ untranslated: Only definitions without translation for the specified language are included.
66
+ DESC
67
+ default: :all
68
+ },
69
+ languages: {
70
+ switch: ['-l', '--lang LANGUAGES', Array],
71
+ description: 'Comma separated list of language codes to use for the specified action.'
72
+ },
73
+ output_path: {
74
+ switch: ['-o', '--output-file OUTPUT_FILE'],
75
+ description: 'Write a new Twine file at this location instead of replacing the original file.'
76
+ },
77
+ pedantic: {
78
+ switch: ['-p', '--[no-]pedantic'],
79
+ description: 'When validating a Twine file, perform additional checks that go beyond pure validity (like presence of tags).'
80
+ },
81
+ tags: {
82
+ switch: ['-t', '--tags TAG1,TAG2,TAG3', Array],
83
+ description: <<-DESC,
84
+ Only definitions with ANY of the specified tags will be processed. Specify this option multiple
85
+ times to only include definitions with ALL of the specified tags. Prefix a tag with ~ to include
86
+ definitions NOT containing that tag. Omit this option to match all definitions in the Twine data file.
87
+ DESC
88
+ repeated: true
89
+ },
90
+ untagged: {
91
+ switch: ['-u', '--[no-]untagged'],
92
+ description: <<-DESC,
93
+ If you have specified tags using the --tags flag, then only those tags will be selected. If you also
94
+ want to select all definitions that are untagged, then you can specify this option to do so.
95
+ DESC
96
+ },
97
+ validate: {
98
+ switch: ['--[no-]validate'],
99
+ description: 'Validate the Twine file before formatting it.'
100
+ }
101
+ }
102
+
103
+ COMMANDS = {
104
+ 'generate-localization-file' => {
105
+ description: '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.',
106
+ arguments: [:twine_file, :output_path],
107
+ optional_options: [
108
+ :developer_language,
109
+ :encoding,
110
+ :format,
111
+ :include,
112
+ :languages,
113
+ :tags,
114
+ :untagged,
115
+ :validate
116
+ ],
117
+ option_validation: Proc.new { |options|
118
+ if options[:languages] and options[:languages].length > 1
119
+ raise Twine::Error.new 'specify only a single language for the `generate-localization-file` command.'
120
+ end
121
+ },
122
+ example: 'twine generate-localization-file twine.txt ko.xml --tags FT'
123
+ },
124
+ 'generate-all-localization-files' => {
125
+ description: '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.',
126
+ arguments: [:twine_file, :output_path],
127
+ optional_options: [
128
+ :create_folders,
129
+ :developer_language,
130
+ :encoding,
131
+ :file_name,
132
+ :format,
133
+ :include,
134
+ :tags,
135
+ :untagged,
136
+ :validate
137
+ ],
138
+ example: 'twine generate-all-localization-files twine.txt Resources/Locales/ --tags FT,FB'
139
+ },
140
+ 'generate-localization-archive' => {
141
+ description: '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-localization-archive command.',
142
+ arguments: [:twine_file, :output_path],
143
+ required_options: [
144
+ :format
145
+ ],
146
+ optional_options: [
147
+ :developer_language,
148
+ :encoding,
149
+ :include,
150
+ :tags,
151
+ :untagged,
152
+ :validate
153
+ ],
154
+ example: 'twine generate-localization-archive twine.txt LocDrop5.zip --tags FT,FB --format android --lang de,en,en-GB,ja,ko'
155
+ },
156
+ 'consume-localization-file' => {
157
+ description: '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.',
158
+ arguments: [:twine_file, :input_path],
159
+ optional_options: [
160
+ :consume_all,
161
+ :consume_comments,
162
+ :developer_language,
163
+ :encoding,
164
+ :format,
165
+ :languages,
166
+ :output_path,
167
+ :tags
168
+ ],
169
+ option_validation: Proc.new { |options|
170
+ if options[:languages] and options[:languages].length > 1
171
+ raise Twine::Error.new 'specify only a single language for the `consume-localization-file` command.'
172
+ end
173
+ },
174
+ example: 'twine consume-localization-file twine.txt ja.strings'
175
+ },
176
+ 'consume-all-localization-files' => {
177
+ description: '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.',
178
+ arguments: [:twine_file, :input_path],
179
+ optional_options: [
180
+ :consume_all,
181
+ :consume_comments,
182
+ :developer_language,
183
+ :encoding,
184
+ :format,
185
+ :output_path,
186
+ :tags
187
+ ],
188
+ example: 'twine consume-all-localization-files twine.txt Resources/Locales/ --developer-language en --tags DefaultTag1,DefaultTag2'
189
+ },
190
+ 'consume-localization-archive' => {
191
+ description: 'Consumes an archive of translated files. This archive should be in the same format as the one created by the generate-localization-archive command.',
192
+ arguments: [:twine_file, :input_path],
193
+ optional_options: [
194
+ :consume_all,
195
+ :consume_comments,
196
+ :developer_language,
197
+ :encoding,
198
+ :format,
199
+ :output_path,
200
+ :tags
201
+ ],
202
+ example: 'twine consume-localization-archive twine.txt LocDrop5.zip'
203
+ },
204
+ 'validate-twine-file' => {
205
+ description: '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.',
206
+ arguments: [:twine_file],
207
+ optional_options: [
208
+ :developer_language,
209
+ :pedantic
210
+ ],
211
+ example: 'twine validate-twine-file twine.txt'
212
+ }
213
+ }
214
+ DEPRECATED_COMMAND_MAPPINGS = {
215
+ 'generate-loc-drop' => 'generate-localization-archive', # added on 17.01.2017 - version 0.10
216
+ 'consume-loc-drop' => 'consume-localization-archive' # added on 17.01.2017 - version 0.10
13
217
  }
14
218
 
15
219
  def self.parse(args)
16
- options = { include: :all }
17
-
18
- parser = OptionParser.new do |opts|
19
- opts.banner = 'Usage: twine COMMAND STRINGS_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 string files to ship with your products.'
22
- opts.separator ''
23
- opts.separator 'Commands:'
24
- opts.separator ''
25
- opts.separator '- generate-string-file'
26
- opts.separator ' Generates a string 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-string-files'
29
- opts.separator ' Generates all the string 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 strings.'
30
- opts.separator ''
31
- opts.separator '- consume-string-file'
32
- opts.separator ' Slurps all of the strings from a translated strings file into the specified STRINGS_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-string-files'
35
- opts.separator ' Slurps all of the strings from a directory into the specified STRINGS_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 strings files in any 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-strings-file'
44
- opts.separator ' Validates that the given strings file is parseable, contains no duplicates, and that every string has a tag. 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 strings with that tag will be processed. Omit this option to match',
52
- ' all strings in the strings data file.') do |t|
53
- options[:tags] = t
54
- end
55
- 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',
56
- ' all strings that are untagged, then you can specify this option to do so.') do |u|
57
- options[:untagged] = u
58
- end
59
- formats = Formatters.formatters.map(&:format_name).map(&:downcase)
60
- opts.on('-f', '--format FORMAT', formats, "The file format to read or write: (#{formats.join(', ')}).",
61
- " Additional formatters can be placed in the formats/ directory.") do |f|
62
- options[:format] = f
63
- end
64
- opts.on('-a', '--[no-]consume-all', 'Normally, when consuming a string file, Twine will ignore any string keys that do not exist in your master file.') do |a|
65
- options[:consume_all] = true
66
- end
67
- opts.on('-i', '--include SET', [:all, :translated, :untranslated],
68
- "This flag will determine which strings are included when generating strings files. It's possible values:",
69
- " all: All strings both translated and untranslated for the specified language are included. This is the default value.",
70
- " translated: Only translated strings are included.",
71
- " untranslated: Only untranslated strings are included.") do |i|
72
- options[:include] = i
73
- end
74
- opts.on('-o', '--output-file OUTPUT_FILE', 'Write the new strings database to this file instead of replacing the original file. This flag is only useful when',
75
- ' running the consume-string-file or consume-loc-drop commands.') do |o|
76
- options[:output_path] = o
77
- end
78
- opts.on('-n', '--file-name FILE_NAME', 'When running the generate-all-string-files command, this flag may be used to overwrite the default file name of the format.') do |n|
79
- options[:file_name] = n
80
- end
81
- opts.on('-r', '--[no-]create-folders', "When running the generate-all-string-files command, this flag may be used to create output folders for all languages,",
82
- " if they don't exist yet. As a result all languages will be exported, not only the ones where an output folder already",
83
- " exists.") do |r|
84
- options[:create_folders] = r
85
- end
86
- opts.on('-d', '--developer-language LANG', 'When writing the strings data file, set the specified language as the "developer language". In practice, this just',
87
- ' means that this language will appear first in the strings data file. When generating files this language will be',
88
- ' used as default language and its translations will be used if a key is not localized for the output language.') do |d|
89
- options[:developer_language] = d
90
- end
91
- opts.on('-c', '--[no-]consume-comments', 'Normally, when consuming a string file, Twine will ignore all comments in the file. With this flag set, any comments',
92
- ' encountered will be read and parsed into the strings data file. This is especially useful when creating your first',
93
- ' strings data file from an existing project.') do |c|
94
- options[:consume_comments] = c
95
- end
96
- 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',
97
- ' files. For example, you could use this to write Apple .strings files in UTF-16. When reading files, Twine does its best',
98
- " to determine the encoding automatically. However, if the files are UTF-16 without BOM, you need to specify if it's",
99
- ' UTF-16LE or UTF16-BE.') do |e|
100
- options[:output_encoding] = e
101
- end
102
- opts.on('--[no-]validate', 'Validate the strings file before formatting it.') do |validate|
103
- options[:validate] = validate
220
+ command = args.select { |a| a[0] != '-' }[0]
221
+ args = args.reject { |a| a == command }
222
+
223
+ mapped_command = DEPRECATED_COMMAND_MAPPINGS[command]
224
+ if mapped_command
225
+ Twine::stderr.puts "WARNING: Twine commands names have changed. `#{command}` 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"
226
+ command = mapped_command
227
+ end
228
+
229
+ unless COMMANDS.keys.include? command
230
+ Twine::stderr.puts "Invalid command: #{command}" unless command.nil?
231
+ print_help(args)
232
+ abort
233
+ end
234
+
235
+ options = parse_command_options(command, args)
236
+
237
+ return options
238
+ end
239
+
240
+ private
241
+
242
+ def self.print_help(args)
243
+ verbose = false
244
+
245
+ help_parser = OptionParser.new
246
+ help_parser.banner = 'Usage: twine [command] [options]'
247
+
248
+ help_parser.define('-h', '--help', 'Show this message.')
249
+ help_parser.define('--verbose', 'More detailed help.') { verbose = true }
250
+
251
+ help_parser.parse!(args)
252
+
253
+ Twine::stdout.puts help_parser.help
254
+ Twine::stdout.puts ''
255
+
256
+
257
+ Twine::stdout.puts 'Commands:'
258
+
259
+ COMMANDS.each do |name, properties|
260
+ if verbose
261
+ Twine::stdout.puts ''
262
+ Twine::stdout.puts ''
263
+ Twine::stdout.puts "# #{name}"
264
+ Twine::stdout.puts ''
265
+ Twine::stdout.puts properties[:description]
266
+ else
267
+ Twine::stdout.puts "- #{name}"
104
268
  end
105
- opts.on('-p', '--[no-]pedantic', 'When validating a strings file, perform additional checks that go beyond pure validity (like presence of tags).') do |p|
106
- options[:pedantic] = p
269
+ end
270
+
271
+ Twine::stdout.puts ''
272
+ Twine::stdout.puts 'type `twine [command] --help` for further information about a command.'
273
+ end
274
+
275
+ # source: https://www.safaribooksonline.com/library/view/ruby-cookbook/0596523696/ch01s15.html
276
+ def self.word_wrap(s, width)
277
+ s.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n").rstrip
278
+ end
279
+
280
+ def self.indent(string, first_line, following_lines)
281
+ lines = string.split("\n")
282
+ indentation = ' ' * following_lines
283
+ lines.map! { |line| indentation + line }
284
+ result = lines.join("\n").strip
285
+ ' ' * first_line + result
286
+ end
287
+
288
+ # ensure the description forms a neat block on the right
289
+ def self.prepare_description!(options, summary_width)
290
+ lines = options[:description].split "\n"
291
+
292
+ # remove leadinge HEREDOC spaces
293
+ space_match = lines[0].match(/^\s+/)
294
+ if space_match
295
+ leading_spaces = space_match[0].length
296
+ lines.map! { |l| l[leading_spaces..-1] }
297
+ end
298
+
299
+ merged_lines = []
300
+ lines.each do |line|
301
+ # if the line is a continuation of the previous one
302
+ if not merged_lines.empty? and (line[0] != ' ' or line[0, 4] == ' ')
303
+ merged_lines[-1] += ' ' + line.strip
304
+ else
305
+ merged_lines << line.rstrip
107
306
  end
108
- opts.on('-h', '--help', 'Show this message.') do |h|
109
- puts opts.help
110
- exit
307
+ end
308
+
309
+ summary_width += 7 # account for description padding
310
+ max_description_width = IO.console.winsize[1] - summary_width
311
+ merged_lines.map! do |line|
312
+ if line[0] == ' '
313
+ line = word_wrap(line.strip, max_description_width - 2)
314
+ line = indent(line, 2, 4)
315
+ else
316
+ line = word_wrap(line, max_description_width)
111
317
  end
112
- opts.on('--version', 'Print the version number and exit.') do
113
- puts "Twine version #{Twine::VERSION}"
114
- exit
318
+ line
319
+ end
320
+
321
+ options[:switch] << indent(merged_lines.join("\n"), 0, summary_width)
322
+ end
323
+
324
+ def self.parse_command_options(command_name, args)
325
+ command = COMMANDS[command_name]
326
+
327
+ result = {
328
+ command: command_name
329
+ }
330
+
331
+ parser = OptionParser.new
332
+ parser.banner = "Usage: twine #{command_name} #{command[:arguments].map { |c| "[#{c}]" }.join(' ')} [options]"
333
+
334
+ [:required_options, :optional_options].each do |option_type|
335
+ options = command[option_type]
336
+ if options and options.size > 0
337
+ parser.separator ''
338
+ parser.separator option_type.to_s.gsub('_', ' ').capitalize + ":"
339
+
340
+ options.each do |option_name|
341
+ option = OPTIONS[option_name]
342
+
343
+ result[option_name] = option[:default] if option[:default]
344
+
345
+ prepare_description!(option, parser.summary_width)
346
+
347
+ parser.define(*option[:switch]) do |value|
348
+ if option[:repeated]
349
+ result[option_name] = (result[option_name] || []) << value
350
+ elsif option[:boolean]
351
+ result[option_name] = true
352
+ else
353
+ result[option_name] = value
354
+ end
355
+ end
356
+ end
115
357
  end
116
- opts.separator ''
117
- opts.separator 'Examples:'
118
- opts.separator ''
119
- opts.separator '> twine generate-string-file strings.txt ko.xml --tags FT'
120
- opts.separator '> twine generate-all-string-files strings.txt Resources/Locales/ --tags FT,FB'
121
- opts.separator '> twine consume-string-file strings.txt ja.strings'
122
- opts.separator '> twine consume-all-string-files strings.txt Resources/Locales/ --developer-language en --tags DefaultTag1,DefaultTag2'
123
- opts.separator '> twine generate-loc-drop strings.txt LocDrop5.zip --tags FT,FB --format android --lang de,en,en-GB,ja,ko'
124
- opts.separator '> twine consume-loc-drop strings.txt LocDrop5.zip'
125
- opts.separator '> twine validate-strings-file strings.txt'
126
358
  end
359
+
360
+ parser.define('-h', '--help', 'Show this message.') do
361
+ puts parser.help
362
+ exit
363
+ end
364
+
365
+ parser.separator ''
366
+ parser.separator 'Examples:'
367
+ parser.separator ''
368
+ parser.separator "> #{command[:example]}"
369
+
127
370
  begin
128
371
  parser.parse! args
129
372
  rescue OptionParser::ParseError => e
130
- Twine::stderr.puts e.message
131
- exit false
373
+ raise Twine::Error.new e.message
132
374
  end
133
375
 
134
- if args.length == 0
135
- puts parser.help
136
- exit false
376
+ arguments = args.reject { |a| a[0] == '-' }
377
+ number_of_missing_arguments = command[:arguments].size - arguments.size
378
+ if number_of_missing_arguments > 0
379
+ missing_arguments = command[:arguments][-number_of_missing_arguments, number_of_missing_arguments]
380
+ raise Twine::Error.new "#{number_of_missing_arguments} missing argument#{number_of_missing_arguments > 1 ? "s" : ""}: #{missing_arguments.join(', ')}. Check `twine #{command_name} -h`"
137
381
  end
138
382
 
139
- number_of_needed_arguments = NEEDED_COMMAND_ARGUMENTS[args[0]]
140
- unless number_of_needed_arguments
141
- raise Twine::Error.new "Invalid command: #{args[0]}"
383
+ if args.length > command[:arguments].size
384
+ raise Twine::Error.new "Unknown argument: #{args[command[:arguments].size]}"
142
385
  end
143
- options[:command] = args[0]
144
386
 
145
- if args.length < 2
146
- raise Twine::Error.new 'You must specify your strings file.'
387
+ if command[:required_options]
388
+ command[:required_options].each do |option_name|
389
+ if result[option_name] == nil
390
+ raise Twine::Error.new "missing option: #{OPTIONS[option_name][:switch][0]}"
391
+ end
392
+ end
147
393
  end
148
- options[:strings_file] = args[1]
149
394
 
150
- if args.length < number_of_needed_arguments
151
- raise Twine::Error.new 'Not enough arguments.'
152
- elsif args.length > number_of_needed_arguments
153
- raise Twine::Error.new "Unknown argument: #{args[number_of_needed_arguments]}"
154
- end
395
+ command[:option_validation].call(result) if command[:option_validation]
155
396
 
156
- case options[:command]
157
- when 'generate-string-file'
158
- options[:output_path] = args[2]
159
- if options[:languages] and options[:languages].length > 1
160
- raise Twine::Error.new 'Please only specify a single language for the generate-string-file command.'
161
- end
162
- when 'generate-all-string-files'
163
- options[:output_path] = args[2]
164
- when 'consume-string-file'
165
- options[:input_path] = args[2]
166
- if options[:languages] and options[:languages].length > 1
167
- raise Twine::Error.new 'Please only specify a single language for the consume-string-file command.'
168
- end
169
- when 'consume-all-string-files'
170
- options[:input_path] = args[2]
171
- when 'generate-loc-drop'
172
- options[:output_path] = args[2]
173
- if !options[:format]
174
- raise Twine::Error.new 'You must specify a format.'
175
- end
176
- when 'consume-loc-drop'
177
- options[:input_path] = args[2]
178
- when 'validate-strings-file'
397
+ command[:arguments].each do |argument_name|
398
+ result[argument_name] = args.shift
179
399
  end
180
400
 
181
- return options
401
+ result
182
402
  end
183
403
  end
184
404
  end