i18n with QT

This commit is contained in:
2022-02-01 18:29:54 +01:00
parent 26e2ee89e8
commit 939c86dbe2
11 changed files with 356 additions and 29 deletions

View File

@@ -20,7 +20,7 @@ class AboutDialog(QDialog):
self.layout = QVBoxLayout(self)
heading_app_name = QLabel("RavenLog")
heading_app_name = QLabel(self.tr("RavenLog"))
heading_app_name.setAlignment(Qt.AlignmentFlag.AlignLeft)
heading_app_name.setFont(QFont("default", 25))
heading_app_name.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)

View File

@@ -335,13 +335,13 @@ class InnerBigText(QWidget):
you_sure.setStandardButtons(QMessageBox.StandardButton.Cancel)
you_sure.addButton(QPushButton(self.tr("Copy {0} to Clipboard").format(bytes_human_readable)),
QMessageBox.ButtonRole.AcceptRole)
you_sure.addButton(QPushButton(self.tr("Write to File")), QMessageBox.ButtonRole.YesRole)
you_sure.addButton(QPushButton(self.tr("Write to File")), QMessageBox.ActionRole)
you_sure.setDefaultButton(QMessageBox.StandardButton.Cancel)
result = you_sure.exec()
if result == 1: # second custom button has the number 1
self._copy_selection_to_file()
if result == QMessageBox.StandardButton.Cancel.value:
if result == QMessageBox.StandardButton.Cancel:
# abort
return

16
main.py
View File

@@ -1,10 +1,11 @@
import logging
import os
import signal
import ctypes
from PySide6 import QtCore
from PySide6.QtWidgets import QApplication
from PySide6.QtCore import QTimer
from PySide6.QtCore import QTimer, QLibraryInfo, QTranslator, QLocale
from PySide6.QtGui import QIcon
import sys
@@ -40,6 +41,17 @@ if __name__ == "__main__":
# if translator.load(QLocale("de"), "messages_de.ts"):
# app.installTranslator(translator)
locale = os.environ['LANG'] if os.environ['LANG'] else "en"
path = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
translator = QTranslator(app)
if translator.load(QLocale(locale), 'qtbase', '_', path):
app.installTranslator(translator)
translator = QTranslator(app)
path = './translations'
if translator.load(QLocale(locale), 'messages', '_', path):
app.installTranslator(translator)
# workaround to make signals work in QT apps.
# They do not work out of the box, because the main thread
# is running in C++ code once app.exec() is executed
@@ -55,6 +67,8 @@ if __name__ == "__main__":
PluginRegistry.load_plugin("LogFilePlugin")
PluginRegistry.load_plugin("NotesPlugin")
PluginRegistry.execute("set_translator", lambda string: translator.tr(string))
window = PluginRegistry.execute_single("create_main_window")
RavenUI.window = window
window.show()

View File

