i18n with gettext

This commit is contained in:
2022-02-02 19:35:57 +01:00
parent 939c86dbe2
commit 9c28a41904
21 changed files with 686 additions and 437 deletions

View File

@@ -8,24 +8,24 @@ from PySide6.QtWidgets import *
import constants
from label import Label
from vbox import VBox
from raven.i18n import _
class AboutDialog(QDialog):
"""Dialog for showing info about RavenLog"""
def __init__(self, parent=None):
super(AboutDialog, self).__init__(parent)
self.setWindowTitle(self.tr("About RavenLog"))
self.setWindowTitle(_("About RavenLog"))
self.setModal(True)
self.layout = QVBoxLayout(self)
heading_app_name = QLabel(self.tr("RavenLog"))
heading_app_name = QLabel(_("RavenLog"))
heading_app_name.setAlignment(Qt.AlignmentFlag.AlignLeft)
heading_app_name.setFont(QFont("default", 25))
heading_app_name.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
version = QLabel(self.tr("Version: {0}".format(self._version())))
version = QLabel(_("Version: {0}".format(self._version())))
version.setAlignment(Qt.AlignmentFlag.AlignLeft)
app_icon = QLabel()
@@ -40,8 +40,8 @@ class AboutDialog(QDialog):
self.layout.addWidget(heading)
tabs = QTabWidget()
tabs.addTab(self._about(), self.tr("About"))
tabs.addTab(self._license(), self.tr("License"))
tabs.addTab(self._about(), _("About"))
tabs.addTab(self._license(), _("License"))
self.layout.addWidget(tabs)
@@ -53,7 +53,7 @@ class AboutDialog(QDialog):
def _about(self) -> QWidget:
result = QWidget()
result.layout = QVBoxLayout(result)
label = Label(self.tr(textwrap.dedent("""
label = Label(_(textwrap.dedent("""
Log file viewer<br>
(c) 2022 Open Text Corporation<br>
<a href="https://www.opentext.com/">License: LGPL v3</a>""")))
@@ -68,7 +68,7 @@ class AboutDialog(QDialog):
<li>urllib3 (MIT) - <a href="https://urllib3.readthedocs.io/en/stable/">https://urllib3.readthedocs.io/en/stable/</a></li>
<li>watchdog 2.16 (Apache 2.0) - <a href="https://github.com/gorakhargosh/watchdog">https://github.com/gorakhargosh/watchdog</a></li>
</ul>""".format(pyside=PySide6.__version__, qt=PySide6.QtCore.__version__)
label = self.tr(textwrap.dedent(dependencies))
label = _(textwrap.dedent(dependencies))
result = QWidget()
result.layout = QVBoxLayout(result)

View File

@@ -25,7 +25,7 @@ from ravenui import RavenUI
from settings import Settings
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from raven.i18n import _
class FileObserver(FileSystemEventHandler):
@@ -168,24 +168,24 @@ class InnerBigText(QWidget):
def _open_menu(self, position):
menu = QMenu(self)
copy_clipboard = QAction(QIcon.fromTheme("edit-copy"), self.tr("&Copy to Clipboard"), self,
copy_clipboard = QAction(QIcon.fromTheme("edit-copy"), _("&Copy to Clipboard"), self,
triggered=self.copy_selection)
copy_clipboard.setShortcut("CTRL+C")
copy_clipboard.setDisabled(not self._has_selection())
menu.addAction(copy_clipboard)
copy_to_file = QAction(QIcon.fromTheme("document-save-as"), self.tr("Copy to &File"), self,
copy_to_file = QAction(QIcon.fromTheme("document-save-as"), _("Copy to &File"), self,
triggered=self._copy_selection_to_file)
copy_to_file.setDisabled(not self._has_selection())
menu.addAction(copy_to_file)
select_all = QAction(QIcon.fromTheme("edit-select-all"), self.tr("Select &All"), self,
select_all = QAction(QIcon.fromTheme("edit-select-all"), _("Select &All"), self,
triggered=self._select_all)
select_all.setShortcut("CTRL+A")
menu.addAction(select_all)
manage_highlighting = QAction(
self.tr("&Highlighter"),
_("&Highlighter"),
self,
triggered=lambda: HighlightingDialog(self.model.settings).exec())
manage_highlighting.setShortcut("CTRL+H")
@@ -329,13 +329,13 @@ class InnerBigText(QWidget):
if end - start > (1024 ** 2) * 5:
you_sure = QMessageBox(
QMessageBox.Icon.Warning,
self.tr("data selection"),
self.tr(
_("data selection"),
_(
"You have selected <b>{0}</b> of data.").format(bytes_human_readable))
you_sure.setStandardButtons(QMessageBox.StandardButton.Cancel)
you_sure.addButton(QPushButton(self.tr("Copy {0} to Clipboard").format(bytes_human_readable)),
you_sure.addButton(QPushButton(_("Copy {0} to Clipboard").format(bytes_human_readable)),
QMessageBox.ButtonRole.AcceptRole)
you_sure.addButton(QPushButton(self.tr("Write to File")), QMessageBox.ActionRole)
you_sure.addButton(QPushButton(_("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
@@ -355,7 +355,7 @@ class InnerBigText(QWidget):
end = max(self.selection_highlight.start_byte, self.selection_highlight.end_byte)
dialog = QFileDialog(self)
(selected_file, _filter) = dialog.getSaveFileName(
caption=self.tr("Save File"),
caption=_("Save File"),
dir=os.path.dirname(self.model.get_file())
)
if selected_file:

View File

@@ -2,7 +2,7 @@ import re
from PySide6.QtGui import QColor, QPixmap, QIcon
from PySide6.QtWidgets import QWidget, QHBoxLayout, QPushButton, QColorDialog, QSizePolicy, QComboBox
from raven.i18n import _
class ColorButton(QWidget):
def __init__(self, color: str, parent=None):
@@ -15,40 +15,40 @@ class ColorButton(QWidget):
colors = {
# red
self.tr('Strawberry Cream'): 'ff8080',
self.tr('Pale Crimson'): 'e61919',
_('Strawberry Cream'): 'ff8080',
_('Pale Crimson'): 'e61919',
# orange
self.tr('Broken Buttercup'): 'ffd080',
self.tr('Passion Fruit Sugar'): 'ffa200',
_('Broken Buttercup'): 'ffd080',
_('Passion Fruit Sugar'): 'ffa200',
# yellow
self.tr('Sunrise Yellow'): 'fff080',
self.tr('Magical Mustard'): 'ccb400',
_('Sunrise Yellow'): 'fff080',
_('Magical Mustard'): 'ccb400',
# green
self.tr('Trendy Green'): 'aaff80',
self.tr('Garden Of Sweden'): '44cc00',
_('Trendy Green'): 'aaff80',
_('Garden Of Sweden'): '44cc00',
# blue
self.tr('Light Sky Blue'): '80c6ff',
self.tr('True Blue'): '0073d1',
_('Light Sky Blue'): '80c6ff',
_('True Blue'): '0073d1',
# purple
self.tr('Fairy Topia'): 'ff80f4',
self.tr('Magenta Bachiego'): 'cc00bb',
_('Fairy Topia'): 'ff80f4',
_('Magenta Bachiego'): 'cc00bb',
# grey
self.tr('Breeze of Mist'): 'eaeaea',
self.tr('Light Grey'): 'cccccc',
self.tr('Grey'): '999999',
_('Breeze of Mist'): 'eaeaea',
_('Light Grey'): 'cccccc',
_('Grey'): '999999',
}
self.color_drop_down = QComboBox()
self.layout.addWidget(self.color_drop_down)
self.color_drop_down.currentIndexChanged.connect(self._color_selected)
self.color_drop_down.addItem(QIcon(self._color_pixmap("ffffffff")), self.tr("transparent"), "None")
self.color_drop_down.addItem(QIcon(self._color_pixmap("ffffffff")), _("transparent"), "None")
for color_name in colors.keys():
color_value = colors[color_name]
self.color_drop_down.addItem(QIcon(self._color_pixmap(color_value)), color_name, color_value)
if color == color_name or color == color_value:
self.color_drop_down.setCurrentIndex(self.color_drop_down.count() - 1)
self.btn_color_picker = QPushButton(QIcon.fromTheme("color-picker"), self.tr("custom"))
self.btn_color_picker = QPushButton(QIcon.fromTheme("color-picker"), _("custom"))
self.layout.addWidget(self.btn_color_picker)
self.btn_color_picker.pressed.connect(self._update_color)
self.btn_color_picker.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))

View File

@@ -1,6 +1,5 @@
import unittest
def humanbytes(bytes: int) -> str:
"""non-localized conversion of bytes to human readable strings"""
powers = {0: 'bytes', 1: 'KB', 2: 'MB', 3: 'GB', 4: 'TB', 5: 'PB', 6: 'EB'}

View File

@@ -11,6 +11,7 @@ from bigtext import BigText
from logFileModel import LogFileModel
from ravenui import RavenUI
from raven.i18n import _
class FilterTask(QRunnable):
aborted = False
@@ -96,15 +97,15 @@ class FilterWidget(QWidget):
self.query_field = QLineEdit()
self.query_field.textChanged.connect(self.filter_changed)
self.btn_cancel_search = QPushButton(self.tr("Cancel"))
self.btn_cancel_search = QPushButton(_("Cancel"))
self.btn_cancel_search.setVisible(False)
self.btn_cancel_search.pressed.connect(self._cancel_search)
self.ignore_case = QCheckBox(self.tr("ignore case"))
self.ignore_case = QCheckBox(_("ignore case"))
self.ignore_case.setChecked(True)
self.ignore_case.stateChanged.connect(self.filter_changed)
self.is_regex = QCheckBox(self.tr("regex"))
self.is_regex = QCheckBox(_("regex"))
self.is_regex.setChecked(True)
self.is_regex.stateChanged.connect(self.filter_changed)

View File

@@ -8,6 +8,7 @@ from highlight_regex import HighlightRegex
from highlighting import Highlighting
from settings import Settings
from raven.i18n import _
class PayloadItem(QListWidgetItem):
def __init__(self, text: str, payload=None):
@@ -18,7 +19,7 @@ class PayloadItem(QListWidgetItem):
class HighlightingDialog(QDialog):
def __init__(self, settings: Settings):
super(HighlightingDialog, self).__init__()
self.setWindowTitle(self.tr("Manage Highlighting"))
self.setWindowTitle(_("Manage Highlighting"))
self.setModal(True)
self._settings = settings
@@ -30,23 +31,23 @@ class HighlightingDialog(QDialog):
form_grid.addWidget(self.list, row, 0, 1, 2)
row = row + 1
self.btn_add = QPushButton(QIcon.fromTheme("list-add"), self.tr("Add"))
self.btn_add = QPushButton(QIcon.fromTheme("list-add"), _("Add"))
self.btn_add.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
self.btn_add.pressed.connect(self._add)
self.btn_update = QPushButton(QIcon.fromTheme("stock_edit"), self.tr("Update"))
self.btn_update = QPushButton(QIcon.fromTheme("stock_edit"), _("Update"))
self.btn_update.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
self.btn_update.pressed.connect(self._update)
self.btn_delete = QPushButton(QIcon.fromTheme("list-remove"), self.tr("Remove"))
self.btn_delete = QPushButton(QIcon.fromTheme("list-remove"), _("Remove"))
self.btn_delete.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
self.btn_delete.pressed.connect(self._delete)
self.btn_move_up = QPushButton(QIcon.fromTheme("go-up"), self.tr("Up"))
self.btn_move_up = QPushButton(QIcon.fromTheme("go-up"), _("Up"))
self.btn_move_up.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
self.btn_move_up.pressed.connect(self._move_up)
self.btn_move_down = QPushButton(QIcon.fromTheme("go-down"), self.tr("Down"))
self.btn_move_down = QPushButton(QIcon.fromTheme("go-down"), _("Down"))
self.btn_move_down.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
self.btn_move_down.pressed.connect(self._move_down)
button_box = HBox(self.btn_update, self.btn_add, self.btn_delete, self.btn_move_up, self.btn_move_down)
@@ -54,26 +55,26 @@ class HighlightingDialog(QDialog):
row = row + 1
self.query = QLineEdit(self)
form_grid.addWidget(QLabel(self.tr("Query:")), row, 0)
form_grid.addWidget(QLabel(_("Query:")), row, 0)
form_grid.addWidget(self.query, row, 1)
row = row + 1
self.ignore_case = QCheckBox(self.tr("Ignore Case"))
self.ignore_case = QCheckBox(_("Ignore Case"))
self.ignore_case.setChecked(True)
form_grid.addWidget(self.ignore_case, row, 0, 1, 2)
row = row + 1
self.is_regex = QCheckBox(self.tr("Regular Expression"))
self.is_regex = QCheckBox(_("Regular Expression"))
self.is_regex.setChecked(True)
form_grid.addWidget(self.is_regex, row, 0, 1, 2)
row = row + 1
form_grid.addWidget(QLabel(self.tr("Hit Background:")), row, 0)
form_grid.addWidget(QLabel(_("Hit Background:")), row, 0)
self.hit_background_color = ColorButton("ccb400")
form_grid.addWidget(self.hit_background_color, row, 1)
row = row + 1
form_grid.addWidget(QLabel(self.tr("Line Background:")), row, 0)
form_grid.addWidget(QLabel(_("Line Background:")), row, 0)
self.line_background_color = ColorButton("fff080")
form_grid.addWidget(self.line_background_color, row, 1)
@@ -137,10 +138,10 @@ class HighlightingDialog(QDialog):
def _save(self):
if self._is_dirty():
unsaved = QMessageBox(QMessageBox.Icon.Question, self.tr("unsaved changes"),
self.tr("You have unsaved changes. Continue?"))
unsaved = QMessageBox(QMessageBox.Icon.Question, _("unsaved changes"),
_("You have unsaved changes. Continue?"))
unsaved.setStandardButtons(QMessageBox.StandardButton.Cancel)
unsaved.addButton(QPushButton(self.tr("Continue")), QMessageBox.ButtonRole.AcceptRole)
unsaved.addButton(QPushButton(_("Continue")), QMessageBox.ButtonRole.AcceptRole)
result = unsaved.exec()
if result == QMessageBox.StandardButton.Cancel:
return

Binary file not shown.

View File

@@ -0,0 +1,279 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: RavenLog\n"
"POT-Creation-Date: 2022-02-01 20:07+0100\n"
"PO-Revision-Date: 2022-02-01 20:17+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"X-Generator: Poedit 2.3\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: aboutdialog.py:19
msgid "About RavenLog"
msgstr "Über RavenLog"
#: aboutdialog.py:24 raven/mainwindow.py:44 ravenui.py:20
msgid "RavenLog"
msgstr "RavenLog"
#: aboutdialog.py:44
msgid "About"
msgstr "Über RavenLog"
#: aboutdialog.py:45
msgid "License"
msgstr "Lizenz"
#: bigtext.py:172
msgid "&Copy to Clipboard"
msgstr "In Zwischenablage &Kopieren"
#: bigtext.py:178
msgid "Copy to &File"
msgstr "In &Datei Kopieren"
#: bigtext.py:183
msgid "Select &All"
msgstr "&Alles Selektieren"
#: bigtext.py:189 raven/mainwindow.py:121
msgid "&Highlighter"
msgstr "&Hervorhebungen"
#: bigtext.py:333
msgid "data selection"
msgstr "selektion"
#: bigtext.py:334
msgid "You have selected <b>{0}</b> of data."
msgstr "Du hast <b>{0}</b> selektiert."
#: bigtext.py:337
msgid "Copy {0} to Clipboard"
msgstr "Kopiere {0} in die Zwischenablage"
#: bigtext.py:339
msgid "Write to File"
msgstr "Schreibe in Datei"
#: bigtext.py:359
msgid "Save File"
msgstr "Speichere Datei"
#: colorbutton.py:19
msgid "Strawberry Cream"
msgstr "Strawberry Cream"
#: colorbutton.py:20
msgid "Pale Crimson"
msgstr "Pale Crimson"
#: colorbutton.py:22
msgid "Broken Buttercup"
msgstr "Pale Crimson"
#: colorbutton.py:23
msgid "Passion Fruit Sugar"
msgstr "Passion Fruit Sugar"
#: colorbutton.py:25
msgid "Sunrise Yellow"
msgstr ""
#: colorbutton.py:26
msgid "Magical Mustard"
msgstr ""
#: colorbutton.py:28
msgid "Trendy Green"
msgstr ""
#: colorbutton.py:29
msgid "Garden Of Sweden"
msgstr ""
#: colorbutton.py:31
msgid "Light Sky Blue"
msgstr ""
#: colorbutton.py:32
msgid "True Blue"
msgstr ""
#: colorbutton.py:34
msgid "Fairy Topia"
msgstr ""
#: colorbutton.py:35
msgid "Magenta Bachiego"
msgstr ""
#: colorbutton.py:37
msgid "Breeze of Mist"
msgstr ""
#: colorbutton.py:38
msgid "Light Grey"
msgstr "Helles Grau"
#: colorbutton.py:39
msgid "Grey"
msgstr "Grau"
#: colorbutton.py:45
msgid "transparent"
msgstr "Transparent"
#: colorbutton.py:52
msgid "custom"
msgstr "individuell"
#: filterwidget.py:101
msgid "Cancel"
msgstr "Abbrechen"
#: filterwidget.py:105
msgid "ignore case"
msgstr "Groß-/Kleinschreibung ignorieren"
#: filterwidget.py:109
msgid "regex"
msgstr "RegExp"
#: highlightingdialog.py:23
msgid "Manage Highlighting"
msgstr "Hervorhebungen Verwalten"
#: highlightingdialog.py:35
msgid "Add"
msgstr "Hinzufügen"
#: highlightingdialog.py:39
msgid "Update"
msgstr "Aktualisieren"
#: highlightingdialog.py:43
msgid "Remove"
msgstr "Entfernen"
#: highlightingdialog.py:47
msgid "Up"
msgstr "Hoch"
#: highlightingdialog.py:51
msgid "Down"
msgstr "Runter"
#: highlightingdialog.py:59
msgid "Query:"
msgstr "Suche:"
#: highlightingdialog.py:63
msgid "Ignore Case"
msgstr "Groß-/Kleinschreibung ignorieren"
#: highlightingdialog.py:68
msgid "Regular Expression"
msgstr "Regulärer Ausdruck"
#: highlightingdialog.py:73
msgid "Hit Background:"
msgstr "Trefferhintergrund:"
#: highlightingdialog.py:78
msgid "Line Background:"
msgstr "Zeilenhintergrund:"
#: highlightingdialog.py:142
msgid "unsaved changes"
msgstr "nicht gespeicherte Änderungen"
#: highlightingdialog.py:143
msgid "You have unsaved changes. Continue?"
msgstr "Du hast nicht gespeicherte Änderungen. Weiter?"
#: highlightingdialog.py:145
msgid "Continue"
msgstr "Weiter"
#: raven/mainwindow.py:52 raven/plugins/openfileplugin.py:31
msgid "Open &Recent"
msgstr "Zu&letzt geöffnete Dateien"
#: raven/mainwindow.py:71
#: venv310/lib/python3.10/site-packages/PySide6/examples/widgets/gettext/main.py:57
msgid "&File"
msgstr "&Datei"
#: raven/mainwindow.py:72
msgid "&Settings"
msgstr "&Einstellungen"
#: raven/mainwindow.py:73
msgid "&Window"
msgstr "&Fenster"
#: raven/mainwindow.py:74
msgid "&Help"
msgstr "&Hilfe"
#: raven/mainwindow.py:129
msgid "Highlight &Searches"
msgstr "&Suchtreffer Hervorheben"
#: raven/mainwindow.py:138
msgid "Open Tab on Save As File"
msgstr "Öffne neues Tab wenn Selektion als neue Datei gespeichert wird"
#: raven/plugins/logfileplugin.py:26
msgid "File not found"
msgstr "Datei nicht gefunden"
#: raven/plugins/logfileplugin.py:27
msgid "'{0}' is not a file or cannot be opened"
msgstr "'{0}' ist keine Datei oder kann nicht geöffnet werden"
#: raven/plugins/notesplugin.py:26
msgid "Add &Notes"
msgstr "&Notizen Hinzufügen"
#: raven/plugins/notesplugin.py:34
msgid "Notes {0}"
msgstr "Notizen {0}"
#: raven/plugins/openfileplugin.py:26
msgid "&Open..."
msgstr "&Öffnen..."
#: raven/plugins/openfileplugin.py:47
msgid "Open File"
msgstr "Öffne Datei"
#: raven/plugins/ravenlogplugin.py:46
msgid "&About"
msgstr "&Über RavenLog"
#: raven/plugins/ravenlogplugin.py:54
msgid "E&xit"
msgstr "&Beenden"
#: ravenui.py:18
msgid "{0} - RavenLog"
msgstr "{0} - RavenLog"
#: venv310/lib/python3.10/site-packages/PySide6/examples/widgets/gettext/main.py:58
msgid "Quit"
msgstr "Beenden"
#: venv310/lib/python3.10/site-packages/PySide6/examples/widgets/gettext/main.py:59
msgid "CTRL+Q"
msgstr "STRG+Q"

280
locales/messages.pot Normal file
View File

@@ -0,0 +1,280 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2022-02-01 20:07+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
#: ./aboutdialog.py:19
msgid "About RavenLog"
msgstr ""
#: ./aboutdialog.py:24 ./raven/mainwindow.py:44 ./ravenui.py:20
msgid "RavenLog"
msgstr ""
#: ./aboutdialog.py:44
msgid "About"
msgstr ""
#: ./aboutdialog.py:45
msgid "License"
msgstr ""
#: ./bigtext.py:172
msgid "&Copy to Clipboard"
msgstr ""
#: ./bigtext.py:178
msgid "Copy to &File"
msgstr ""
#: ./bigtext.py:183
msgid "Select &All"
msgstr ""
#: ./bigtext.py:189 ./raven/mainwindow.py:121
msgid "&Highlighter"
msgstr ""
#: ./bigtext.py:333
msgid "data selection"
msgstr ""
#: ./bigtext.py:334
msgid "You have selected <b>{0}</b> of data."
msgstr ""
#: ./bigtext.py:337
msgid "Copy {0} to Clipboard"
msgstr ""
#: ./bigtext.py:339
msgid "Write to File"
msgstr ""
#: ./bigtext.py:359
msgid "Save File"
msgstr ""
#: ./colorbutton.py:19
msgid "Strawberry Cream"
msgstr ""
#: ./colorbutton.py:20
msgid "Pale Crimson"
msgstr ""
#: ./colorbutton.py:22
msgid "Broken Buttercup"
msgstr ""
#: ./colorbutton.py:23
msgid "Passion Fruit Sugar"
msgstr ""
#: ./colorbutton.py:25
msgid "Sunrise Yellow"
msgstr ""
#: ./colorbutton.py:26
msgid "Magical Mustard"
msgstr ""
#: ./colorbutton.py:28
msgid "Trendy Green"
msgstr ""
#: ./colorbutton.py:29
msgid "Garden Of Sweden"
msgstr ""
#: ./colorbutton.py:31
msgid "Light Sky Blue"
msgstr ""
#: ./colorbutton.py:32
msgid "True Blue"
msgstr ""
#: ./colorbutton.py:34
msgid "Fairy Topia"
msgstr ""
#: ./colorbutton.py:35
msgid "Magenta Bachiego"
msgstr ""
#: ./colorbutton.py:37
msgid "Breeze of Mist"
msgstr ""
#: ./colorbutton.py:38
msgid "Light Grey"
msgstr ""
#: ./colorbutton.py:39
msgid "Grey"
msgstr ""
#: ./colorbutton.py:45
msgid "transparent"
msgstr ""
#: ./colorbutton.py:52
msgid "custom"
msgstr ""
#: ./filterwidget.py:101
msgid "Cancel"
msgstr ""
#: ./filterwidget.py:105
msgid "ignore case"
msgstr ""
#: ./filterwidget.py:109
msgid "regex"
msgstr ""
#: ./highlightingdialog.py:23
msgid "Manage Highlighting"
msgstr ""
#: ./highlightingdialog.py:35
msgid "Add"
msgstr ""
#: ./highlightingdialog.py:39
msgid "Update"
msgstr ""
#: ./highlightingdialog.py:43
msgid "Remove"
msgstr ""
#: ./highlightingdialog.py:47
msgid "Up"
msgstr ""
#: ./highlightingdialog.py:51
msgid "Down"
msgstr ""
#: ./highlightingdialog.py:59
msgid "Query:"
msgstr ""
#: ./highlightingdialog.py:63
msgid "Ignore Case"
msgstr ""
#: ./highlightingdialog.py:68
msgid "Regular Expression"
msgstr ""
#: ./highlightingdialog.py:73
msgid "Hit Background:"
msgstr ""
#: ./highlightingdialog.py:78
msgid "Line Background:"
msgstr ""
#: ./highlightingdialog.py:142
msgid "unsaved changes"
msgstr ""
#: ./highlightingdialog.py:143
msgid "You have unsaved changes. Continue?"
msgstr ""
#: ./highlightingdialog.py:145
msgid "Continue"
msgstr ""
#: ./raven/mainwindow.py:52 ./raven/plugins/openfileplugin.py:31
msgid "Open &Recent"
msgstr ""
#: ./raven/mainwindow.py:71
#: ./venv310/lib/python3.10/site-packages/PySide6/examples/widgets/gettext/main.py:57
msgid "&File"
msgstr ""
#: ./raven/mainwindow.py:72
msgid "&Settings"
msgstr ""
#: ./raven/mainwindow.py:73
msgid "&Window"
msgstr ""
#: ./raven/mainwindow.py:74
msgid "&Help"
msgstr ""
#: ./raven/mainwindow.py:129
msgid "Highlight &Searches"
msgstr ""
#: ./raven/mainwindow.py:138
msgid "Open Tab on Save As File"
msgstr ""
#: ./raven/plugins/logfileplugin.py:26
msgid "File not found"
msgstr ""
#: ./raven/plugins/logfileplugin.py:27
msgid "'{0}' is not a file or cannot be opened"
msgstr ""
#: ./raven/plugins/notesplugin.py:26
msgid "Add &Notes"
msgstr ""
#: ./raven/plugins/notesplugin.py:34
msgid "Notes {0}"
msgstr ""
#: ./raven/plugins/openfileplugin.py:26
msgid "&Open..."
msgstr ""
#: ./raven/plugins/openfileplugin.py:47
msgid "Open File"
msgstr ""
#: ./raven/plugins/ravenlogplugin.py:46
msgid "&About"
msgstr ""
#: ./raven/plugins/ravenlogplugin.py:54
msgid "E&xit"
msgstr ""
#: ./ravenui.py:18
msgid "{0} - RavenLog"
msgstr ""
#:
#: ./venv310/lib/python3.10/site-packages/PySide6/examples/widgets/gettext/main.py:58
msgid "Quit"
msgstr ""
#:
#: ./venv310/lib/python3.10/site-packages/PySide6/examples/widgets/gettext/main.py:59
msgid "CTRL+Q"
msgstr ""

31
main.py
View File

@@ -2,6 +2,7 @@ import logging
import os
import signal
import ctypes
from pathlib import Path
from PySide6 import QtCore
from PySide6.QtWidgets import QApplication
@@ -13,9 +14,14 @@ import constants
from raven.pluginregistry import PluginRegistry
from ravenui import RavenUI
import gettext
gettext.install('ravenlog', 'locale')
logging.basicConfig(level=logging.INFO)
log = logging.getLogger("main")
def stop_signal(signum, _stackframe):
""" Handle terminate signal """
try:
@@ -37,20 +43,21 @@ if __name__ == "__main__":
myappid = 'opentext.ravenlog' # arbitrary string
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
# translator = QTranslator()
# 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)
src_dir = Path(__file__).resolve().parent
try:
translation = gettext.translation('messages', localedir=src_dir / 'locales', languages=[locale])
if translation:
translation.install()
_ = translation.gettext
ngettext = translation.ngettext
except FileNotFoundError:
pass
if not _:
_ = gettext.gettext
ngettext = gettext.ngettext
print('No translation found')
# workaround to make signals work in QT apps.
# They do not work out of the box, because the main thread

View File

@@ -1,326 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de_DE">
<context>
<name>AboutDialog</name>
<message>
<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="aboutdialog.py" line="28"/>
<source>Version: {0}</source>
<translation>Version: {0}</translation>
</message>
<message>
<location filename="aboutdialog.py" line="43"/>
<source>About</source>
<translation>Über RavenLog</translation>
</message>
<message>
<location filename="aboutdialog.py" line="44"/>
<source>License</source>
<translation>Lizenz</translation>
</message>
</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>

20
raven/i18n.py Normal file
View File

@@ -0,0 +1,20 @@
import gettext
import os
from pathlib import Path
locale = os.environ['LANG'] if os.environ['LANG'] else "en"
_ = False
src_dir = Path(__file__).resolve().parent.parent
try:
translation = gettext.translation('messages', localedir=src_dir / 'locales', languages=[locale])
if translation:
translation.install()
_ = translation.gettext
ngettext = translation.ngettext
except FileNotFoundError:
pass
if not _:
_ = gettext.gettext
ngettext = gettext.ngettext
print('No translation found')

View File

@@ -18,6 +18,8 @@ from tabs import Tabs
from urlutils import url_is_file
from functools import reduce
from raven.i18n import _
MAX_LINE_LENGTH = 4096
logging.basicConfig(level=logging.INFO)
@@ -35,9 +37,7 @@ class MainWindow(QMainWindow):
self.settings = SettingsStore.load()
PluginRegistry.execute("set_settings", self.settings)
self.setWindowTitle(self.tr("RavenLog"))
self.setWindowTitle(_("RavenLog"))
self._restore_window()
self.setDockNestingEnabled(True)
@@ -45,7 +45,7 @@ class MainWindow(QMainWindow):
self.tabs = Tabs(self.settings)
self._menu_recent_files = QMenu(self.tr("Open &Recent"), self)
self._menu_recent_files = QMenu(_("Open &Recent"), self)
self.setCentralWidget(self.tabs)
self.status_bar = QStatusBar(self)
self.setStatusBar(self.status_bar)
@@ -64,10 +64,10 @@ class MainWindow(QMainWindow):
menu_contributions = sort_menu_contributions(menu_contributions)
known_menus = [
("file", self.tr("&File")),
("settings", self.tr("&Settings")),
("window", self.tr("&Window")),
("help", self.tr("&Help"))
("file", _("&File")),
("settings", _("&Settings")),
("window", _("&Window")),
("help", _("&Help"))
]
for (menu_id, menu_label) in known_menus:
@@ -98,7 +98,7 @@ class MainWindow(QMainWindow):
qmenu.addAction(action)
def _raction_to_qaction(self, raction: RAction, qmenu: QMenu) -> QAction:
action = QAction(self.tr(raction.label), qmenu)
action = QAction(_(raction.label), qmenu)
if raction.icon_from_theme:
action.setIcon(QIcon.fromTheme(raction.icon_from_theme))
if raction.icon_file:
@@ -114,7 +114,7 @@ class MainWindow(QMainWindow):
def _action_highlighter(self):
manage = RAction(
"&Highlighter",
_("&Highlighter"),
action=lambda: HighlightingDialog(self.settings).exec(),
shortcut='Ctrl+H'
)
@@ -122,7 +122,7 @@ class MainWindow(QMainWindow):
def _action_highlight_search_terms(self):
highlight_search_terms = RAction(
"Highlight &Searches",
_("Highlight &Searches"),
action=lambda checked: self.settings.set_session("general", "highlight_search_term",
str(checked)) or self.update()
)
@@ -131,7 +131,7 @@ class MainWindow(QMainWindow):
return highlight_search_terms
def _action_new_tab(self):
new_tab = RAction("Open Tab on Save As File")
new_tab = RAction(_("Open Tab on Save As File"))
new_tab.set_checkable(True)
new_tab.set_checked(self.settings.session.getboolean("general", "open_tab_on_save_as_file"))
new_tab.set_action(

View File

@@ -61,7 +61,7 @@ class PluginRegistry():
if len(sig.parameters) != len(args):
raise RuntimeError("method %s.%s has wrong number of arguments. expected %s but was %s " % (
plugin, function_name, len(args), len(sig.parameters)))
print("calling %s with args %s" % (fun, args))
# print("calling %s with args %s" % (fun, args))
if len(args) == 0:
return_value = fun()
elif len(args) == 1:

View File

@@ -9,23 +9,20 @@ from raven.pluginbase import PluginBase
from raven.plugins.ravenlog.Tab import Tab
from settings import Settings
from raven.i18n import _
class LogFilePlugin(PluginBase):
def __init__(self):
super(LogFilePlugin, self).__init__()
self.settings = None
self.tr = None
def set_settings(self, settings: Settings):
self.settings = settings
def set_translator(self, tr: Callable[[str], str]):
self.tr = tr
def create_tab(self, file: str) -> Optional[Tab]:
if not os.path.isfile(file):
message = QMessageBox(QMessageBox.Icon.Warning, "File not found",
"'%s' is not a file or cannot be opened" % file)
message = QMessageBox(QMessageBox.Icon.Warning, _("File not found"),
_("'{0}' is not a file or cannot be opened").format(file))
message.exec()
return None

View File

@@ -7,26 +7,22 @@ from raven.pluginregistry import PluginRegistry
from raven.plugins.domain.menucontribution import MenuContribution
from raven.plugins.domain.raction import RAction
from raven.plugins.notes.noteswidget import NotesWidget
from raven.i18n import _
class NotesPlugin(PluginBase):
def __init__(self):
super(NotesPlugin, self).__init__()
self.settings = None
self.tr = None
self.tab_counter = 0
def set_translator(self, tr: Callable[[str], str]):
self.tr = tr
def get_menu_contributions(self) -> [MenuContribution]:
return [
MenuContribution("window", action=self._add_notes_tab_action(), action_id="add notes tab", after="<last>"),
]
def _add_notes_tab_action(self) -> RAction:
open_file = RAction(self.tr("Add &Notes"), self._add_notes_tab, shortcut='Ctrl+Shift+N',
open_file = RAction(_("Add &Notes"), self._add_notes_tab, shortcut='Ctrl+Shift+N',
icon_from_theme="filenew")
return open_file
@@ -34,5 +30,5 @@ class NotesPlugin(PluginBase):
self.tab_counter = self.tab_counter + 1
notes = NotesWidget(
"notes_tab_%d" % self.tab_counter,
self.tr("Notes %d") % self.tab_counter)
_("Notes {0}").format(self.tab_counter))
PluginRegistry.execute_single("add_dock", Qt.DockWidgetArea.RightDockWidgetArea, notes)

View File

@@ -12,26 +12,23 @@ from raven.plugins.domain.raction import RAction
from raven.plugins.domain.rmenu import RMenu
from settings import Settings
from raven.i18n import _
class OpenFilePlugin(PluginBase):
def __init__(self):
super(OpenFilePlugin, self).__init__()
self.settings = None
self.tr = None
def set_settings(self, settings: Settings):
self.settings = settings
def set_translator(self, tr: Callable[[str], str]):
self.tr = tr
def _action_open_file(self) -> RAction:
open_file = RAction(self.tr("&Open..."), self._open_file_dialog, shortcut='Ctrl+O',
open_file = RAction(_("&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(self.tr("Open &Recent"), icon_from_theme="document-open-recent")
self._menu_recent_files = RMenu(_("Open &Recent"), icon_from_theme="document-open-recent")
self._update_recent_files_menu()
return self._menu_recent_files
@@ -47,7 +44,7 @@ class OpenFilePlugin(PluginBase):
dialog = QFileDialog()
(selected_file, _filter) = dialog.getOpenFileName(
caption=self.tr("Open File"),
caption=_("Open File"),
dir=directory
)
# directory=directory

View File

@@ -11,17 +11,13 @@ from raven.pluginbase import PluginBase
from raven.plugins.domain.menucontribution import MenuContribution
from raven.plugins.domain.raction import RAction
from raven.plugins.ravenlog.Tab import Tab
from raven.i18n import _
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()
@@ -46,7 +42,7 @@ class RavenLogPlugin(PluginBase):
def _action_about(self) -> RAction:
about_action = RAction(
self.tr("&About"),
_("&About"),
action=lambda: AboutDialog().exec(),
icon_file=constants.raven_icon
)
@@ -54,6 +50,6 @@ class RavenLogPlugin(PluginBase):
def _action_close(self) -> RAction:
icon = "close" if sys.platform == 'win32' or sys.platform == 'cygwin' else "exit"
close_action = RAction(self.tr("E&xit"), action=lambda: self.main_window.destruct(), shortcut='Ctrl+X',
close_action = RAction(_("E&xit"), action=lambda: self.main_window.destruct(), shortcut='Ctrl+X',
icon_from_theme=icon)
return close_action

View File

@@ -1,3 +1,6 @@
from raven.i18n import _
class RavenUI():
# no type hint because of circular dependencies
window = None
@@ -11,9 +14,9 @@ class RavenUI():
if not RavenUI.window:
return
if len(title) > 0:
RavenUI.window.setWindowTitle("%s - RavenLog" % title)
RavenUI.window.setWindowTitle(_("{0} - RavenLog").format(title))
else:
RavenUI.window.setWindowTitle("RavenLog")
RavenUI.window.setWindowTitle(_("RavenLog"))
@staticmethod
def update_status_bar(text: str):

View File

@@ -1,7 +1,6 @@
#!/bin/bash
echo "extract text from source files"
pyside6-lupdate *.py raven/*.py raven/plugins/*.py -recursive -ts messages_de.ts
find . -iname "*.py" | xargs /home/andi/bin/Python-3.10.0/Tools/i18n/pygettext.py -o locales/messages.pot
echo "write translation to qm file"
pyside6-lrelease messages_de.ts -qm translations/messages_de.qm
echo "edit with poedit"

Binary file not shown.