diff options
author | Sebastian Ludwig <sebastian@lurado.de> | 2017-12-12 17:26:38 +0300 |
---|---|---|
committer | Sebastian Ludwig <sebastian@lurado.de> | 2017-12-12 17:26:38 +0300 |
commit | b5cd295e3a82ddcb5fb4e6540805815d5ac2e686 (patch) | |
tree | f0b307e8990130d95993756f8b29704e9d18e6de | |
parent | 0688167c59c9094d9767fec91272543baadebf42 (diff) |
Escape angle brackets in Android formatter, if the string contains a placeholder to enable users to use the official way to retrieve these strings. Improves #212.
-rw-r--r-- | CHANGELOG.md | 4 | ||||
-rw-r--r-- | README.md | 7 | ||||
-rw-r--r-- | lib/twine/formatters/android.rb | 9 | ||||
-rw-r--r-- | lib/twine/placeholders.rb | 14 | ||||
-rw-r--r-- | test/test_formatters.rb | 11 |
5 files changed, 33 insertions, 12 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index f5b445b..a29a8bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# next version + +- Improvement: Better support for placeholders in HTML styled Android strings (#212) + # 1.0.1 (2017-10-17) - Bugfix: Always prefer the passed-in formatter (#221) @@ -78,7 +78,12 @@ Twine currently supports the following output formats: * [iOS and OS X String Resources][applestrings] (format: apple) * [Android String Resources][androidstrings] (format: android) - * 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. + * HTML tags will be escaped by replacing `<` with `<` + * Tags inside `<![CDATA[` won't be escaped. + * Supports [basic styling][androidstyling] with `<b>`, `<i>`, `<u>` and `<a>` links. + * These tags will *not* be escaped, if the string doesn't contain placeholders so you can reference them directly in your layouts or use [`getText()`](https://developer.android.com/reference/android/content/res/Resources.html#getText(int)) to read them programatically. + * 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. + * See [\#212](https://github.com/scelis/twine/issues/212) for details. * [Gettext PO Files][gettextpo] (format: gettext) * [jquery-localize Language Files][jquerylocalize] (format: jquery) * [Django PO Files][djangopo] (format: django) diff --git a/lib/twine/formatters/android.rb b/lib/twine/formatters/android.rb index ced90b7..55c735c 100644 --- a/lib/twine/formatters/android.rb +++ b/lib/twine/formatters/android.rb @@ -116,10 +116,15 @@ module Twine value = gsub_unless(value, "'", "\\'") { |substring| substring =~ inside_cdata } value = gsub_unless(value, /&/, '&') { |substring| substring =~ inside_cdata || substring =~ inside_opening_anchor_tag } - # escape opening angle brackes unless it's a supported styling tag + # if `value` contains a placeholder, escape all angle brackets + # if not, escape opening angle brackes unless it's a supported styling tag # https://github.com/scelis/twine/issues/212 # https://stackoverflow.com/questions/3235131/#18199543 - angle_bracket = /<(?!(\/?(b|u|i|a|\!\[CDATA)))/ # matches all `<` but <b>, <u>, <i>, <a> and <![CDATA + if number_of_twine_placeholders(value) > 0 + angle_bracket = /<(?!(\/?(\!\[CDATA)))/ # matches all `<` but <![CDATA + else + angle_bracket = /<(?!(\/?(b|u|i|a|\!\[CDATA)))/ # matches all `<` but <b>, <u>, <i>, <a> and <![CDATA + end value = gsub_unless(value, angle_bracket, '<') { |substring| substring =~ inside_cdata } # escape non resource identifier @ signs (http://developer.android.com/guide/topics/resources/accessing-resources.html#ResourcesFromXml) diff --git a/lib/twine/placeholders.rb b/lib/twine/placeholders.rb index 1c7b200..bc44d05 100644 --- a/lib/twine/placeholders.rb +++ b/lib/twine/placeholders.rb @@ -6,6 +6,11 @@ module Twine PLACEHOLDER_FLAGS_WIDTH_PRECISION_LENGTH = '([-+0#])?(\d+|\*)?(\.(\d+|\*))?(hh?|ll?|L|z|j|t|q)?' PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH = '(\d+\$)?' + PLACEHOLDER_FLAGS_WIDTH_PRECISION_LENGTH PLACEHOLDER_TYPES = '[diufFeEgGxXoscpaA]' + PLACEHOLDER_REGEX = /%#{PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH}#{PLACEHOLDER_TYPES}/ + + def number_of_twine_placeholders(input) + input.scan(PLACEHOLDER_REGEX).size + end def convert_twine_string_placeholder(input) # %@ -> %s @@ -19,15 +24,13 @@ module Twine # %@ -> %s value = convert_twine_string_placeholder(input) - placeholder_syntax = PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH + PLACEHOLDER_TYPES - placeholder_regex = /%#{placeholder_syntax}/ - - number_of_placeholders = value.scan(placeholder_regex).size + number_of_placeholders = number_of_twine_placeholders(input) return value if number_of_placeholders == 0 # got placeholders -> need to double single percent signs # % -> %% (but %% -> %%, %d -> %d) + placeholder_syntax = PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH + PLACEHOLDER_TYPES single_percent_regex = /([^%])(%)(?!(%|#{placeholder_syntax}))/ value.gsub! single_percent_regex, '\1%%' @@ -61,8 +64,7 @@ module Twine def convert_placeholders_from_twine_to_flash(input) value = convert_twine_string_placeholder(input) - placeholder_regex = /%#{PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH}#{PLACEHOLDER_TYPES}/ - value.gsub(placeholder_regex).each_with_index do |match, index| + value.gsub(PLACEHOLDER_REGEX).each_with_index do |match, index| "{#{index}}" end end diff --git a/test/test_formatters.rb b/test/test_formatters.rb index 87658b7..51d3c51 100644 --- a/test/test_formatters.rb +++ b/test/test_formatters.rb @@ -50,6 +50,10 @@ class TestAndroidFormatter < FormatterTest '<i>italic</i>' => '<i>italic</i>', '<u>underline</u>' => '<u>underline</u>', + '<b>%@</b>' => '<b>%s</b>', + '<i>%@</i>' => '<i>%s</i>', + '<u>%@</u>' => '<u>%s</u>', + '<span>inline</span>' => '<span>inline</span>', '<p>paragraph</p>' => '<p>paragraph</p>', @@ -58,9 +62,10 @@ class TestAndroidFormatter < FormatterTest '<a href="target"></a>"out"' => '<a href="target"></a>\"out\"', '<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>', - '<p>escaped</p><![CDATA[]]>' => '<p>escaped</p><![CDATA[]]>', - '<![CDATA[]]><p>escaped</p>' => '<![CDATA[]]><p>escaped</p>', - '<![CDATA[<p>unescaped</p>]]>' => '<![CDATA[<p>unescaped</p>]]>', + '<p>escaped</p><![CDATA[]]>' => '<p>escaped</p><![CDATA[]]>', + '<![CDATA[]]><p>escaped</p>' => '<![CDATA[]]><p>escaped</p>', + '<![CDATA[<p>unescaped</p>]]>' => '<![CDATA[<p>unescaped</p>]]>', + '<![CDATA[<p>unescaped with %@</p>]]>' => '<![CDATA[<p>unescaped with %s</p>]]>', '<![CDATA[]]><![CDATA[<p>unescaped</p>]]>' => '<![CDATA[]]><![CDATA[<p>unescaped</p>]]>', '<![CDATA[&]]>' => '<![CDATA[&]]>', |