@@ -1,29 +1,326 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>MainWindow</name>
<TS version="2.1" language="de_DE">
<context>
<name>AboutDialog</name>
<message>
<location filename="main.py" line="22" />
<location filename="aboutdialog.py" line="18"/>
<source>About RavenLog</source>
<translation>Über RavenLog</translation>
</message>
<message>
<location filename="aboutdialog.py" line="23"/>
<source>RavenLog</source>
<translation>RavenLog</translation>
</message>
<message>
<location filename="main.py" line="36" />
<source>Font Size:</source>
<translation>Schriftgröße:</translation>
<location filename="aboutdialog.py" line="28"/>
<source>Version: {0}</source>
<translation>Version: {0}</translation>
</message>
<message>
<location filename="main.py" line="72" />
<source>File</source>
<comment>name of the file menu</comment>
<translation>Datei</translation>
<location filename="aboutdialog.py" line="43"/>
<source>About</source>
<translation>Über RavenLog</translation>
</message>
<message>
<location filename="main.py" line="73" />
<source>Close</source>
<comment>menu item to close the application</comment>
<translation>Schließen</translation>
<location filename="aboutdialog.py" line="44"/>
<source>License</source>
<translation>Lizenz</translation>
</message>
</context>
</context>
<context>
<name>ColorButton</name>
<message>
<location filename="colorbutton.py" line="18"/>
<source>Strawberry Cream</source>
<translation>Strawberry Cream</translation>
</message>
<message>
<location filename="colorbutton.py" line="19"/>
<source>Pale Crimson</source>
<translation>Pale Crimson</translation>
</message>
<message>
<location filename="colorbutton.py" line="21"/>
<source>Broken Buttercup</source>
<translation>Broken Buttercup</translation>
</message>
<message>
<location filename="colorbutton.py" line="22"/>
<source>Passion Fruit Sugar</source>
<translation>Passion Fruit Sugar</translation>
</message>
<message>
<location filename="colorbutton.py" line="24"/>
<source>Sunrise Yellow</source>
<translation>Sunrise Yellow</translation>
</message>
<message>
<location filename="colorbutton.py" line="25"/>
<source>Magical Mustard</source>
<translation>Magical Mustard</translation>
</message>
<message>
<location filename="colorbutton.py" line="27"/>
<source>Trendy Green</source>
<translation>Trendy Green</translation>
</message>
<message>
<location filename="colorbutton.py" line="28"/>
<source>Garden Of Sweden</source>
<translation>Garden Of Sweden</translation>
</message>
<message>
<location filename="colorbutton.py" line="30"/>
<source>Light Sky Blue</source>
<translation>Light Sky Blue</translation>
</message>
<message>
<location filename="colorbutton.py" line="31"/>
<source>True Blue</source>
<translation>True Blue</translation>
</message>
<message>
<location filename="colorbutton.py" line="33"/>
<source>Fairy Topia</source>
<translation>Fairy Topia</translation>
</message>
<message>
<location filename="colorbutton.py" line="34"/>
<source>Magenta Bachiego</source>
<translation>Magenta Bachiego</translation>
</message>
<message>
<location filename="colorbutton.py" line="36"/>
<source>Breeze of Mist</source>
<translation>Breeze of Mist</translation>
</message>
<message>
<location filename="colorbutton.py" line="37"/>
<source>Light Grey</source>
<translation>Light Grey</translation>
</message>
<message>
<location filename="colorbutton.py" line="38"/>
<source>Grey</source>
<translation>Grey</translation>
</message>
<message>
<location filename="colorbutton.py" line="44"/>
<source>transparent</source>
<translation>Transparent</translation>
</message>
<message>
<location filename="colorbutton.py" line="51"/>
<source>custom</source>
<translation>Individuell</translation>
</message>
</context>
<context>
<name>FilterWidget</name>
<message>
<location filename="filterwidget.py" line="99"/>
<source>Cancel</source>
<translation>Abbrechen</translation>
</message>
<message>
<location filename="filterwidget.py" line="103"/>
<source>ignore case</source>
<translation>Groß-/Kleinschreibung</translation>
</message>
<message>
<location filename="filterwidget.py" line="107"/>
<source>regex</source>
<translation>RegExp</translation>
</message>
</context>
<context>
<name>HighlightingDialog</name>
<message>
<location filename="highlightingdialog.py" line="21"/>
<source>Manage Highlighting</source>
<translation>Hervorhebungen Verwalten</translation>
</message>
<message>
<location filename="highlightingdialog.py" line="33"/>
<source>Add</source>
<translation>Hinzufügen</translation>
</message>
<message>
<location filename="highlightingdialog.py" line="37"/>
<source>Update</source>
<translation>Aktualisieren</translation>
</message>
<message>
<location filename="highlightingdialog.py" line="41"/>
<source>Remove</source>
<translation>Entfernen</translation>
</message>
<message>
<location filename="highlightingdialog.py" line="45"/>
<source>Up</source>
<translation>Hoch</translation>
</message>
<message>
<location filename="highlightingdialog.py" line="49"/>
<source>Down</source>
<translation>Runter</translation>
</message>
<message>
<location filename="highlightingdialog.py" line="57"/>
<source>Query:</source>
<translation>Suche</translation>
</message>
<message>
<location filename="highlightingdialog.py" line="61"/>
<source>Ignore Case</source>
<translation>Groß-/Kleinschreibung</translation>
</message>
<message>
<location filename="highlightingdialog.py" line="66"/>
<source>Regular Expression</source>
<translation>Regulärer Ausdruck</translation>
</message>
<message>
<location filename="highlightingdialog.py" line="71"/>
<source>Hit Background:</source>
<translation>Hintergrund Treffer</translation>
</message>
<message>
<location filename="highlightingdialog.py" line="76"/>
<source>Line Background:</source>
<translation>Hintergrund Zeile</translation>
</message>
<message>
<location filename="highlightingdialog.py" line="140"/>
<source>unsaved changes</source>
<translation>nicht gespeicherte Änderungen</translation>
</message>
<message>
<location filename="highlightingdialog.py" line="141"/>
<source>You have unsaved changes. Continue?</source>
<translation>Du hast Änderungen die noch nicht gespeichert sind. Weiter?</translation>
</message>
<message>
<location filename="highlightingdialog.py" line="143"/>
<source>Continue</source>
<translation>Weiter</translation>
</message>
</context>
<context>
<name>InnerBigText</name>
<message>
<location filename="bigtext.py" line="171"/>
<source>&amp;Copy to Clipboard</source>
<translation>&amp;Kopiere in die Zwischenablage</translation>
</message>
<message>
<location filename="bigtext.py" line="177"/>
<source>Copy to &amp;File</source>
<translation>Speichere als &amp;Datei</translation>
</message>
<message>
<location filename="bigtext.py" line="182"/>
<source>Select &amp;All</source>
<translation>&amp;Alles Selektieren</translation>
</message>
<message>
<location filename="bigtext.py" line="188"/>
<source>&amp;Highlighter</source>
<translation>&amp;Hervorhebungen</translation>
</message>
<message>
<location filename="bigtext.py" line="332"/>
<source>data selection</source>
<translation>Selektion</translation>
</message>
<message>
<location filename="bigtext.py" line="334"/>
<source>You have selected &lt;b&gt;{0}&lt;/b&gt; of data.</source>
<translation>Du hast &lt;b&gt;{0}&lt;/b&gt; selektiert.</translation>
</message>
<message>
<location filename="bigtext.py" line="336"/>
<source>Copy {0} to Clipboard</source>
<translation>{0} in Zwischenablage kopieren</translation>
</message>
<message>
<location filename="bigtext.py" line="337"/>
<source>Write to File</source>
<translation>In Datei speichern</translation>
</message>
<message>
<location filename="bigtext.py" line="357"/>
<source>Save File</source>
<translation>Datei Speichern</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="raven/mainwindow.py" line="40"/>
<source>RavenLog</source>
<translation>RavenLog</translation>
</message>
<message>
<location filename="raven/mainwindow.py" line="48"/>
<source>Open &amp;Recent</source>
<translation>Zu&amp;letzt geöffnete Dateien</translation>
</message>
<message>
<location filename="raven/mainwindow.py" line="67"/>
<source>&amp;File</source>
<translation>&amp;Datei</translation>
</message>
<message>
<location filename="raven/mainwindow.py" line="68"/>
<source>&amp;Settings</source>
<translation>&amp;Einstellungen</translation>
</message>
<message>
<location filename="raven/mainwindow.py" line="69"/>
<source>&amp;Window</source>
<translation>&amp;Fenster</translation>
</message>
<message>
<location filename="raven/mainwindow.py" line="70"/>
<source>&amp;Help</source>
<translation>&amp;Hilfe</translation>
</message>
</context>
<context>
<name>NotesPlugin</name>
<message>
<location filename="raven/plugins/notesplugin.py" line="29"/>
<source>Add &amp;Notes</source>
<translation>Notizen Hinzufügen</translation>
</message>
<message>
<location filename="raven/plugins/notesplugin.py" line="37"/>
<source>Notes %d</source>
<translation>Notizen %d</translation>
</message>
</context>
<context>
<name>OpenFilePlugin</name>
<message>
<location filename="raven/plugins/openfileplugin.py" line="48"/>
<source>Open File</source>
<translation>Datei öffnen</translation>
</message>
</context>
<context>
<name>RavenLogPlugin</name>
<message>
<location filename="raven/plugins/ravenlogplugin.py" line="45"/>
<source>&amp;About</source>
<translation>&amp;Über RavenLog</translation>
</message>
<message>
<location filename="raven/plugins/ravenlogplugin.py" line="53"/>
<source>E&amp;xit</source>
<translation>Be&amp;enden</translation>
</message>
</context>
</TS>

