Skip to content

Commit

Permalink
Add translation support. (#31)
Browse files Browse the repository at this point in the history
* Add initial translation.

Signed-off-by: Slendi <[email protected]>

* Use glob to get UI files instead of manually going though each one.

Signed-off-by: Slendi <[email protected]>

* Replace self.translator.translate => self.tr

Signed-off-by: Slendi <[email protected]>

---------

Signed-off-by: Slendi <[email protected]>
  • Loading branch information
xslendix authored Aug 19, 2023
1 parent fd1d5b0 commit 62d372e
Show file tree
Hide file tree
Showing 5 changed files with 457 additions and 11 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ nexus.egg-info/
.coverage
**/__pycache__/
src/nexus/ui/*.py
src/nexus/translations/
12 changes: 12 additions & 0 deletions dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import os
import sys
import argparse
import glob
from pathlib import Path

# Error and exit on Python version < 3.11
if sys.version_info < (3, 11):
Expand Down Expand Up @@ -51,6 +53,16 @@
os.system(f"{venv_path}pyside6-uic ui/banword.ui -o src/nexus/ui/BanwordDialog.py")
os.system(f"{venv_path}pyside6-uic ui/confirm.ui -o src/nexus/ui/ConfirmDialog.py")

print("Generating TS template...")
os.system(f"{venv_path}pyside6-lupdate " +
' '.join(glob.glob('ui/*.ui') + ["src/nexus/GUI.py"]) +
" -ts translations/i18n_en.ts")

print("Generating QM files...")
os.makedirs('src/nexus/translations', exist_ok=True)
for i in glob.glob('translations/*.ts'):
os.system(f"{venv_path}pyside6-lrelease {i} -qm src/nexus/translations/{Path(i).stem}.qm")

if not (args.no_build or args.ui_only):
# Pyinstaller command
build_cmd = "pyinstaller -Fn nexus src/nexus/__main__.py"
Expand Down
44 changes: 33 additions & 11 deletions src/nexus/GUI.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import argparse
from threading import Thread
from pathlib import Path

from PySide6.QtCore import Qt
from PySide6.QtCore import Qt, QTranslator, QLocale
from PySide6.QtWidgets import QApplication, QPushButton, QStatusBar, QTableWidget, QTableWidgetItem, QMainWindow, \
QDialog, QFileDialog

Expand Down Expand Up @@ -46,12 +47,29 @@ def __init__(self, *args, **kwargs):
self.setupUi(self)


class Translator(QTranslator):
"""Custom translator"""

def translate(self, context: str, source: str, disambiguation=None, n=-1):
final = super().translate(context, source, disambiguation, n)
if final:
return final
return source


class GUI(object):
"""Nexus GUI"""

def __init__(self, args: argparse.Namespace):
"""Initialize GUI"""
self.app = QApplication([])

self.translator = Translator(self.app)

if self.translator.load(QLocale.system(), 'i18n', '_', str(Path(__file__).resolve().parent)+'/translations'):
self.app.installTranslator(self.translator)
self.tr = self.translator.translate

self.window = MainWindow()

# Components
Expand Down Expand Up @@ -84,12 +102,12 @@ def stop_logging(self):

def start_stop(self):
"""Controller for start/stop logging button"""
if self.start_stop_button.text() == "Start logging":
if self.start_stop_button.text() == self.tr("GUI", "Start logging"):
# Update button to starting
# TODO: fix signal blocking (not currently working)
self.start_stop_button.blockSignals(True)
self.start_stop_button.setEnabled(False)
self.start_stop_button.setText("Starting...")
self.start_stop_button.setText(self.tr("GUI", "Starting..."))
self.start_stop_button.setStyleSheet("background-color: yellow")
self.window.repaint()

Expand All @@ -100,11 +118,11 @@ def start_stop(self):
# Update button to stop
while not (self.freqlog and self.freqlog.is_logging):
pass
self.start_stop_button.setText("Stop logging")
self.start_stop_button.setText(self.tr("GUI", "Stop logging"))
self.start_stop_button.setStyleSheet("background-color: red")
self.start_stop_button.setEnabled(True)
self.start_stop_button.blockSignals(False)
self.statusbar.showMessage("Logging started")
self.statusbar.showMessage(self.tr("GUI", "Logging started"))
self.window.repaint()
else:
# Update button to stopping
Expand All @@ -119,11 +137,11 @@ def start_stop(self):

# Update button to start
self.logging_thread.join()
self.start_stop_button.setText("Start logging")
self.start_stop_button.setText(self.tr("GUI", "Start logging"))
self.start_stop_button.setStyleSheet("background-color: green")
self.start_stop_button.setEnabled(True)
self.start_stop_button.blockSignals(False)
self.statusbar.showMessage("Logging stopped")
self.statusbar.showMessage(self.tr("GUI", "Logging stopped"))
self.window.repaint()

def refresh(self):
Expand Down Expand Up @@ -156,7 +174,7 @@ def refresh(self):
self.chentry_table.setRowCount(len(words))
self.chentry_table.resizeColumnsToContents()
self.chentry_table.setSortingEnabled(True)
self.statusbar.showMessage(f"Loaded {len(words)} freqlogged words")
self.statusbar.showMessage(self.tr("GUI", "Loaded {} freqlogged words").format(len(words)))

def show_banlist(self):
"""Controller for banlist button"""
Expand Down Expand Up @@ -217,8 +235,11 @@ def remove_banword():
] = (CaseSensitivity.SENSITIVE if bl_dialog.banlistTable.item(row.row(), 2).text() == "Sensitive"
else CaseSensitivity.INSENSITIVE)
conf_dialog = ConfirmDialog()
conf_dialog.confirmText.setText(
f"Unban {len(selected_words)} word{'s' if len(selected_words) > 1 else ''}?")
if len(selected_words) > 1:
confirmText = self.tr("GUI", "Unban {} words")
else:
confirmText = self.tr("GUI", "Unban one word")
conf_dialog.confirmText.setText(confirmText.format(len(selected_words)))
conf_dialog.buttonBox.accepted.connect(lambda: self.temp_freqlog.unban_words(selected_words))
conf_dialog.exec()
refresh_banlist()
Expand All @@ -234,7 +255,8 @@ def export(self):
if not filename.endswith(".csv"):
filename += ".csv"
num_exported = self.temp_freqlog.export_words_to_csv(filename)
self.statusbar.showMessage(f"Exported {num_exported} words to {filename}")
self.statusbar.showMessage(
self.tr("GUI", "Exported {} words to {}".format(num_exported, filename)))

def exec(self):
"""Start the GUI"""
Expand Down
210 changes: 210 additions & 0 deletions translations/i18n_en.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en_US">
<context>
<name>BanlistDialog</name>
<message>
<location filename="../ui/banlist.ui" line="14"/>
<source>Banlist</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/banlist.ui" line="39"/>
<source>Word</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/banlist.ui" line="44"/>
<source>Date added</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/banlist.ui" line="49"/>
<source>Case</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/banlist.ui" line="62"/>
<source>Add</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/banlist.ui" line="69"/>
<source>Remove</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>BanwordDialog</name>
<message>
<location filename="../ui/banword.ui" line="17"/>
<source>Ban word</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/banword.ui" line="25"/>
<source>Word to ban:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/banword.ui" line="39"/>
<source>Case:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/banword.ui" line="46"/>
<source>Insensitive</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/banword.ui" line="56"/>
<source>Sensitive</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/banword.ui" line="63"/>
<source>First char</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ConfirmDialog</name>
<message>
<location filename="../ui/confirm.ui" line="14"/>
<source>Ban word</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/confirm.ui" line="20"/>
<source>Are you sure?</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>GUI</name>
<message>
<location filename="../src/nexus/GUI.py" line="108"/>
<location filename="../src/nexus/GUI.py" line="140"/>
<source>GUI</source>
<comment>Start logging</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/nexus/GUI.py" line="110"/>
<source>GUI</source>
<comment>Starting...</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/nexus/GUI.py" line="121"/>
<source>GUI</source>
<comment>Stop logging</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/nexus/GUI.py" line="125"/>
<source>GUI</source>
<comment>Logging started</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/nexus/GUI.py" line="144"/>
<source>GUI</source>
<comment>Logging stopped</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/nexus/GUI.py" line="177"/>
<source>GUI</source>
<comment>Loaded {} freqlogged words</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/nexus/GUI.py" line="240"/>
<source>GUI</source>
<comment>Unban {} words</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/nexus/GUI.py" line="242"/>
<source>GUI</source>
<comment>Unban one word</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/nexus/GUI.py" line="259"/>
<source>GUI</source>
<comment>Exported {} words to {}</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../ui/main.ui" line="14"/>
<source>Nexus</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/main.ui" line="32"/>
<source>Start logging</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/main.ui" line="39"/>
<source>Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/main.ui" line="46"/>
<source>Banlist</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/main.ui" line="53"/>
<source>Export</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/main.ui" line="67"/>
<source>Chorded Entry</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/main.ui" line="110"/>
<source>Chord</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/main.ui" line="115"/>
<source>Frequency</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/main.ui" line="120"/>
<location filename="../ui/main.ui" line="184"/>
<source>Last used</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/main.ui" line="131"/>
<source>Character Entry</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/main.ui" line="174"/>
<source>Word</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/main.ui" line="179"/>
<source>Freq.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/main.ui" line="189"/>
<source>Avg speed</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>
Loading

0 comments on commit 62d372e

Please sign in to comment.