mirror of
https://github.com/fergalmoran/picard.git
synced 2026-04-04 19:45:14 +00:00
PICARD-1929: Convert NSIS translations to/from JSON for Transifex
This commit is contained in:
57
installer/languages/json2nsh.py
Executable file
57
installer/languages/json2nsh.py
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Picard, the next-generation MusicBrainz tagger
|
||||
#
|
||||
# Copyright (C) 2020 Philipp Wolfer
|
||||
#
|
||||
# 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 2
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import glob
|
||||
import json
|
||||
import os.path
|
||||
|
||||
import nshutil as nsh
|
||||
|
||||
|
||||
def language_from_filename(path):
|
||||
lang = os.path.splitext(os.path.basename(path))[0]
|
||||
return (nsh.code_to_language(lang), lang)
|
||||
|
||||
|
||||
def write_langstring(f, language, identifier, text):
|
||||
langstring = nsh.make_langstring(language, identifier, text)
|
||||
f.write(langstring)
|
||||
|
||||
|
||||
def main():
|
||||
scriptdir = os.path.dirname(os.path.abspath(__file__))
|
||||
sourcesdir = os.path.join(scriptdir, 'sources')
|
||||
|
||||
for path in glob.glob(os.path.join(sourcesdir, '*.json')):
|
||||
language, language_code = language_from_filename(path)
|
||||
if not language:
|
||||
print(f'Unknown language code "{language_code}", skipping')
|
||||
continue
|
||||
target_file = os.path.join(scriptdir, f'{language}.nsh')
|
||||
with open(path, 'r', encoding='utf-8') as infile:
|
||||
data = json.loads(infile.read())
|
||||
with open(target_file, 'w+', encoding='utf-8') as outfile:
|
||||
for identifier, text in data.items():
|
||||
write_langstring(outfile, language, identifier, text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
60
installer/languages/nsh2json.py
Executable file
60
installer/languages/nsh2json.py
Executable file
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Picard, the next-generation MusicBrainz tagger
|
||||
#
|
||||
# Copyright (C) 2020 Philipp Wolfer
|
||||
#
|
||||
# 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 2
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import glob
|
||||
import json
|
||||
import os.path
|
||||
|
||||
import nshutil as nsh
|
||||
|
||||
|
||||
def language_from_filename(path):
|
||||
lang = os.path.splitext(os.path.basename(path))[0]
|
||||
return (lang, nsh.language_to_code(lang))
|
||||
|
||||
|
||||
def extract_strings(f):
|
||||
for line in f:
|
||||
parsed = nsh.parse_langstring(line)
|
||||
if parsed:
|
||||
yield parsed
|
||||
|
||||
|
||||
def main():
|
||||
scriptdir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
for path in glob.glob(os.path.join(scriptdir, '*.nsh')):
|
||||
language, language_code = language_from_filename(path)
|
||||
if not language_code:
|
||||
print(f'Unknown language "{language}", skipping')
|
||||
continue
|
||||
target_file = os.path.join(scriptdir, 'sources', f'{language_code}.json')
|
||||
with open(path, 'r', encoding='utf-8') as infile:
|
||||
output = {}
|
||||
for identifier, text in extract_strings(infile):
|
||||
output[identifier] = text
|
||||
|
||||
with open(target_file, 'w+', encoding='utf-8') as outfile:
|
||||
outfile.write(json.dumps(output, indent=4))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
107
installer/languages/nshutil.py
Normal file
107
installer/languages/nshutil.py
Normal file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Picard, the next-generation MusicBrainz tagger
|
||||
#
|
||||
# Copyright (C) 2020 Philipp Wolfer
|
||||
#
|
||||
# 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 2
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import re
|
||||
|
||||
|
||||
LANGUAGES = {
|
||||
'Arabic': 'ar',
|
||||
'Catalan': 'ca',
|
||||
'Czech': 'cs',
|
||||
'Danish': 'da',
|
||||
'Dutch': 'nl',
|
||||
'English': 'en',
|
||||
'Estonian': 'et',
|
||||
'Finnish': 'fi',
|
||||
'French': 'fr',
|
||||
'German': 'de',
|
||||
'Greek': 'el',
|
||||
'Hebrew': 'he',
|
||||
'Italian': 'it',
|
||||
'Japanese': 'ja',
|
||||
'Korean': 'ko',
|
||||
'Norwegian': 'nb',
|
||||
'Polish': 'pl',
|
||||
'Portuguese': 'pt',
|
||||
'PortugueseBR': 'pt_BR',
|
||||
'Russian': 'ru',
|
||||
'SimpChinese': 'zh-Hans',
|
||||
'Slovak': 'sk',
|
||||
'Slovenian': 'sl',
|
||||
'Spanish': 'es',
|
||||
'Swedish': 'sv',
|
||||
'TradChinese': 'zh-Hant',
|
||||
'Turkish': 'tr',
|
||||
'Ukrainian': 'uk',
|
||||
}
|
||||
|
||||
_R_LANGUAGES = dict([(code, name) for name, code in LANGUAGES.items()])
|
||||
|
||||
# See https://nsis.sourceforge.io/Docs/Chapter4.html#varstrings
|
||||
ESCAPE_CHARS = {
|
||||
r'$\r': '\r',
|
||||
r'$\n': '\n',
|
||||
r'$\t': '\t',
|
||||
r'$\"': '"',
|
||||
r'$\'': "'",
|
||||
r'$\`': '`',
|
||||
}
|
||||
|
||||
RE_LANGSTRING_LINE = re.compile(r'LangString\s+(?P<identifier>[A-Za-z0-9_]+)\s+\${LANG_[A-Z]+}\s+["\'`](?P<text>.*)["\'`]$')
|
||||
|
||||
|
||||
def language_to_code(language):
|
||||
return LANGUAGES.get(language)
|
||||
|
||||
|
||||
def code_to_language(language_code):
|
||||
return _R_LANGUAGES.get(language_code)
|
||||
|
||||
|
||||
def escape_string(text):
|
||||
for escape, char in ESCAPE_CHARS.items():
|
||||
if char in ("'", "`"): # No need to escape quotes other than ""
|
||||
continue
|
||||
text = text.replace(char, escape)
|
||||
return text
|
||||
|
||||
|
||||
def unescape_string(text):
|
||||
for escape, char in ESCAPE_CHARS.items():
|
||||
text = text.replace(escape, char)
|
||||
return text
|
||||
|
||||
|
||||
def parse_langstring(line):
|
||||
match = RE_LANGSTRING_LINE.match(line)
|
||||
if match:
|
||||
return (
|
||||
match.group('identifier'),
|
||||
unescape_string(match.group('text'))
|
||||
)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def make_langstring(language, identifier, text):
|
||||
language = language.upper()
|
||||
text = escape_string(text)
|
||||
return f'LangString {identifier} ${{LANG_{language}}} "{text}"\n'
|
||||
16
installer/languages/sources/de.json
Normal file
16
installer/languages/sources/de.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"MsgAlreadyInstalled": "${PRODUCT_NAME} ist bereits installiert. \n\nKlicken Sie \u201eOK\u201c um die vorherige Version zu deinstallieren oder \u201eAbbrechen\u201c um das Update abzubrechen.",
|
||||
"MsgApplicationRunning": "Die Anwendung ${PRODUCT_NAME} wird ausgef\u00fchrt. Bitte schlie\u00dfen und erneut versuchen.",
|
||||
"MsgRequires64Bit": "Diese Version von ${PRODUCT_NAME} erfordert ein 64-bit Windows-System.",
|
||||
"MuiDescriptionRequired": "Installiert ${PRODUCT_NAME} mit den f\u00fcr die Ausf\u00fchrung erforderlichen Dateien.",
|
||||
"MuiDescriptionLang": "Installiert \u00dcbersetzungen von ${PRODUCT_NAME} in verschiedenen Sprachen.",
|
||||
"MuiDescriptionShortcuts": "Installiert Verkn\u00fcpfungen, um ${PRODUCT_NAME} zu starten.",
|
||||
"MuiDescriptionDesktop": "Installiert eine Verkn\u00fcpfung auf dem Desktop.",
|
||||
"MuiDescriptionStarteMenu": "Installiert eine Verkn\u00fcpfung im Startmen\u00fc.",
|
||||
"OptionRemoveSettings": "Einstellungen und pers\u00f6nliche Daten entfernen",
|
||||
"SectionDesktop": "Desktop",
|
||||
"SectionLanguages": "Sprachen",
|
||||
"SectionRequired": "Programmdateien (erforderlich)",
|
||||
"SectionShortcuts": "Verkn\u00fcpfungen",
|
||||
"SectionStartMenu": "Startmen\u00fc"
|
||||
}
|
||||
16
installer/languages/sources/en.json
Normal file
16
installer/languages/sources/en.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"MsgAlreadyInstalled": "${PRODUCT_NAME} is already installed. \n\nClick \"OK\" to uninstall the previous version or \"Cancel\" to cancel this upgrade.",
|
||||
"MsgApplicationRunning": "The application ${PRODUCT_NAME} is running. Please close it and try again.",
|
||||
"MsgRequires64Bit": "This version of ${PRODUCT_NAME} requires a 64-bit Windows system.",
|
||||
"MuiDescriptionRequired": "Installs ${PRODUCT_NAME} along with the necessary files for it run.",
|
||||
"MuiDescriptionLang": "Installs translations of ${PRODUCT_NAME} in different languages.",
|
||||
"MuiDescriptionShortcuts": "Installs shortcuts to launch ${PRODUCT_NAME}.",
|
||||
"MuiDescriptionDesktop": "Installs a shortcut on the desktop.",
|
||||
"MuiDescriptionStarteMenu": "Installs a shortcut in the Start Menu.",
|
||||
"OptionRemoveSettings": "Remove settings and personal data",
|
||||
"SectionDesktop": "Desktop",
|
||||
"SectionLanguages": "Languages",
|
||||
"SectionRequired": "Program files (required)",
|
||||
"SectionShortcuts": "Shortcuts",
|
||||
"SectionStartMenu": "Start menu"
|
||||
}
|
||||
16
installer/languages/sources/fr.json
Normal file
16
installer/languages/sources/fr.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"MsgAlreadyInstalled": "${PRODUCT_NAME} est d\u00e9j\u00e0 install\u00e9. \n\nCliquez sur \u00ab\u00a0OK\u00a0\u00bb pour d\u00e9sinstaller la version pr\u00e9c\u00e9dente ou \u00ab\u00a0Annuler\u00a0\u00bb pour annuler cette mise \u00e0 jour.",
|
||||
"MsgApplicationRunning": "L\u2019application ${PRODUCT_NAME} est en cours d\u2019ex\u00e9cution. Veuillez la stopper et essayer \u00e0 nouveau.",
|
||||
"MsgRequires64Bit": "Cette version de ${PRODUCT_NAME} requiert un syst\u00e8me Windows 64 bits.",
|
||||
"MuiDescriptionRequired": "Installe ${PRODUCT_NAME} ainsi que les fichiers n\u00e9cessaires \u00e0 son ex\u00e9cution.",
|
||||
"MuiDescriptionLang": "Installe les traductions de ${PRODUCT_NAME} dans diff\u00e9rentes langues.",
|
||||
"MuiDescriptionShortcuts": "Installe les raccourcis pour lancer ${PRODUCT_NAME}.",
|
||||
"MuiDescriptionDesktop": "Installe un raccourci sur le bureau.",
|
||||
"MuiDescriptionStarteMenu": "Installe un raccourci dans le menu D\u00e9marrer.",
|
||||
"OptionRemoveSettings": "Supprimer les pr\u00e9f\u00e9rences et les donn\u00e9es personnelles",
|
||||
"SectionDesktop": "Bureau",
|
||||
"SectionLanguages": "Langues",
|
||||
"SectionRequired": "Fichiers du programme (requis)",
|
||||
"SectionShortcuts": "Raccourcis",
|
||||
"SectionStartMenu": "Menu D\u00e9marrer"
|
||||
}
|
||||
16
installer/languages/sources/it.json
Normal file
16
installer/languages/sources/it.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"MsgAlreadyInstalled": "${PRODUCT_NAME} \u00e8 gi\u00e0 installato.\n\nFai clic su 'OK' per disinstallare la versione installata o su 'Annulla' per annullare l'aggiornamento.",
|
||||
"MsgApplicationRunning": "L'applicazione ${PRODUCT_NAME} \u00e8 in esecuzione.\nChiudi l'applicazione e riprova.",
|
||||
"MsgRequires64Bit": "Questa versione di ${PRODUCT_NAME} richiede un sistema Windows a 64bit.",
|
||||
"MuiDescriptionRequired": "Installa ${PRODUCT_NAME} e i relativi file necessari alla sua esecuzione.",
|
||||
"MuiDescriptionLang": "Installa le traduzioni di ${PRODUCT_NAME} per le differenti lingue.",
|
||||
"MuiDescriptionShortcuts": "Installa collegamento per eseguire ${PRODUCT_NAME}.",
|
||||
"MuiDescriptionDesktop": "Installa collegamento sul desktop.",
|
||||
"MuiDescriptionStarteMenu": "Installa collegamento nel menu Start.",
|
||||
"OptionRemoveSettings": "Elimina impostazioni e dati personali",
|
||||
"SectionDesktop": "Desktop",
|
||||
"SectionLanguages": "Lingue",
|
||||
"SectionRequired": "File programma (richiesti)",
|
||||
"SectionShortcuts": "Collegamenti",
|
||||
"SectionStartMenu": "Menu Start"
|
||||
}
|
||||
16
installer/languages/sources/nl.json
Normal file
16
installer/languages/sources/nl.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"MsgAlreadyInstalled": "${PRODUCT_NAME} is al ge\u00efnstalleerd. \n\nKlik op \u201cOK\u201d om de vorige versie te verwijderen of op \u201cAnnuleren\u201d om de installatie te annuleren.",
|
||||
"MsgApplicationRunning": "De applicatie ${PRODUCT_NAME} is nog actief. Sluit haar af en probeer het opnieuw.",
|
||||
"MsgRequires64Bit": "Voor deze versie van ${PRODUCT_NAME} heb je een 64 bitssysteem nodig.",
|
||||
"MuiDescriptionRequired": "Installeert ${PRODUCT_NAME} en de bestanden die het nodig heeft om te draaien.",
|
||||
"MuiDescriptionLang": "Installeert vertalingen van ${PRODUCT_NAME}.",
|
||||
"MuiDescriptionShortcuts": "Installeert snelkoppelingen om ${PRODUCT_NAME} te starten.",
|
||||
"MuiDescriptionDesktop": "Installeert een snelkoppeling op het bureaublad.",
|
||||
"MuiDescriptionStarteMenu": "Installeert een snelkoppeling in het startmenu.",
|
||||
"OptionRemoveSettings": "Verwijder instellingen en persoonlijke gegevens",
|
||||
"SectionDesktop": "Bureaublad",
|
||||
"SectionLanguages": "Talen",
|
||||
"SectionRequired": "Programmabestanden (vereist)",
|
||||
"SectionShortcuts": "Snelkoppelingen",
|
||||
"SectionStartMenu": "Startmenu"
|
||||
}
|
||||
Reference in New Issue
Block a user