Beam/Tools/Scripts/localizer.py
ismailgulek 25eea4bcf1
Localizations Setup (#6)
* Move assets into ElementX folder

* Add first version of localizer script

* Add generated strings & tests & fallback mechanism

* Rename strings file to Localizable

* Rename Assets to Resources

* Calculate preferred languages only when needed, remove share extension check

* Add comments in the localizer script

* Add GH workflow to push issues to the [ElementX board](https://github.com/orgs/vector-im/projects/43)

* Closes #16 - Add license file

* New version of localizer script, handle pluralization

* Move assets into ElementX folder

* Add first version of localizer script

* Add generated strings & tests & fallback mechanism

* Rename strings file to Localizable

* Rename Assets to Resources

* Calculate preferred languages only when needed, remove share extension check

* Add comments in the localizer script

* New version of localizer script, handle pluralization

* Revert login button text

* Add multiple dialect pluralization, fix string formatting

Co-authored-by: manuroe <manu@matrix.org>
Co-authored-by: Stefan Ceriu <stefanc@matrix.org>
2022-04-26 22:48:17 +03:00

143 lines
5.8 KiB
Python
Executable File

#!/usr/bin/python2.7
import sys
import os
import errno
from imp import reload
from xml.etree import cElementTree as ET
from xml.etree.ElementTree import XMLParser
encoding = 'utf-8'
if sys.version_info.major < 3:
reload(sys)
sys.setdefaultencoding(encoding)
# normalize given language code to iOS language code format:
# https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html
def normalize_language_code(code):
mappings = {
'b+sr+Latn': 'sr-Latn'
}
# codes cannot be converted: 'vls', 'ang', 'szl', 'tzm'
# return from mappings if exists
if code in mappings:
return mappings[code]
# try to strip additional 'r' from the code
r_tag = code.find('-r')
if len(code) == 6 and r_tag != -1:
result = code.replace('-r', '-')
return result
# return the original
return code
# normalize given string by handling escapes and Android -> iOS format specifiers
def normalize_str(e):
unique_tmp_val = '___'
quote = '"'
escaping_quote = '\\"'
result = str(e).encode(encoding).strip() # convert input to a encoded string object and strip
result = result.replace(escaping_quote, unique_tmp_val) # replace escaping quotes with a temp value
result = result.replace(quote, '') # remove all quotes
result = result.replace(unique_tmp_val, escaping_quote) # revert temp values to escaping quotes back
result = result.replace('%s', '%@') # replace C-style specifiers
for i in range(1, 6):
result = result.replace('%' + str(i) + '$s', '%' + str(i) + '$@') # replace C-style indexed specifiers
result = result.replace('${app_name}', '%@') # replace JSON-style specifiers
result = result.replace('$ {app_name}', '%@') # replace JSON-style specifiers
result = result.replace('&amp;', '&') # replace ampersand
result = result.replace('&lt;', '<') # replace less than
result = result.replace('&gt;', '>') # replace greater than
result = result.replace('\n', '')
return result
def create_directories_for(output):
if not os.path.exists(os.path.dirname(output)):
try:
os.makedirs(os.path.dirname(output))
except OSError as exc:
if exc.errno != errno.EEXIST:
raise
def convert_file(input, output):
create_directories_for(output)
f_strings = open(output, 'w')
# parse input XML into root
root = ET.parse(input, parser=XMLParser(encoding=encoding)).getroot()
for node in root.findall('string'):
key = node.get('name')
value = ET.tostring(node, encoding=encoding)
value = value.replace('</string>', '')
end_of_string_tag = value.find('>')
if end_of_string_tag != -1:
value = value[end_of_string_tag+1:]
f_strings.write('"' + normalize_str(key) + '" = "' + normalize_str(value) + '";' + '\n')
f_strings.close()
# parse plurals and build stringsdict plist
strings_plist = ET.Element('plist')
strings_plist.set('version', '1.0')
stringsDict = ET.SubElement(strings_plist, 'dict')
for node in root.findall('plurals'):
top_key = ET.SubElement(stringsDict, 'key')
top_key.text = node.get('name')
top_dict = ET.SubElement(stringsDict, 'dict')
format_key = ET.Element('key')
format_key.text = 'NSStringLocalizedFormatKey'
top_dict.append(format_key)
inner_string = ET.Element('string')
inner_string.text = '%#@VARIABLE@'
top_dict.append(inner_string)
inner_key2 = ET.Element('key')
inner_key2.text = 'VARIABLE'
top_dict.append(inner_key2)
inner_dict = ET.Element('dict')
spec_type_key = ET.SubElement(inner_dict, 'key')
spec_type_key.text = 'NSStringFormatSpecTypeKey'
rule_type_key = ET.SubElement(inner_dict, 'string')
rule_type_key.text = 'NSStringPluralRuleType'
value_type_key = ET.SubElement(inner_dict, 'key')
value_type_key.text = 'NSStringFormatValueTypeKey'
value_type_value_string = ET.SubElement(inner_dict, 'string')
value_type_value_string.text = 'd'
for item in node.findall('item'):
if item.text is not None and item.text != '':
value = item.text
quantity = item.get('quantity')
key = ET.SubElement(inner_dict, 'key')
key.text = normalize_str(quantity)
string = ET.SubElement(inner_dict, 'string')
string.text = normalize_str(value)
top_dict.append(inner_dict)
# write to stringsdict file
if stringsDict.find('key') is not None:
output_dict = str(output) + 'dict'
tree = ET.ElementTree(element=strings_plist)
tree.write(file_or_filename=output_dict, encoding=encoding, xml_declaration=False)
os.system('plutil -convert xml1 ' + output_dict)
# os.system('./fetch_android_strings.sh')
print('\nAndroid strings fetched.\n')
res_folder = 'element-android/vector/src/main/res'
for subdir, dirs, files in os.walk(res_folder):
for dir in dirs:
lang_code = dir
lang_code = lang_code.replace('values-', '')
if lang_code == 'values':
lang_code = 'en'
input = os.path.join(os.path.join(res_folder, dir), 'strings.xml')
output = '../../ElementX/Resources/Localizations/' + normalize_language_code(lang_code) + '.lproj/Localizable.strings'
input = os.path.realpath(input)
output = os.path.realpath(output)
print('--- Processing ' + lang_code + ' as: ' + normalize_language_code(lang_code))
convert_file(input, output)
print('')
os.chdir('../..')
os.system('xcodegen')