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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 303ce6c7d8bab093ca71941fe800a657fb809ef3
4
- data.tar.gz: 429d906f86a7f7bd566ffc4eb8590f8157a000e0
3
+ metadata.gz: 0e7971931654800b4d398dd6c3d9e86b96e4f5ba
4
+ data.tar.gz: 64a1eccc6c604439e10c82bded869527b123f8db
5
5
  SHA512:
6
- metadata.gz: 5998ed4a6f39b0d09bcfd33d404239ccf2b7f6523aeae9fd36cd3af3b0c897ab589575ae91f365e77629718eba457ffaf6915d0965b12f40a097fb06cc054472
7
- data.tar.gz: 0659ce0901ebef294dd81b59a08a1467d1f7399e04d84b4e303900a10ffbbf9252234d059fa1ec143fcacbf93b3ef857708c3e00b7fe55166be83464ffafa0e5
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
- * Supports [basic styling][androidstyling] with \<b\>, \<i\>, \<u\> and \<a\> links. These tags will *not* be escaped. Use [`getText()`](https://developer.android.com/reference/android/content/res/Resources.html#getText(int)) to read these strings. Also tags inside `<![CDATA[` won't be escaped. See [\#212](https://github.com/scelis/twine/issues/212) for details.
81
+ * HTML tags will be escaped by replacing `<` with `&lt`
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]: http://developer.apple.com/documentation/Cocoa/Conceptual/LoadingResources/Strings/Strings.html
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, /&/, '&amp;') { |substring| substring =~ inside_cdata || substring =~ inside_opening_anchor_tag }
118
118
 
119
- # escape opening angle brackes unless it's a supported styling tag
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
- angle_bracket = /<(?!(\/?(b|u|i|a|\!\[CDATA)))/ # matches all `<` but <b>, <u>, <i>, <a> and <![CDATA
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, '&lt;') { |substring| substring =~ inside_cdata }
124
129
 
125
130
  # escape non resource identifier @ signs (http://developer.android.com/guide/topics/resources/accessing-resources.html#ResourcesFromXml)
@@ -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
- placeholder_syntax = PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH + PLACEHOLDER_TYPES
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
- placeholder_regex = /%#{PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH}#{PLACEHOLDER_TYPES}/
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
@@ -1,3 +1,3 @@
1
1
  module Twine
2
- VERSION = '1.0.1'
2
+ VERSION = '1.0.2'
3
3
  end
@@ -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>' => '&lt;b>%s&lt;/b>',
54
+ '<i>%@</i>' => '&lt;i>%s&lt;/i>',
55
+ '<u>%@</u>' => '&lt;u>%s&lt;/u>',
56
+
53
57
  '<span>inline</span>' => '&lt;span>inline&lt;/span>',
54
58
  '<p>paragraph</p>' => '&lt;p>paragraph&lt;/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&param2=3&param3=%20">link</a>' => '<a href="http://url.com?param=1&param2=3&param3=%20">link</a>',
60
64
 
61
- '<p>escaped</p><![CDATA[]]>' => '&lt;p>escaped&lt;/p><![CDATA[]]>',
62
- '<![CDATA[]]><p>escaped</p>' => '<![CDATA[]]>&lt;p>escaped&lt;/p>',
63
- '<![CDATA[<p>unescaped</p>]]>' => '<![CDATA[<p>unescaped</p>]]>',
65
+ '<p>escaped</p><![CDATA[]]>' => '&lt;p>escaped&lt;/p><![CDATA[]]>',
66
+ '<![CDATA[]]><p>escaped</p>' => '<![CDATA[]]>&lt;p>escaped&lt;/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
- options = {}
6
- options[:output_path] = @output_dir
7
- options[:format] = 'apple'
8
- options[:create_folders] = create_folders
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.1
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: 2017-10-18 00:00:00.000000000 Z
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.0.14.1
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.