I18N: Add script to generate translated strings.xml and fake cpp

- Add a python script (generate-android-i18n-strings.py)
 that generates the translated android strings.xml as per:
 https://developer.android.com/guide/topics/resources/providing-resources#AlternativeResources
 It considers the dists/android/res/values/strings.xml file as
 a base template to generate those translated strings.xml files.

- The python script also generates a fake cpp with strings from
 dists/android/res/values/strings.xml. These strings will be picked
 up by gettext to make it translatable. If there is any change in the
 original strings.xml file, we won't have to worry about the changes
 in cpp file.

- Add documentation for the generate-android-i18n-strings.py script
This commit is contained in:
Ankush Dutt 2023-04-09 17:49:46 +05:30 committed by Eugene Sandulenko
parent 1dae65f670
commit 74dff32dd9
31 changed files with 447 additions and 46 deletions

View File

@ -177,6 +177,20 @@ ___________________
https://docs.scummvm.org/en/latest/use_scummvm/mac_game_files.html
generate-android-i18n-strings.py
--------------------------------
This script generates translated strings.xml files
in dists/android/res/values-<qualifier> directory as per the specs:
https://developer.android.com/guide/topics/resources/providing-resources#AlternativeResources
It considers the dists/android/res/values/strings.xml file as a base template to generate
those translated files.
Additionally, this script generates a fake cpp file (dists/android.strings.xml.cpp) with strings
from dists/android/res/values/strings.xml wrapped inside _() to be picked up by
gettext for weblate translations. You can run it like this:
cd devtools && python3 generate-android-i18n-strings.py
gog_gameid.py, steam_gameid.py
______________________________
Tools for obtaining gameids from GOG and Steam used when preparing the

View File

@ -0,0 +1,149 @@
#!/usr/bin/env python3
# This script generates dists/android/res/values-<qualifier>/strings.xml files
# to add multilanguage support for android strings in res/values/strings.xml file.
# It considers dists/android/res/values/strings.xml file as a base template to generate
# those files. Relevant translated strings.xml file will be automatically used based on
# the android system's language.
#
# Also, this script generates a fake cpp file (dists/android/strings.xml.cpp) with strings
# from dists/android/res/values/strings.xml wrapped inside _() to be picked up by
# gettext for weblate translations
import polib
import os
import re
import xml.etree.ElementTree as ET
def generate_fake_cpp():
cpp_text = '''/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This is an auto generated dummy file used for sticking strings from
* dists/android/res/values/strings.xml into our translation system
*
*/
#include "common/translation.h" // For catching the file during POTFILES reviews\n
'''
with open('../dists/android.strings.xml.cpp', 'w') as file:
file.write(cpp_text)
tree = ET.parse('../dists/android/res/values/strings.xml')
root = tree.getroot()
for string in root.findall('string'):
if (string.attrib.get("translatable") != "false"):
file.write(
f'static Common::U32String {string.attrib.get("name")} = _("{string.text}");\n')
def extract_translations(file):
po_file = polib.pofile('../po/' + file + '.po')
translations = {}
for entry in po_file:
if entry.msgid and entry.msgstr:
translations[entry.msgid] = entry.msgstr
return translations
def escape_special_characters(translated_string):
'''Some characters like single quote (') have special usage in XML and hence must be escaped.\n
See: https://developer.android.com/guide/topics/resources/string-resource.html#escaping_quotes
'''
escaped = translated_string.replace('@', '\\@')
escaped = escaped.replace('?', '\\?')
escaped = escaped.replace('\'', '\\\'')
escaped = escaped.replace('\"', '\\\"')
escaped = escaped.replace('\n', '\\n')
escaped = escaped.replace('\t', '\\t')
return escaped
def is_bcp47_language_code(language_code):
pattern = r'^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$'
if re.match(pattern, language_code):
return True
else:
return False
def get_lang_qualifier(file):
'''Generates <qualifier> for res/values-<qualifier> directory as per the specs given here:
https://developer.android.com/guide/topics/resources/providing-resources#AlternativeResources
'''
lang_qualifier = file[0] + file[1]
if (is_bcp47_language_code(file)):
subtags = file.split("-")
lang_qualifier = "+".join(subtags)
lang_qualifier = "b+" + lang_qualifier
else:
lang_qualifier = file.replace('_', '-r')
return lang_qualifier
def generate_translated_xml(file):
tree = ET.parse('../dists/android/res/values/strings.xml')
root = tree.getroot()
translations = extract_translations(file)
for string in root.findall('string'):
if string.text in translations:
string.text = escape_special_characters(translations[string.text])
else:
root.remove(string)
ET.indent(tree, ' ')
dir = '../dists/android/res/values-' + get_lang_qualifier(file)
if not os.path.exists(dir):
os.makedirs(dir)
tree.write(dir + '/strings.xml', encoding='utf-8', xml_declaration=True)
def get_po_files():
po_file_names = []
for filename in os.listdir("../po/"):
if filename.endswith(".po"):
if (filename != "be-tarask.po"):
# This skips be-tarask file because there is a bug with be-tarask that gives this compile error:
# AAPT: error: failed to deserialize resource table: configuration has invalid locale 'be-'.
# See the open issue here: https://issuetracker.google.com/issues/234820481
po_file_names.append(os.path.splitext(filename)[0])
return po_file_names
def main():
generate_fake_cpp()
po_file_names = get_po_files()
for file in po_file_names:
generate_translated_xml(file)
if __name__ == '__main__':
main()

