diff --git a/ModAssistant/Localisation/de.xaml b/ModAssistant/Localisation/de.xaml
index 5dd640f..6493fa5 100644
--- a/ModAssistant/Localisation/de.xaml
+++ b/ModAssistant/Localisation/de.xaml
@@ -151,6 +151,10 @@
Installiere Playlist: {0}
Titel fehlgeschlagen: {0}
[{0} Fehler] Playlist Installation abgeschlossen: {1}
+ Show OneClick Installer Window
+ Yes
+ Close
+ No
Diagnose
Log öffnen
AppData öffnen
@@ -223,6 +227,7 @@
Max tries reached: Skipping {0}
Ratelimit hit. Resuming in {0}
Download failed: {0}
+ Done'd
Design nicht gefunden, gehe zurück zum Standard Design...
diff --git a/ModAssistant/Localisation/en-DEBUG.xaml b/ModAssistant/Localisation/en-DEBUG.xaml
index c508210..6124d99 100644
--- a/ModAssistant/Localisation/en-DEBUG.xaml
+++ b/ModAssistant/Localisation/en-DEBUG.xaml
@@ -111,6 +111,10 @@
{0} Options:InstallingPlaylist
{0} Options:FailedPlaylistSong
{0} {1} Options:FinishedPlaylist
+ Options:ShowOCIWindow
+ Options:OCIWindowYes
+ Options:OCIWindowClose
+ Options:OCIWindowNo
Options:Diagnostics
Options:OpenLogsButton
Options:OpenAppDataButton
@@ -164,6 +168,7 @@
{0} OneClick:RatelimitSkip
{0} OneClick:RatelimitHit
{0} OneClick:Failed
+ OneClick:Done
Themes:ThemeNotFound
diff --git a/ModAssistant/Localisation/fr.xaml b/ModAssistant/Localisation/fr.xaml
index dc28f82..1854794 100644
--- a/ModAssistant/Localisation/fr.xaml
+++ b/ModAssistant/Localisation/fr.xaml
@@ -157,6 +157,10 @@
Installation de la playlist : {0}
Échec de la musique : {0}
[{0} échecs] Installation de la playlist terminée : {1}
+ Show OneClick Installer Window
+ Yes
+ Close
+ No
Diagnostic
Ouvrir les logs
Ouvrir AppData
@@ -230,7 +234,8 @@
Maximum de tentatives atteint : {0} passé
Limite atteinte. Reprise dans {0}
Téléchargement échoué : {0}
-
+ Done'd
+
Thème non trouvé, passage au thème par défaut...
Thème défini sur {0}.
diff --git a/ModAssistant/Localisation/it.xaml b/ModAssistant/Localisation/it.xaml
index 598f7ea..4e8ea37 100644
--- a/ModAssistant/Localisation/it.xaml
+++ b/ModAssistant/Localisation/it.xaml
@@ -151,6 +151,10 @@
Installazione Playlist: {0}
Installazione canzone fallita: {0}
[{0} fails] Installazione playlist terminata: {1}
+ Show OneClick Installer Window
+ Yes
+ Close
+ No
Diagnostica
Apri il Log
Apri AppData
@@ -223,7 +227,8 @@
Max tries reached: Skipping {0}
Ratelimit hit. Resuming in {0}
Download failed: {0}
-
+ Done'd
+
Tema non trovato, ritorno al tema predefinito...
Tema impostato su {0}.
diff --git a/ModAssistant/Localisation/ko.xaml b/ModAssistant/Localisation/ko.xaml
index a011cbc..b6e6180 100644
--- a/ModAssistant/Localisation/ko.xaml
+++ b/ModAssistant/Localisation/ko.xaml
@@ -150,6 +150,10 @@
Installing Playlist: {0}
Failed song: {0}
[{0} fails] Finished Installing Playlist: {1}
+ Show OneClick Installer Window
+ Yes
+ Close
+ No
진단
로그 열기
앱데이터 열기
@@ -222,7 +226,8 @@
Max tries reached: Skipping {0}
Ratelimit hit. Resuming in {0}
Download failed: {0}
-
+ Done'd
+
테마를 찾을 수 없어, 기본 테마로 돌아갑니다...
{0} 테마로 설정합니다.
diff --git a/ModAssistant/Localisation/nl.xaml b/ModAssistant/Localisation/nl.xaml
index 5e7333c..1e60ae4 100644
--- a/ModAssistant/Localisation/nl.xaml
+++ b/ModAssistant/Localisation/nl.xaml
@@ -31,7 +31,7 @@
Geen mod geselecteerd!
{0} heeft geen info pagina
-
+
Introductie
Welkom bij Mod Assistant
Lees deze pagina alstublieft volledig en aandachtig
@@ -149,6 +149,10 @@
Afspeellijst installeren: {0}
Installatie nummer mislukt: {0}
[{0} mislukkingen] Afspeellijst geïnstalleerd: {1}
+ Show OneClick Installer Window
+ Yes
+ Close
+ No
Diagnostiek
Open Logs
Open AppData
@@ -221,7 +225,8 @@
Maximaal aantal pogingen bereikt: {0} word overgeslagen
Snelheidslimiet bereikt. Gaat verder over {0}
Download mislukt: {0}
-
+ Done'd
+
Thema niet gevonden, terugvallen op standaard thema...
Theme ingesteld op {0}.
diff --git a/ModAssistant/Localisation/ru.xaml b/ModAssistant/Localisation/ru.xaml
index 007e6b8..264bc1e 100644
--- a/ModAssistant/Localisation/ru.xaml
+++ b/ModAssistant/Localisation/ru.xaml
@@ -151,6 +151,10 @@
Установка плейлиста: {0}
Ошибка с песней: {0}
[{0} ошибок] Установка плейлиста окончена: {1}
+ Show OneClick Installer Window
+ Yes
+ Close
+ No
Диагностика
Открыть логи
Открыть AppData
@@ -222,8 +226,9 @@
Установка: {0}
Достигнуто максимальное кол-во попыток: Пропускаем {0}
Достигнут лимит. Возобновление через {0}
- Скачивание неудалось: {0}
-
+ Скачивание неудалось: {0}
+ Done'd
+
Тема не найдена, возвращаемся к стандартной теме...
Установлена тема: {0}.
diff --git a/ModAssistant/Localisation/sv.xaml b/ModAssistant/Localisation/sv.xaml
index 9b3919d..30fc6ee 100644
--- a/ModAssistant/Localisation/sv.xaml
+++ b/ModAssistant/Localisation/sv.xaml
@@ -103,6 +103,7 @@
Detta kan leda till att dina andra mods slutar att fungera
Extrahering misslyckades {0}, försöker igen om {1} sekunder. ({2}/{3})
Misslyckades med att extrahera {0} efter maxantalet försök ({1}), hoppar över. Denna mod kanske inte fungerar som den ska så fortsätt på egen risk.
+ Search...
Om
@@ -140,9 +141,20 @@
Aktivera OneClick™-Installationer
BeatSaver
ModelSaber
+ Playlists
+ Close window when finished
Spelvariant
Steam
Oculus
+ Tools
+ Install Playlist
+ Installing Playlist: {0}
+ Failed song: {0}
+ [{0} fails] Finished Installing Playlist: {1}
+ Show OneClick Installer Window
+ Yes
+ Close
+ No
Diagnostikverktyg
Öppna Loggar
Öppna AppData
@@ -211,6 +223,11 @@
Misslyckades med att installera.
{0} OneClick™-installeringshanterare registrerade!
{0} OneClick™-installeringshanterare avregistrerade!
+ Installing: {0}
+ Max tries reached: Skipping {0}
+ Ratelimit hit. Resuming in {0}
+ Download failed: {0}
+ Done'd
Temat hittades inte, återställer till standardtemat...
diff --git a/tools/README.md b/tools/README.md
new file mode 100644
index 0000000..3d7e0ac
--- /dev/null
+++ b/tools/README.md
@@ -0,0 +1,7 @@
+# ModAssistant Tools
+> These are tools used to build / improve ModAssistant. **They are not to be distributed with the compiled binary.**
+
+## Translation Stubs
+Use `generate_translation_stubs.py` to read the English locale file and generate missing strings for all other locales. Requires Python 3.6 or above.
+
+Simply run `python ./tools/generate_translation_stubs.py` and commit the stubs.
diff --git a/tools/generate_translation_stubs.py b/tools/generate_translation_stubs.py
new file mode 100644
index 0000000..7aced83
--- /dev/null
+++ b/tools/generate_translation_stubs.py
@@ -0,0 +1,144 @@
+# -*- coding: utf-8 -*-
+import os
+import re
+from shutil import copyfile
+
+# --------------- Configuration ---------------- #
+master_file = "./ModAssistant/Localisation/en.xaml"
+source_dir = "./ModAssistant/Localisation"
+target_dir = source_dir
+comment = " "
+# --------------- Configuration ---------------- #
+
+
+def read_file(filepath):
+ """
+ Read file content
+ :param filepath:
+ :return:
+ """
+ with open(filepath, "r", encoding="utf-8") as file:
+ data = file.read()
+ return data
+
+
+def find_files(root_directory):
+ """
+ Find all files to be processed
+ :param root_directory:
+ :return:
+ """
+ for root, ds, fs in os.walk(root_directory):
+ for fn in fs:
+ fullname = os.path.join(root, fn)
+ master_name = os.path.basename(master_file)
+ if master_name in fullname:
+ continue
+ yield fullname
+
+
+def search(regex, m_string, group=1):
+ """
+ Search for the first item that matches by regular expression
+ :param regex:
+ :param m_string:
+ :return:
+ """
+ found = re.compile(regex, re.M).search(m_string)
+ result = ""
+ if found:
+ result = found.group(group)
+ return result
+
+
+def write_file(filepath, content):
+ """
+ Write text content to file
+ :param filepath:
+ :param content:
+ :return:
+ """
+ if not os.path.exists(target_dir):
+ os.makedirs(target_dir, exist_ok=True)
+ with open(filepath, "w", encoding="utf-8") as f:
+ f.write(content)
+
+
+def find_items(data):
+ keys_regex = r"<\s*([^\s>]+)\s.*Key[^>]+>"
+ keys_matches = re.finditer(keys_regex, data, re.M)
+ items = []
+ for n, m in enumerate(keys_matches, start=1):
+ if len(items):
+ last_dict = items[-1]
+ if len(last_dict):
+ last_dict['end'] = m.start()
+ items.append({"match": m[0], "name": m[1], "start": m.end()})
+ items[-1]['end'] = len(data)
+ for item in items:
+ item_text = data[item['start']: item['end']]
+ end_tag = "%s>" % item['name']
+ full_tag = item['match'] + item_text[:item_text.rfind(end_tag) + len(end_tag)]
+ item['end_tag'] = end_tag
+ item['full_tag'] = full_tag
+ return items
+
+
+def wrapper_key(match, content):
+ """
+ Try to find the comment behind the key
+ :param match:
+ :param content:
+ :return:
+ """
+ regex = "(\s*" + re.escape(match) + "(\ *<\!\-\-[^\-]+\-\->)?\s*)"
+ with_comment = search(r"" + str(regex), content, 1)
+ # print(regex)
+ # print(match)
+ # print(with_comment)
+ # print("-----")
+ if with_comment:
+ match = with_comment
+ return match
+
+
+def main():
+ """
+ Cycle processing of xaml files except master_file
+ :return:
+ """
+ master_data = read_file(master_file)
+ print("The master file is", master_file)
+ items = find_items(master_data)
+
+ for f in find_files(source_dir):
+ content = master_data + ""
+ xml_data = read_file(f)
+ xml_dict = {}
+ for xml_item in find_items(xml_data):
+ xml_dict[xml_item['match']] = xml_item['full_tag']
+ for item in items:
+ # print(f)
+ # if "OneClick:Done" in item['match'] and "fr.xaml" in f:
+ # print("----")
+ # pass
+ if item['match'] in xml_dict.keys():
+ match = wrapper_key(xml_dict[item['match']], xml_data)
+ master_match = wrapper_key(item['full_tag'], content)
+ # print(master_match)
+ content = content.replace(master_match, match)
+ else:
+ pre_blanks = search(r"(\s*)" + re.escape(item['full_tag']), master_data)
+ content = re.sub(r"\s*" + re.escape(item['full_tag']), pre_blanks + item['full_tag'] + comment, content)
+ # Put the processed files in the "dist" directory
+ filepath = f.replace(source_dir, target_dir)
+ write_file(filepath, content)
+ print("Processing", f)
+ # Copy "master_file" to the target directory
+ if source_dir != target_dir:
+ copyfile(master_file, master_file.replace(source_dir, target_dir))
+
+
+if __name__ == '__main__':
+ main()
+ print("done'd!")