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 &
This commit is contained in:
parent
125eb59036
commit
ce96dcd425
2 changed files with 57 additions and 17 deletions
|
@ -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 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Android Strings File -->\n<!-- Generated by Twine -->\n<!-- Language: #{lang} -->"
|
||||
f.write '<resources>'
|
||||
|
@ -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<!-- #{comment} -->\n"
|
||||
end
|
||||
f.puts "\t<string name=\"#{key}\">#{value}</string>"
|
||||
end
|
||||
|
||||
if comment && comment.length > 0
|
||||
f.puts "\t<!-- #{comment} -->\n"
|
||||
end
|
||||
f.puts "\t<string name=\"#{key}\">#{value}</string>"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Reference in a new issue