twine 1.0.1 → 1.0.2
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 +4 -4
- data/README.md +7 -2
- data/lib/twine/formatters/android.rb +7 -2
- data/lib/twine/placeholders.rb +8 -6
- data/lib/twine/version.rb +1 -1
- data/test/test_formatters.rb +8 -3
- data/test/test_generate_all_localization_files.rb +33 -5
- data/test/test_generate_localization_file.rb +12 -2
- metadata +21 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e7971931654800b4d398dd6c3d9e86b96e4f5ba
|
4
|
+
data.tar.gz: 64a1eccc6c604439e10c82bded869527b123f8db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 808d4045076dfef7fcba6d26797eb05d7638fd3c2adc964c24059a20f378beb8c5d978f1598d651e1117a13a1fbdbdf102d21c767aee3a68c7eb5699fae7215a
|
7
|
+
data.tar.gz: a63755c14cbadb14c0bba2960ff178a5785280bbb72e300dba5dc449ea510c823c6e248a1b848306f7c5de532c658ef8d4f034e80347f58ec2a4525673cf1ab6
|
data/README.md
CHANGED
@@ -78,7 +78,12 @@ Twine currently supports the following output formats:
|
|
78
78
|
|
79
79
|
* [iOS and OS X String Resources][applestrings] (format: apple)
|
80
80
|
* [Android String Resources][androidstrings] (format: android)
|
81
|
-
*
|
81
|
+
* HTML tags will be escaped by replacing `<` with `<`
|
82
|
+
* Tags inside `<![CDATA[` won't be escaped.
|
83
|
+
* Supports [basic styling][androidstyling] with `<b>`, `<i>`, `<u>` and `<a>` links.
|
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
|
+
* 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
|
+
* See [\#212](https://github.com/scelis/twine/issues/212) for details.
|
82
87
|
* [Gettext PO Files][gettextpo] (format: gettext)
|
83
88
|
* [jquery-localize Language Files][jquerylocalize] (format: jquery)
|
84
89
|
* [Django PO Files][djangopo] (format: django)
|
@@ -211,7 +216,7 @@ Many thanks to all of the contributors to the Twine project, including:
|
|
211
216
|
[rubyzip]: http://rubygems.org/gems/rubyzip
|
212
217
|
[git]: http://git-scm.org/
|
213
218
|
[INI]: http://en.wikipedia.org/wiki/INI_file
|
214
|
-
[applestrings]:
|
219
|
+
[applestrings]: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/LoadingResources/Strings/Strings.html
|
215
220
|
[androidstrings]: http://developer.android.com/guide/topics/resources/string-resource.html
|
216
221
|
[androidstyling]: http://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling
|
217
222
|
[gettextpo]: http://www.gnu.org/savannah-checkouts/gnu/gettext/manual/html_node/PO-Files.html
|
@@ -116,10 +116,15 @@ module Twine
|
|
116
116
|
value = gsub_unless(value, "'", "\\'") { |substring| substring =~ inside_cdata }
|
117
117
|
value = gsub_unless(value, /&/, '&') { |substring| substring =~ inside_cdata || substring =~ inside_opening_anchor_tag }
|
118
118
|
|
119
|
-
#
|
119
|
+
# if `value` contains a placeholder, escape all angle brackets
|
120
|
+
# if not, escape opening angle brackes unless it's a supported styling tag
|
120
121
|
# https://github.com/scelis/twine/issues/212
|
121
122
|
# https://stackoverflow.com/questions/3235131/#18199543
|
122
|
-
|
123
|
+
if number_of_twine_placeholders(value) > 0
|
124
|
+
angle_bracket = /<(?!(\/?(\!\[CDATA)))/ # matches all `<` but <![CDATA
|
125
|
+
else
|
126
|
+
angle_bracket = /<(?!(\/?(b|u|i|a|\!\[CDATA)))/ # matches all `<` but <b>, <u>, <i>, <a> and <![CDATA
|
127
|
+
end
|
123
128
|
value = gsub_unless(value, angle_bracket, '<') { |substring| substring =~ inside_cdata }
|
124
129
|
|
125
130
|
# escape non resource identifier @ signs (http://developer.android.com/guide/topics/resources/accessing-resources.html#ResourcesFromXml)
|
data/lib/twine/placeholders.rb
CHANGED
@@ -6,6 +6,11 @@ module Twine
|
|
6
6
|
PLACEHOLDER_FLAGS_WIDTH_PRECISION_LENGTH = '([-+0#])?(\d+|\*)?(\.(\d+|\*))?(hh?|ll?|L|z|j|t|q)?'
|
7
7
|
PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH = '(\d+\$)?' + PLACEHOLDER_FLAGS_WIDTH_PRECISION_LENGTH
|
8
8
|
PLACEHOLDER_TYPES = '[diufFeEgGxXoscpaA]'
|
9
|
+
PLACEHOLDER_REGEX = /%#{PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH}#{PLACEHOLDER_TYPES}/
|
10
|
+
|
11
|
+
def number_of_twine_placeholders(input)
|
12
|
+
input.scan(PLACEHOLDER_REGEX).size
|
13
|
+
end
|
9
14
|
|
10
15
|
def convert_twine_string_placeholder(input)
|
11
16
|
# %@ -> %s
|
@@ -19,15 +24,13 @@ module Twine
|
|
19
24
|
# %@ -> %s
|
20
25
|
value = convert_twine_string_placeholder(input)
|
21
26
|
|
22
|
-
|
23
|
-
placeholder_regex = /%#{placeholder_syntax}/
|
24
|
-
|
25
|
-
number_of_placeholders = value.scan(placeholder_regex).size
|
27
|
+
number_of_placeholders = number_of_twine_placeholders(input)
|
26
28
|
|
27
29
|
return value if number_of_placeholders == 0
|
28
30
|
|
29
31
|
# got placeholders -> need to double single percent signs
|
30
32
|
# % -> %% (but %% -> %%, %d -> %d)
|
33
|
+
placeholder_syntax = PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH + PLACEHOLDER_TYPES
|
31
34
|
single_percent_regex = /([^%])(%)(?!(%|#{placeholder_syntax}))/
|
32
35
|
value.gsub! single_percent_regex, '\1%%'
|
33
36
|
|
@@ -61,8 +64,7 @@ module Twine
|
|
61
64
|
def convert_placeholders_from_twine_to_flash(input)
|
62
65
|
value = convert_twine_string_placeholder(input)
|
63
66
|
|
64
|
-
|
65
|
-
value.gsub(placeholder_regex).each_with_index do |match, index|
|
67
|
+
value.gsub(PLACEHOLDER_REGEX).each_with_index do |match, index|
|
66
68
|
"{#{index}}"
|
67
69
|
end
|
68
70
|
end
|
data/lib/twine/version.rb
CHANGED
data/test/test_formatters.rb
CHANGED
@@ -50,6 +50,10 @@ class TestAndroidFormatter < FormatterTest
|
|
50
50
|
'<i>italic</i>' => '<i>italic</i>',
|
51
51
|
'<u>underline</u>' => '<u>underline</u>',
|
52
52
|
|
53
|
+
'<b>%@</b>' => '<b>%s</b>',
|
54
|
+
'<i>%@</i>' => '<i>%s</i>',
|
55
|
+
'<u>%@</u>' => '<u>%s</u>',
|
56
|
+
|
53
57
|
'<span>inline</span>' => '<span>inline</span>',
|
54
58
|
'<p>paragraph</p>' => '<p>paragraph</p>',
|
55
59
|
|
@@ -58,9 +62,10 @@ class TestAndroidFormatter < FormatterTest
|
|
58
62
|
'<a href="target"></a>"out"' => '<a href="target"></a>\"out\"',
|
59
63
|
'<a href="http://url.com?param=1¶m2=3¶m3=%20">link</a>' => '<a href="http://url.com?param=1¶m2=3¶m3=%20">link</a>',
|
60
64
|
|
61
|
-
'<p>escaped</p><![CDATA[]]>'
|
62
|
-
'<![CDATA[]]><p>escaped</p>'
|
63
|
-
'<![CDATA[<p>unescaped</p>]]>'
|
65
|
+
'<p>escaped</p><![CDATA[]]>' => '<p>escaped</p><![CDATA[]]>',
|
66
|
+
'<![CDATA[]]><p>escaped</p>' => '<![CDATA[]]><p>escaped</p>',
|
67
|
+
'<![CDATA[<p>unescaped</p>]]>' => '<![CDATA[<p>unescaped</p>]]>',
|
68
|
+
'<![CDATA[<p>unescaped with %@</p>]]>' => '<![CDATA[<p>unescaped with %s</p>]]>',
|
64
69
|
'<![CDATA[]]><![CDATA[<p>unescaped</p>]]>' => '<![CDATA[]]><![CDATA[<p>unescaped</p>]]>',
|
65
70
|
|
66
71
|
'<![CDATA[&]]>' => '<![CDATA[&]]>',
|
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'command_test'
|
2
2
|
|
3
3
|
class TestGenerateAllLocalizationFiles < CommandTest
|
4
|
-
def new_runner(create_folders, twine_file = nil)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
def new_runner(create_folders, twine_file = nil, options = {})
|
5
|
+
default_options = {}
|
6
|
+
default_options[:output_path] = @output_dir
|
7
|
+
default_options[:format] = 'apple'
|
8
|
+
default_options[:create_folders] = create_folders
|
9
|
+
|
10
|
+
options = default_options.merge options
|
9
11
|
|
10
12
|
unless twine_file
|
11
13
|
twine_file = build_twine_file 'en', 'es' do
|
@@ -18,6 +20,32 @@ class TestGenerateAllLocalizationFiles < CommandTest
|
|
18
20
|
Twine::Runner.new(options, twine_file)
|
19
21
|
end
|
20
22
|
|
23
|
+
class TestFormatterSelection < TestGenerateAllLocalizationFiles
|
24
|
+
def setup
|
25
|
+
super
|
26
|
+
Dir.mkdir File.join @output_dir, 'values-en'
|
27
|
+
|
28
|
+
# both Android and Tizen can handle folders containing `values-en`
|
29
|
+
android_formatter = prepare_mock_formatter(Twine::Formatters::Android)
|
30
|
+
tizen_formatter = prepare_mock_formatter(Twine::Formatters::Tizen, false)
|
31
|
+
end
|
32
|
+
|
33
|
+
def new_runner(options = {})
|
34
|
+
super(true, nil, options)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_returns_error_for_ambiguous_output_path
|
38
|
+
assert_raises Twine::Error do
|
39
|
+
new_runner(format: nil).generate_all_localization_files
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_uses_specified_formatter_to_resolve_ambiguity
|
44
|
+
# implicit assert that this call doesn't raise an exception
|
45
|
+
new_runner(format: 'android').generate_all_localization_files
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
21
49
|
class TestDoNotCreateFolders < TestGenerateAllLocalizationFiles
|
22
50
|
def new_runner(twine_file = nil)
|
23
51
|
super(false, twine_file)
|
@@ -1,8 +1,7 @@
|
|
1
1
|
require 'command_test'
|
2
2
|
|
3
3
|
class TestGenerateLocalizationFile < CommandTest
|
4
|
-
def new_runner(language, file)
|
5
|
-
options = {}
|
4
|
+
def new_runner(language, file, options = {})
|
6
5
|
options[:output_path] = File.join(@output_dir, file) if file
|
7
6
|
options[:languages] = language if language
|
8
7
|
|
@@ -59,6 +58,17 @@ class TestGenerateLocalizationFile < CommandTest
|
|
59
58
|
end
|
60
59
|
end
|
61
60
|
|
61
|
+
def test_uses_specified_formatter_to_resolve_ambiguity
|
62
|
+
# both Android and Tizen use .xml
|
63
|
+
android_formatter = prepare_mock_formatter(Twine::Formatters::Android)
|
64
|
+
android_formatter.stubs(:format_file).returns(true)
|
65
|
+
tizen_formatter = prepare_mock_formatter(Twine::Formatters::Tizen, false)
|
66
|
+
tizen_formatter.stubs(:format_file).returns(true)
|
67
|
+
|
68
|
+
# implicit assert that this call doesn't raise an exception
|
69
|
+
new_runner('fr', 'fr.xml', format: 'android').generate_localization_file
|
70
|
+
end
|
71
|
+
|
62
72
|
def test_deducts_language_from_output_path
|
63
73
|
random_language = KNOWN_LANGUAGES.sample
|
64
74
|
formatter = prepare_mock_formatter Twine::Formatters::Android
|
metadata
CHANGED
@@ -1,97 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Celis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubyzip
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: safe_yaml
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '1.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '10.4'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '10.4'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: minitest
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '5.5'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '5.5'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: minitest-ci
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - ~>
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '3.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - ~>
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '3.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: mocha
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - ~>
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '1.1'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - ~>
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '1.1'
|
97
97
|
description: |2
|
@@ -105,10 +105,13 @@ extensions: []
|
|
105
105
|
extra_rdoc_files: []
|
106
106
|
files:
|
107
107
|
- Gemfile
|
108
|
-
- README.md
|
109
108
|
- LICENSE
|
109
|
+
- README.md
|
110
|
+
- bin/twine
|
111
|
+
- lib/twine.rb
|
110
112
|
- lib/twine/cli.rb
|
111
113
|
- lib/twine/encoding.rb
|
114
|
+
- lib/twine/formatters.rb
|
112
115
|
- lib/twine/formatters/abstract.rb
|
113
116
|
- lib/twine/formatters/android.rb
|
114
117
|
- lib/twine/formatters/apple.rb
|
@@ -117,15 +120,12 @@ files:
|
|
117
120
|
- lib/twine/formatters/gettext.rb
|
118
121
|
- lib/twine/formatters/jquery.rb
|
119
122
|
- lib/twine/formatters/tizen.rb
|
120
|
-
- lib/twine/formatters.rb
|
121
123
|
- lib/twine/output_processor.rb
|
122
124
|
- lib/twine/placeholders.rb
|
123
125
|
- lib/twine/plugin.rb
|
124
126
|
- lib/twine/runner.rb
|
125
127
|
- lib/twine/twine_file.rb
|
126
128
|
- lib/twine/version.rb
|
127
|
-
- lib/twine.rb
|
128
|
-
- bin/twine
|
129
129
|
- test/command_test.rb
|
130
130
|
- test/fixtures/consume_localization_archive.zip
|
131
131
|
- test/fixtures/enc_utf16be.dummy
|
@@ -167,17 +167,17 @@ require_paths:
|
|
167
167
|
- lib
|
168
168
|
required_ruby_version: !ruby/object:Gem::Requirement
|
169
169
|
requirements:
|
170
|
-
- -
|
170
|
+
- - ">="
|
171
171
|
- !ruby/object:Gem::Version
|
172
172
|
version: '2.0'
|
173
173
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
174
|
requirements:
|
175
|
-
- -
|
175
|
+
- - ">="
|
176
176
|
- !ruby/object:Gem::Version
|
177
177
|
version: '0'
|
178
178
|
requirements: []
|
179
179
|
rubyforge_project:
|
180
|
-
rubygems_version: 2.
|
180
|
+
rubygems_version: 2.5.2
|
181
181
|
signing_key:
|
182
182
|
specification_version: 4
|
183
183
|
summary: Manage strings and their translations for your iOS, Android and other projects.
|