twine 1.0.2 → 1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +45 -6
- data/lib/twine/cli.rb +24 -2
- data/lib/twine/formatters/abstract.rb +10 -3
- data/lib/twine/formatters/android.rb +21 -12
- data/lib/twine/formatters/apple.rb +1 -1
- data/lib/twine/formatters/django.rb +7 -16
- data/lib/twine/formatters/flash.rb +0 -5
- data/lib/twine/formatters/gettext.rb +4 -14
- data/lib/twine/formatters/jquery.rb +5 -10
- data/lib/twine/placeholders.rb +7 -1
- data/lib/twine/plugin.rb +2 -1
- data/lib/twine/runner.rb +33 -14
- data/lib/twine/twine_file.rb +1 -1
- data/lib/twine/version.rb +1 -1
- data/test/fixtures/consume_localization_archive.zip +0 -0
- data/test/fixtures/formatter_django.po +5 -6
- data/test/fixtures/formatter_gettext.po +2 -2
- data/test/fixtures/formatter_gettext_quotes.po +10 -0
- data/test/test_cli.rb +27 -3
- data/test/test_consume_localization_archive.rb +13 -7
- data/test/test_formatters.rb +203 -11
- data/test/test_generate_all_localization_files.rb +24 -14
- data/test/test_generate_localization_archive.rb +9 -4
- data/test/test_placeholders.rb +21 -0
- data/test/test_validate_twine_file.rb +8 -0
- data/test/twine_test.rb +2 -2
- metadata +17 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d8667f50ad7147b8b7edac0d82ce542c2ecc973604c8334e878513b6acaa9a14
|
4
|
+
data.tar.gz: 1ceb2b2b18dea8a3585bd91a1b427b30ebd9c888817dcf7140b3d211cd9e157c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a961953ec7b74510c10e17114b84c227bac43117a869ba4254d7410a16ea9413e4133a2c9f099c3d67922fd6e1632d841f366e79d28687e61f73861721dea43a
|
7
|
+
data.tar.gz: 954b69b0d6e0fadec38cf145e0e1772eb1fde0259337b45ffac172d41b6f6c031b33373c768cfbb48ad3e9cfb1565dc9e91db8e825023421fdc30098439a4d86
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Twine
|
2
2
|
|
3
|
-
[](https://circleci.com/gh/scelis/twine)
|
4
4
|
|
5
5
|
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.
|
6
6
|
|
@@ -80,7 +80,7 @@ Twine currently supports the following output formats:
|
|
80
80
|
* [Android String Resources][androidstrings] (format: android)
|
81
81
|
* HTML tags will be escaped by replacing `<` with `<`
|
82
82
|
* Tags inside `<![CDATA[` won't be escaped.
|
83
|
-
* Supports [basic styling][androidstyling]
|
83
|
+
* Supports [basic styling][androidstyling] according to [Android documentation](https://developer.android.com/guide/topics/resources/string-resource.html#StylingWithHTML). All of the documented tags are supported, in addition to `<a>` links.
|
84
84
|
* These tags will *not* be escaped if the string doesn't contain placeholders. You can reference them directly in your layouts or by using [`getText()`](https://developer.android.com/reference/android/content/res/Resources.html#getText(int)) to read them programatically.
|
85
85
|
* These tags *will* be escaped if the string contains placeholders. You can use [`getString()`](https://developer.android.com/reference/android/content/res/Resources.html#getString(int,%20java.lang.Object...)) combined with [`fromHtml`](https://developer.android.com/reference/android/text/Html.html#fromHtml(java.lang.String)) as shown in the [documentation][androidstyling] to display them.
|
86
86
|
* See [\#212](https://github.com/scelis/twine/issues/212) for details.
|
@@ -150,7 +150,7 @@ This command validates that the Twine data file can be parsed, contains no dupli
|
|
150
150
|
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.
|
151
151
|
|
152
152
|
$ touch twine.txt
|
153
|
-
$ twine consume-all-localization-files twine.txt Resources/Locales --developer-language en --consume-all --consume-comments
|
153
|
+
$ twine consume-all-localization-files twine.txt Resources/Locales --developer-language en --consume-all --consume-comments --format apple/android/gettext/jquery/django/tizen/flash
|
154
154
|
|
155
155
|
## Twine and Your Build Process
|
156
156
|
|
@@ -174,7 +174,10 @@ Now, whenever you build your application, Xcode will automatically invoke Twine
|
|
174
174
|
|
175
175
|
### Android Studio/Gradle
|
176
176
|
|
177
|
-
|
177
|
+
#### Standard
|
178
|
+
|
179
|
+
Add the following code to `app/build.gradle`:
|
180
|
+
|
178
181
|
```
|
179
182
|
task generateLocalizations {
|
180
183
|
String script = 'if hash twine 2>/dev/null; then twine generate-localization-file twine.txt ./src/main/res/values/generated_strings.xml; fi'
|
@@ -183,10 +186,46 @@ task generateLocalizations {
|
|
183
186
|
args '-c', script
|
184
187
|
}
|
185
188
|
}
|
189
|
+
|
190
|
+
preBuild {
|
191
|
+
dependsOn generateLocalizations
|
192
|
+
}
|
186
193
|
```
|
187
194
|
|
188
|
-
|
195
|
+
#### Using [jruby](http://jruby.org)
|
189
196
|
|
197
|
+
With this approach, developers do not need to manually install ruby, gem, or twine.
|
198
|
+
|
199
|
+
Add the following code to `app/build.gradle`:
|
200
|
+
|
201
|
+
```
|
202
|
+
buildscript {
|
203
|
+
repositories { jcenter() }
|
204
|
+
|
205
|
+
dependencies {
|
206
|
+
/* NOTE: Set your prefered version of jruby here. */
|
207
|
+
classpath "com.github.jruby-gradle:jruby-gradle-plugin:1.5.0"
|
208
|
+
}
|
209
|
+
}
|
210
|
+
|
211
|
+
apply plugin: 'com.github.jruby-gradle.base'
|
212
|
+
|
213
|
+
dependencies {
|
214
|
+
/* NOTE: Set your prefered version of twine here. */
|
215
|
+
jrubyExec 'rubygems:twine:1.0.3'
|
216
|
+
}
|
217
|
+
|
218
|
+
task generateLocalizations (type: JRubyExec) {
|
219
|
+
dependsOn jrubyPrepare
|
220
|
+
jrubyArgs '-S'
|
221
|
+
script "twine"
|
222
|
+
scriptArgs 'generate-localization-file', 'twine.txt', './src/main/res/values/generated_strings.xml'
|
223
|
+
}
|
224
|
+
|
225
|
+
preBuild {
|
226
|
+
dependsOn generateLocalizations
|
227
|
+
}
|
228
|
+
```
|
190
229
|
|
191
230
|
## User Interface
|
192
231
|
|
@@ -224,4 +263,4 @@ Many thanks to all of the contributors to the Twine project, including:
|
|
224
263
|
[djangopo]: https://docs.djangoproject.com/en/dev/topics/i18n/translation/
|
225
264
|
[tizen]: https://developer.tizen.org/documentation/articles/localization
|
226
265
|
[flash]: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/resources/IResourceManager.html#getString()
|
227
|
-
[printf]: https://en.wikipedia.org/wiki/Printf_format_string
|
266
|
+
[printf]: https://en.wikipedia.org/wiki/Printf_format_string
|
data/lib/twine/cli.rb
CHANGED
@@ -45,6 +45,14 @@ module Twine
|
|
45
45
|
files are UTF-16 without BOM, you need to specify if it's UTF-16LE or UTF16-BE.
|
46
46
|
DESC
|
47
47
|
},
|
48
|
+
escape_all_tags: {
|
49
|
+
switch: ['--[no-]escape-all-tags'],
|
50
|
+
description: <<-DESC,
|
51
|
+
Always escape all HTML tags. By default the Android formatter will ONLY escape styling tags, if a
|
52
|
+
string also contains placeholders. This flag enforces that styling tags are escaped regardless of
|
53
|
+
placeholders.
|
54
|
+
DESC
|
55
|
+
},
|
48
56
|
file_name: {
|
49
57
|
switch: ['-n', '--file-name FILE_NAME'],
|
50
58
|
description: 'This flag may be used to overwrite the default file name of the format.'
|
@@ -78,6 +86,10 @@ module Twine
|
|
78
86
|
switch: ['-p', '--[no-]pedantic'],
|
79
87
|
description: 'When validating a Twine file, perform additional checks that go beyond pure validity (like presence of tags).'
|
80
88
|
},
|
89
|
+
quiet: {
|
90
|
+
switch: ['-q', '--[no-]quiet'],
|
91
|
+
description: 'Suppress all console output except error messages.'
|
92
|
+
},
|
81
93
|
tags: {
|
82
94
|
switch: ['-t', '--tags TAG1,TAG2,TAG3', Array],
|
83
95
|
description: <<-DESC,
|
@@ -107,9 +119,11 @@ module Twine
|
|
107
119
|
optional_options: [
|
108
120
|
:developer_language,
|
109
121
|
:encoding,
|
122
|
+
:escape_all_tags,
|
110
123
|
:format,
|
111
124
|
:include,
|
112
125
|
:languages,
|
126
|
+
:quiet,
|
113
127
|
:tags,
|
114
128
|
:untagged,
|
115
129
|
:validate
|
@@ -128,9 +142,11 @@ module Twine
|
|
128
142
|
:create_folders,
|
129
143
|
:developer_language,
|
130
144
|
:encoding,
|
145
|
+
:escape_all_tags,
|
131
146
|
:file_name,
|
132
147
|
:format,
|
133
148
|
:include,
|
149
|
+
:quiet,
|
134
150
|
:tags,
|
135
151
|
:untagged,
|
136
152
|
:validate
|
@@ -146,7 +162,9 @@ module Twine
|
|
146
162
|
optional_options: [
|
147
163
|
:developer_language,
|
148
164
|
:encoding,
|
165
|
+
:escape_all_tags,
|
149
166
|
:include,
|
167
|
+
:quiet,
|
150
168
|
:tags,
|
151
169
|
:untagged,
|
152
170
|
:validate
|
@@ -164,6 +182,7 @@ module Twine
|
|
164
182
|
:format,
|
165
183
|
:languages,
|
166
184
|
:output_path,
|
185
|
+
:quiet,
|
167
186
|
:tags
|
168
187
|
],
|
169
188
|
option_validation: Proc.new { |options|
|
@@ -183,6 +202,7 @@ module Twine
|
|
183
202
|
:encoding,
|
184
203
|
:format,
|
185
204
|
:output_path,
|
205
|
+
:quiet,
|
186
206
|
:tags
|
187
207
|
],
|
188
208
|
example: 'twine consume-all-localization-files twine.txt Resources/Locales/ --developer-language en --tags DefaultTag1,DefaultTag2'
|
@@ -197,6 +217,7 @@ module Twine
|
|
197
217
|
:encoding,
|
198
218
|
:format,
|
199
219
|
:output_path,
|
220
|
+
:quiet,
|
200
221
|
:tags
|
201
222
|
],
|
202
223
|
example: 'twine consume-localization-archive twine.txt LocDrop5.zip'
|
@@ -206,7 +227,8 @@ module Twine
|
|
206
227
|
arguments: [:twine_file],
|
207
228
|
optional_options: [
|
208
229
|
:developer_language,
|
209
|
-
:pedantic
|
230
|
+
:pedantic,
|
231
|
+
:quiet
|
210
232
|
],
|
211
233
|
example: 'twine validate-twine-file twine.txt'
|
212
234
|
}
|
@@ -227,7 +249,7 @@ module Twine
|
|
227
249
|
|
228
250
|
mapped_command = DEPRECATED_COMMAND_MAPPINGS[command]
|
229
251
|
if mapped_command
|
230
|
-
Twine::
|
252
|
+
Twine::stdout.puts "WARNING: Twine commands names have changed. `#{command}` is now `#{mapped_command}`. The old command is deprecated and will soon stop working. For more information please check the documentation at https://github.com/mobiata/twine"
|
231
253
|
command = mapped_command
|
232
254
|
end
|
233
255
|
|
@@ -3,6 +3,8 @@ require 'fileutils'
|
|
3
3
|
module Twine
|
4
4
|
module Formatters
|
5
5
|
class Abstract
|
6
|
+
LANGUAGE_CODE_WITH_OPTIONAL_REGION_CODE = "[a-z]{2}(?:-[A-Za-z]{2})?"
|
7
|
+
|
6
8
|
attr_accessor :twine_file
|
7
9
|
attr_accessor :options
|
8
10
|
|
@@ -38,7 +40,7 @@ module Twine
|
|
38
40
|
definition.translations[lang] = value
|
39
41
|
end
|
40
42
|
elsif @options[:consume_all]
|
41
|
-
Twine::
|
43
|
+
Twine::stdout.puts "Adding new definition '#{key}' to twine file."
|
42
44
|
current_section = @twine_file.sections.find { |s| s.name == 'Uncategorized' }
|
43
45
|
unless current_section
|
44
46
|
current_section = TwineSection.new('Uncategorized')
|
@@ -54,7 +56,7 @@ module Twine
|
|
54
56
|
@twine_file.definitions_by_key[key] = current_definition
|
55
57
|
@twine_file.definitions_by_key[key].translations[lang] = value
|
56
58
|
else
|
57
|
-
Twine::
|
59
|
+
Twine::stdout.puts "WARNING: '#{key}' not found in twine file."
|
58
60
|
end
|
59
61
|
if !@twine_file.language_codes.include?(lang)
|
60
62
|
@twine_file.add_language_code(lang)
|
@@ -76,7 +78,12 @@ module Twine
|
|
76
78
|
end
|
77
79
|
|
78
80
|
def determine_language_given_path(path)
|
79
|
-
|
81
|
+
only_language_and_region = /^#{LANGUAGE_CODE_WITH_OPTIONAL_REGION_CODE}$/i
|
82
|
+
basename = File.basename(path, File.extname(path))
|
83
|
+
return basename if basename =~ only_language_and_region
|
84
|
+
return basename if @twine_file.language_codes.include? basename
|
85
|
+
|
86
|
+
path.split(File::SEPARATOR).reverse.find { |segment| segment =~ only_language_and_region }
|
80
87
|
end
|
81
88
|
|
82
89
|
def output_path_for_language(lang)
|
@@ -37,11 +37,15 @@ module Twine
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
return
|
40
|
+
return super
|
41
41
|
end
|
42
42
|
|
43
43
|
def output_path_for_language(lang)
|
44
|
-
|
44
|
+
if lang == @twine_file.language_codes[0]
|
45
|
+
"values"
|
46
|
+
else
|
47
|
+
"values-#{lang}".gsub(/-(\p{Lu})/, '-r\1')
|
48
|
+
end
|
45
49
|
end
|
46
50
|
|
47
51
|
def set_translation_for_key(key, lang, value)
|
@@ -56,7 +60,7 @@ module Twine
|
|
56
60
|
|
57
61
|
def read(io, lang)
|
58
62
|
document = REXML::Document.new io, :compress_whitespace => %w{ string }
|
59
|
-
|
63
|
+
document.context[:attribute_quote] = :quote
|
60
64
|
comment = nil
|
61
65
|
document.root.children.each do |child|
|
62
66
|
if child.is_a? REXML::Comment
|
@@ -67,7 +71,8 @@ module Twine
|
|
67
71
|
|
68
72
|
key = child.attributes['name']
|
69
73
|
|
70
|
-
|
74
|
+
content = child.children.map(&:to_s).join
|
75
|
+
set_translation_for_key(key, lang, content)
|
71
76
|
set_comment_for_key(key, comment) if comment
|
72
77
|
|
73
78
|
comment = nil
|
@@ -108,22 +113,26 @@ module Twine
|
|
108
113
|
|
109
114
|
# http://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling
|
110
115
|
def escape_value(value)
|
111
|
-
inside_cdata = /<\!\[CDATA\[((?!\]\]>).)*$/
|
112
|
-
|
116
|
+
inside_cdata = /<\!\[CDATA\[((?!\]\]>).)*$/ # opening CDATA tag ('<![CDATA[') not followed by a closing tag (']]>')
|
117
|
+
inside_opening_tag = /<(a|font|span|p)\s?((?!>).)*$/ # tag start ('<a ', '<font ', '<span ' or '<p ') not followed by a '>'
|
113
118
|
|
114
119
|
# escape double and single quotes and & signs
|
115
|
-
value = gsub_unless(value, '"', '\\"') { |substring| substring =~ inside_cdata || substring =~
|
120
|
+
value = gsub_unless(value, '"', '\\"') { |substring| substring =~ inside_cdata || substring =~ inside_opening_tag }
|
116
121
|
value = gsub_unless(value, "'", "\\'") { |substring| substring =~ inside_cdata }
|
117
|
-
value = gsub_unless(value, /&/, '&') { |substring| substring =~ inside_cdata || substring =~
|
122
|
+
value = gsub_unless(value, /&/, '&') { |substring| substring =~ inside_cdata || substring =~ inside_opening_tag }
|
118
123
|
|
119
124
|
# if `value` contains a placeholder, escape all angle brackets
|
120
125
|
# if not, escape opening angle brackes unless it's a supported styling tag
|
121
126
|
# https://github.com/scelis/twine/issues/212
|
122
127
|
# https://stackoverflow.com/questions/3235131/#18199543
|
123
|
-
if number_of_twine_placeholders(value) > 0
|
124
|
-
|
125
|
-
|
126
|
-
|
128
|
+
if number_of_twine_placeholders(value) > 0 or @options[:escape_all_tags]
|
129
|
+
# matches all `<` but <![CDATA
|
130
|
+
angle_bracket = /<(?!(\/?(\!\[CDATA)))/
|
131
|
+
else
|
132
|
+
# matches all '<' but <b>, <em>, <i>, <cite>, <dfn>, <big>, <small>, <font>, <tt>, <s>,
|
133
|
+
# <strike>, <del>, <u>, <super>, <sub>, <ul>, <li>, <br>, <div>, <span>, <p>, <a>
|
134
|
+
# and <![CDATA
|
135
|
+
angle_bracket = /<(?!(\/?(b|em|i|cite|dfn|big|small|font|tt|s|strike|del|u|super|sub|ul|li|br|div|span|p|a|\!\[CDATA)))/
|
127
136
|
end
|
128
137
|
value = gsub_unless(value, angle_bracket, '<') { |substring| substring =~ inside_cdata }
|
129
138
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module Twine
|
2
2
|
module Formatters
|
3
|
+
# For a description of the .po file format, see https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
|
3
4
|
class Django < Abstract
|
4
5
|
def format_name
|
5
6
|
'django'
|
@@ -13,22 +14,11 @@ module Twine
|
|
13
14
|
'strings.po'
|
14
15
|
end
|
15
16
|
|
16
|
-
def determine_language_given_path(path)
|
17
|
-
path_arr = path.split(File::SEPARATOR)
|
18
|
-
path_arr.each do |segment|
|
19
|
-
match = /([a-z]{2}(-[A-Za-z]{2})?)\.po$/.match(segment)
|
20
|
-
return match[1] if match
|
21
|
-
end
|
22
|
-
|
23
|
-
return
|
24
|
-
end
|
25
|
-
|
26
17
|
def read(io, lang)
|
27
|
-
comment_regex =
|
28
|
-
key_regex =
|
29
|
-
value_regex =
|
18
|
+
comment_regex = /^\s*#\. *"?(.*)"?$/
|
19
|
+
key_regex = /^msgid *"(.*)"$/
|
20
|
+
value_regex = /^msgstr *"(.*)"$/m
|
30
21
|
|
31
|
-
last_comment = nil
|
32
22
|
while line = io.gets
|
33
23
|
comment_match = comment_regex.match(line)
|
34
24
|
if comment_match
|
@@ -64,11 +54,12 @@ module Twine
|
|
64
54
|
end
|
65
55
|
|
66
56
|
def format_header(lang)
|
67
|
-
|
57
|
+
# see https://www.gnu.org/software/trans-coord/manual/gnun/html_node/PO-Header.html for details
|
58
|
+
"# Django Strings File\n# Generated by Twine #{Twine::VERSION}\n# Language: #{lang}\nmsgid \"\"\nmsgstr \"\"\n\"Content-Type: text/plain; charset=UTF-8\\n\""
|
68
59
|
end
|
69
60
|
|
70
61
|
def format_section_header(section)
|
71
|
-
"
|
62
|
+
"# --------- #{section.name} --------- #\n"
|
72
63
|
end
|
73
64
|
|
74
65
|
def format_definition(definition, lang)
|
@@ -15,11 +15,6 @@ module Twine
|
|
15
15
|
'resources.properties'
|
16
16
|
end
|
17
17
|
|
18
|
-
def determine_language_given_path(path)
|
19
|
-
# match two-letter language code, optionally followed by a two letter region code
|
20
|
-
path.split(File::SEPARATOR).reverse.find { |segment| segment =~ /^([a-z]{2}(-[a-z]{2})?)$/i }
|
21
|
-
end
|
22
|
-
|
23
18
|
def set_translation_for_key(key, lang, value)
|
24
19
|
value = convert_placeholders_from_flash_to_twine(value)
|
25
20
|
super(key, lang, value)
|
@@ -15,16 +15,6 @@ module Twine
|
|
15
15
|
'strings.po'
|
16
16
|
end
|
17
17
|
|
18
|
-
def determine_language_given_path(path)
|
19
|
-
path_arr = path.split(File::SEPARATOR)
|
20
|
-
path_arr.each do |segment|
|
21
|
-
match = /([a-z]{2}(-[A-Za-z]{2})?)\.po$/.match(segment)
|
22
|
-
return match[1] if match
|
23
|
-
end
|
24
|
-
|
25
|
-
return
|
26
|
-
end
|
27
|
-
|
28
18
|
def read(io, lang)
|
29
19
|
comment_regex = /#.? *"(.*)"$/
|
30
20
|
key_regex = /msgctxt *"(.*)"$/
|
@@ -65,7 +55,7 @@ module Twine
|
|
65
55
|
end
|
66
56
|
|
67
57
|
def format_header(lang)
|
68
|
-
"msgid \"\"\nmsgstr \"\"\n\"Language: #{lang}
|
58
|
+
"msgid \"\"\nmsgstr \"\"\n\"Language: #{lang}\"\n\"X-Generator: Twine #{Twine::VERSION}\"\n"
|
69
59
|
end
|
70
60
|
|
71
61
|
def format_section_header(section)
|
@@ -86,15 +76,15 @@ module Twine
|
|
86
76
|
end
|
87
77
|
|
88
78
|
def format_key(key)
|
89
|
-
"msgctxt \"#{key}\"\n"
|
79
|
+
"msgctxt \"#{escape_quotes(key)}\"\n"
|
90
80
|
end
|
91
81
|
|
92
82
|
def format_base_translation(definition)
|
93
|
-
"msgid \"#{definition.translations[@default_lang]}\"\n"
|
83
|
+
"msgid \"#{escape_quotes(definition.translations[@default_lang])}\"\n"
|
94
84
|
end
|
95
85
|
|
96
86
|
def format_value(value)
|
97
|
-
"msgstr \"#{value}\"\n"
|
87
|
+
"msgstr \"#{escape_quotes(value)}\"\n"
|
98
88
|
end
|
99
89
|
end
|
100
90
|
end
|
@@ -14,22 +14,17 @@ module Twine
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def determine_language_given_path(path)
|
17
|
-
|
18
|
-
|
19
|
-
match = /^((.+)-)?([^-]+)\.json$/.match(segment)
|
20
|
-
if match
|
21
|
-
return match[3]
|
22
|
-
end
|
23
|
-
end
|
17
|
+
match = /^.+-([^-]{2})\.json$/.match File.basename(path)
|
18
|
+
return match[1] if match
|
24
19
|
|
25
|
-
return
|
20
|
+
return super
|
26
21
|
end
|
27
22
|
|
28
23
|
def read(io, lang)
|
29
24
|
begin
|
30
25
|
require "json"
|
31
26
|
rescue LoadError
|
32
|
-
raise Twine::Error.new "You must run
|
27
|
+
raise Twine::Error.new "You must run `gem install json` in order to read or write jquery-localize files."
|
33
28
|
end
|
34
29
|
|
35
30
|
json = JSON.load(io)
|
@@ -46,7 +41,7 @@ module Twine
|
|
46
41
|
|
47
42
|
def format_sections(twine_file, lang)
|
48
43
|
sections = twine_file.sections.map { |section| format_section(section, lang) }
|
49
|
-
sections.delete_if
|
44
|
+
sections.delete_if(&:empty?)
|
50
45
|
sections.join(",\n\n")
|
51
46
|
end
|
52
47
|
|