View File

@ -20,54 +20,32 @@
*/
/*
* This is a dummy file used for sticking strings from
* This is an auto generated dummy file used for sticking strings from
* dists/android/res/values/strings.xml into our translation system
*
*/
#include "common/translation.h" // For catching the file during POTFILES reviews
Common::U32String app_desc = _("Graphic adventure game engine");
Common::U32String ok = _("OK");
Common::U32String quit = _("Quit");
Common::U32String no_config_file_title = _("Config File Error");
Common::U32String no_config_file = _("Unable to read ScummVM config file or create a new one!");
Common::U32String no_save_path_title = _("Save Path Error");
Common::U32String no_save_path_configured = _("Unable to create or access default save path!");
Common::U32String no_icons_path_title = _("Icons Path Error");
Common::U32String no_icons_path_configured = _("Unable to create or access default icons and shaders path!");
Common::U32String bad_explicit_save_path_configured = _("Unable to access the globally set save path! Please revert to default from ScummVM Options");
Common::U32String keyboard_toggle_btn_desc = _("Toggle virtual keyboard");
Common::U32String customkeyboardview_keycode_alt =
// I18N: Description of the Alt button in a KeyboardView.
_("Alt");
Common::U32String customkeyboardview_keycode_cancel =
// I18N: Description of the Cancel button in a KeyboardView.
_("Cancel");
Common::U32String customkeyboardview_keycode_delete =
// I18N: Description of the Delete button in a KeyboardView.
_("Delete");
Common::U32String customkeyboardview_keycode_done =
// I18N: Description of the Done button in a KeyboardView.
_("Done");
Common::U32String customkeyboardview_keycode_mode_change =
// I18N: Description of the Mode change button in a KeyboardView.
_("Mode change");
Common::U32String customkeyboardview_keycode_shift =
// I18N: Description of the Shift button in a KeyboardView.
_("Shift");
Common::U32String customkeyboardview_keycode_enter =
// I18N: Description of the Enter button in a KeyboardView.
_("Enter");
Common::U32String customkeyboardview_popup_close = _("Close popup");
Common::U32String saf_request_prompt = _("Please select the *root* of your external (physical) SD card. This is required for ScummVM to access this path: ");
Common::U32String saf_revoke_done = _("Storage Access Framework Permissions for ScummVM were revoked!");
static Common::U32String app_name = _("ScummVM");
static Common::U32String app_desc = _("Graphic adventure game engine");
static Common::U32String ok = _("OK");
static Common::U32String quit = _("Quit");
static Common::U32String no_config_file_title = _("Config File Error");
static Common::U32String no_config_file = _("Unable to read ScummVM config file or create a new one!");
static Common::U32String no_save_path_title = _("Save Path Error");
static Common::U32String no_save_path_configured = _("Unable to create or access default save path!");
static Common::U32String no_icons_path_title = _("Icons Path Error");
static Common::U32String no_icons_path_configured = _("Unable to create or access default icons and shaders path!");
static Common::U32String bad_explicit_save_path_configured = _("Unable to access the globally set save path! Please revert to default from ScummVM Options");
static Common::U32String keyboard_toggle_btn_desc = _("Toggle virtual keyboard");
static Common::U32String customkeyboardview_keycode_alt = _("Alt");
static Common::U32String customkeyboardview_keycode_cancel = _("Cancel");
static Common::U32String customkeyboardview_keycode_delete = _("Delete");
static Common::U32String customkeyboardview_keycode_done = _("Done");
static Common::U32String customkeyboardview_keycode_mode_change = _("Mode change");
static Common::U32String customkeyboardview_keycode_shift = _("Shift");
static Common::U32String customkeyboardview_keycode_enter = _("Enter");
static Common::U32String customkeyboardview_popup_close = _("Close popup");
static Common::U32String saf_request_prompt = _("Please select the *root* of your external (physical) SD card. This is required for ScummVM to access this path: ");
static Common::U32String saf_revoke_done = _("Storage Access Framework Permissions for ScummVM were revoked!");