View File

@@ -35,7 +35,7 @@ class MainWindow(QMainWindow):
self.settings = SettingsStore.load()
PluginRegistry.execute("set_settings", self.settings)
PluginRegistry.execute("set_translator", self.tr)
self.setWindowTitle(self.tr("RavenLog"))
self._restore_window()
@@ -80,7 +80,7 @@ class MainWindow(QMainWindow):
action = self._raction_to_qaction(menu_contribution.action, menu)
menu.addAction(action)
if menu_contribution.menu:
submenu = QMenu(self.tr(menu_contribution.menu.label), menu_bar)
submenu = QMenu(menu_contribution.menu.label, menu_bar)
submenu.setIcon(QIcon.fromTheme(menu_contribution.menu.icon_from_theme))
menu_contribution.menu.add_change_listener(
lambda qmenu=submenu, rmenu=menu_contribution.menu: self._rmenu_update(qmenu, rmenu))

View File

@@ -1,3 +1,6 @@
from PySide6.QtCore import QObject
class PluginBase():
def __init__(self):
pass

View File

@@ -26,7 +26,7 @@ class NotesPlugin(PluginBase):
]
def _add_notes_tab_action(self) -> RAction:
open_file = RAction("Add &Notes", self._add_notes_tab, shortcut='Ctrl+Shift+N',
open_file = RAction(self.tr("Add &Notes"), self._add_notes_tab, shortcut='Ctrl+Shift+N',
icon_from_theme="filenew")
return open_file

View File

@@ -1,6 +1,8 @@
import os
from typing import Callable
from pathlib import Path
from PySide6.QtCore import QObject
from PySide6.QtWidgets import QFileDialog
from raven.pluginbase import PluginBase
@@ -24,12 +26,12 @@ class OpenFilePlugin(PluginBase):
self.tr = tr
def _action_open_file(self) -> RAction:
open_file = RAction("&Open...", self._open_file_dialog, shortcut='Ctrl+O',
open_file = RAction(self.tr("&Open..."), self._open_file_dialog, shortcut='Ctrl+O',
icon_from_theme="document-open")
return open_file
def _sub_menu_recent_files(self) -> RMenu:
self._menu_recent_files = RMenu("Open &Recent", icon_from_theme="document-open-recent")
self._menu_recent_files = RMenu(self.tr("Open &Recent"), icon_from_theme="document-open-recent")
self._update_recent_files_menu()
return self._menu_recent_files

View File

@@ -1,5 +1,5 @@
import sys
from typing import Optional
from typing import Optional, Callable
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QDockWidget
@@ -16,8 +16,12 @@ from raven.plugins.ravenlog.Tab import Tab
class RavenLogPlugin(PluginBase):
def __init__(self):
super(RavenLogPlugin, self).__init__()
self.tr = None
self.main_window = None
def set_translator(self, tr: Callable[[str], str]):
self.tr = tr
def create_main_window(self):
if not self.main_window:
self.main_window = MainWindow()
@@ -42,7 +46,7 @@ class RavenLogPlugin(PluginBase):
def _action_about(self) -> RAction:
about_action = RAction(
"&About",
self.tr("&About"),
action=lambda: AboutDialog().exec(),
icon_file=constants.raven_icon
)
@@ -50,6 +54,6 @@ class RavenLogPlugin(PluginBase):
def _action_close(self) -> RAction:
icon = "close" if sys.platform == 'win32' or sys.platform == 'cygwin' else "exit"
close_action = RAction("E&xit", action=lambda: self.main_window.destruct(), shortcut='Ctrl+X',
close_action = RAction(self.tr("E&xit"), action=lambda: self.main_window.destruct(), shortcut='Ctrl+X',
icon_from_theme=icon)
return close_action

7
translate.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
echo "extract text from source files"
pyside6-lupdate *.py raven/*.py raven/plugins/*.py -recursive -ts messages_de.ts
echo "write translation to qm file"
pyside6-lrelease messages_de.ts -qm translations/messages_de.qm

BIN
translations/messages_de.qm Normal file

Binary file not shown.