From ce96dcd4259bcc1badf5f6b690d12525231aca45 Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Mon, 20 Feb 2012 14:43:33 -0500 Subject: [PATCH] android-specific improvements - cross-reference between iOS/Android language/region codes - support for default languages other than English - proper escaping of ' and " - translation between %@ and %s, including numbered parameters (e.g. %1$@) - proper XML-escaping of < and & --- lib/twine/formatters/android.rb | 61 ++++++++++++++++++++++++--------- lib/twine/stringsfile.rb | 13 ++++++- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/lib/twine/formatters/android.rb b/lib/twine/formatters/android.rb index 633df1f..449490c 100644 --- a/lib/twine/formatters/android.rb +++ b/lib/twine/formatters/android.rb @@ -1,6 +1,5 @@ # encoding: utf-8 -require 'cgi' require 'rexml/document' module Twine @@ -9,6 +8,20 @@ module Twine FORMAT_NAME = 'android' EXTENSION = '.xml' DEFAULT_FILE_NAME = 'strings.xml' + LANG_CODES = Hash[ + 'zh' => 'zh-Hans', + 'zh-rCN' => 'zh-Hans', + 'zh-rHK' => 'zh-Hant', + 'zh-rTW' => 'zh-TW', + 'en-rGB' => 'en-UK', + 'fr-rCA' => 'fr-CA', + 'in' => 'id', + 'nb' => 'no' + # TODO: spanish + ] + DEFAULT_LANG_CODES = Hash[ + 'zh-TW' => 'zh-Hant' # if we don't have a zh-TW translation, try zh-Hant before en + ] def self.can_handle_directory?(path) Dir.entries(path).any? { |item| /^values-.+$/.match(item) } @@ -24,6 +37,7 @@ module Twine match = /^values-(.*)$/.match(segment) if match lang = match[1] + lang = LANG_CODES.fetch(lang, lang) lang.sub!('-r', '-') return lang end @@ -42,14 +56,19 @@ module Twine value.gsub!('\\\'', '\'') value.gsub!('\\"', '"') value.gsub!(/\n/, '') - value.gsub!('%s', '%@') + value.gsub!(/%([0-9\$]*)s/, '%\1@') + value.gsub!('<', '<') + value.gsub!('&', '&') set_translation_for_key(key, lang, value) end end end def write_file(path, lang) - default_lang = @strings.language_codes[0] + default_lang = [@strings.language_codes[0]] + if DEFAULT_LANG_CODES.has_key?(lang) + default_lang.insert(0, DEFAULT_LANG_CODES[lang]) + end File.open(path, 'w:UTF-8') do |f| f.puts "\n\n\n" f.write '' @@ -67,22 +86,32 @@ module Twine end key = row.key - key = CGI.escapeHTML(key) value = row.translated_string_for_lang(lang, default_lang) - value.gsub!('\'', '\\\\\'') - value.gsub!('%@', '%s') - value = CGI.escapeHTML(value) - - comment = row.comment - if comment - comment = comment.gsub('--', '—') + value = String.new(value) # use a copy to prevent modifying the original + if value + # if values is nil, there was no default, so let Android handle the defaulting + + # Android enforces the following rules on the values + # 1) apostrophes and quotes must be escaped with a backslash + value.gsub!('\'', '\\\\\'') + value.gsub!('"', '\\\\"') + # 2) ampersand and less-than must be in XML-escaped form + value.gsub!('&', '&') + value.gsub!('<', '<') + # 3) use "s" instead of "@" for substituting strings + value.gsub!(/%([0-9\$]*)@/, '%\1s') + + comment = row.comment + if comment + comment = comment.gsub('--', '—') + end + + if comment && comment.length > 0 + f.puts "\t\n" + end + f.puts "\t#{value}" end - - if comment && comment.length > 0 - f.puts "\t\n" - end - f.puts "\t#{value}" end end end diff --git a/lib/twine/stringsfile.rb b/lib/twine/stringsfile.rb index 47ff1be..3d82a15 100644 --- a/lib/twine/stringsfile.rb +++ b/lib/twine/stringsfile.rb @@ -41,7 +41,18 @@ module Twine end def translated_string_for_lang(lang, default_lang=nil) - @translations[lang] || @translations[default_lang] + if @translations[lang] + return @translations[lang] + elsif default_lang.respond_to?("each") + default_lang.each do |def_lang| + if @translations[def_lang] + return @translations[def_lang] + end + end + return nil + else + return @translations[default_lang] + end end end