View File

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Afslut</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Annuller</string>
<string name="customkeyboardview_keycode_delete">Slet</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Έξοδος</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Ακύρωση</string>
<string name="customkeyboardview_keycode_delete">Σβήσιμο</string>
<string name="customkeyboardview_keycode_shift">Πλήκτρο Shift</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">Ados</string>
<string name="quit">Irten</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Utzi</string>
<string name="customkeyboardview_keycode_delete">Ezabatu</string>
<string name="customkeyboardview_keycode_enter">Sartu</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">אישור</string>
<string name="quit">יציאה</string>
<string name="customkeyboardview_keycode_alt">אלט</string>
<string name="customkeyboardview_keycode_cancel">ביטול</string>
<string name="customkeyboardview_keycode_delete">מחיקה</string>
<string name="customkeyboardview_keycode_shift">Shift</string>
<string name="customkeyboardview_keycode_enter">להיכנס</string>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">ठीक है</string>
<string name="quit">खेल</string>
<string name="customkeyboardview_keycode_cancel">रद्द करें</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">終了</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">キャンセル</string>
<string name="customkeyboardview_keycode_delete">削除</string>
<string name="customkeyboardview_keycode_shift">シフト</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">확인</string>
<string name="quit">종료</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">취소</string>
<string name="customkeyboardview_keycode_delete">삭제</string>
<string name="customkeyboardview_keycode_shift">시프트 키</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,8 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Oyun</string>
<string name="customkeyboardview_keycode_cancel">İptal</string>
<string name="customkeyboardview_keycode_delete">Sil</string>
<string name="customkeyboardview_keycode_enter">Etkileşim</string>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">确认</string>
<string name="quit">離開</string>
<string name="customkeyboardview_keycode_cancel">取消</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Выхад</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Адмена</string>
<string name="customkeyboardview_keycode_delete">Выдаліць</string>
<string name="customkeyboardview_keycode_shift">Shift</string>
<string name="customkeyboardview_keycode_enter">Увод</string>
</resources>

View File

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">D\'acord</string>
<string name="quit">Surt</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Cancel·la</string>
<string name="customkeyboardview_keycode_delete">Suprimeix</string>
<string name="customkeyboardview_keycode_enter">Intro</string>
</resources>

View File

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Ukončit</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Zrušit</string>
<string name="customkeyboardview_keycode_delete">Smazat</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Beenden</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Abbrechen</string>
<string name="customkeyboardview_keycode_delete">Löschen</string>
<string name="customkeyboardview_keycode_shift">Umschalt-Taste</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">Aceptar</string>
<string name="quit">Salir</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Cancelar</string>
<string name="customkeyboardview_keycode_delete">Eliminar</string>
<string name="customkeyboardview_keycode_shift">Mayúsculas</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Lopeta</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Peruuta</string>
<string name="customkeyboardview_keycode_delete">Poista</string>
<string name="customkeyboardview_keycode_shift">Shift</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Quitter</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Annuler</string>
<string name="customkeyboardview_keycode_delete">Supprimer</string>
<string name="customkeyboardview_keycode_shift">Shift</string>
<string name="customkeyboardview_keycode_enter">Entrer</string>
</resources>

View File

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">Aceptar</string>
<string name="quit">Saír</string>
<string name="customkeyboardview_keycode_alt">ALT</string>
<string name="customkeyboardview_keycode_cancel">Cancelar</string>
<string name="customkeyboardview_keycode_delete">Eliminar</string>
<string name="customkeyboardview_keycode_enter">INTRO</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Kilépés</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Mégse</string>
<string name="customkeyboardview_keycode_delete">Töröl</string>
<string name="customkeyboardview_keycode_shift">Shift</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Esci</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Annulla</string>
<string name="customkeyboardview_keycode_delete">Elimina</string>
<string name="customkeyboardview_keycode_shift">Tasto Maiusc</string>
<string name="customkeyboardview_keycode_enter">Invio</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Avslutt</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Avbryt</string>
<string name="customkeyboardview_keycode_delete">Slett</string>
<string name="customkeyboardview_keycode_shift">Shift</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Stoppen</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Annuleren</string>
<string name="customkeyboardview_keycode_delete">Verwijderen</string>
<string name="customkeyboardview_keycode_shift">Shift</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Avslutt</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Avbryt</string>
<string name="customkeyboardview_keycode_delete">Slett</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Zakończ</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Anuluj</string>
<string name="customkeyboardview_keycode_delete">Skasuj</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Sair</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Cancelar</string>
<string name="customkeyboardview_keycode_delete">Excluir</string>
<string name="customkeyboardview_keycode_shift">Shift</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,8 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Sair</string>
<string name="customkeyboardview_keycode_cancel">Cancelar</string>
<string name="customkeyboardview_keycode_delete">Eliminar</string>
<string name="customkeyboardview_keycode_enter">Centrado</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Выход</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Отмена</string>
<string name="customkeyboardview_keycode_delete">Удалить</string>
<string name="customkeyboardview_keycode_shift">Shift</string>
<string name="customkeyboardview_keycode_enter">Ввод</string>
</resources>

View File

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Avsluta</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Avbryt</string>
<string name="customkeyboardview_keycode_delete">Radera</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="ok">OK</string>
<string name="quit">Вихід</string>
<string name="customkeyboardview_keycode_alt">Alt</string>
<string name="customkeyboardview_keycode_cancel">Відміна</string>
<string name="customkeyboardview_keycode_delete">Видалити</string>
<string name="customkeyboardview_keycode_shift">Shift</string>
<string name="customkeyboardview_keycode_enter">Enter</string>
</resources>