203 lines
7.0 KiB
Python
203 lines
7.0 KiB
Python
#!/usr/bin/env python3
|
|
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction, QMenuBar, QMessageBox, QFileDialog, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QTableWidget, QTableWidgetItem, QHeaderView, QPushButton, QTabWidget, QFormLayout
|
|
from PyQt5.QtCore import Qt
|
|
import sys
|
|
import os
|
|
import polib
|
|
|
|
class LangToolWindow(QMainWindow):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.setWindowTitle("Dusk Language Editor")
|
|
self.setGeometry(100, 100, 800, 600)
|
|
self.current_file = None
|
|
self.dirty = False
|
|
self.init_menu()
|
|
self.init_ui()
|
|
|
|
def init_ui(self):
|
|
central = QWidget()
|
|
layout = QVBoxLayout(central)
|
|
|
|
tabs = QTabWidget()
|
|
# Header Tab
|
|
header_tab = QWidget()
|
|
header_layout = QFormLayout(header_tab)
|
|
self.language_edit = QLineEdit()
|
|
self.language_edit.setMaximumWidth(220)
|
|
header_layout.addRow(QLabel("Language:"), self.language_edit)
|
|
self.plural_edit = QLineEdit()
|
|
self.plural_edit.setMaximumWidth(320)
|
|
header_layout.addRow(QLabel("Plural-Forms:"), self.plural_edit)
|
|
self.content_type_edit = QLineEdit("text/plain; charset=UTF-8")
|
|
self.content_type_edit.setMaximumWidth(320)
|
|
header_layout.addRow(QLabel("Content-Type:"), self.content_type_edit)
|
|
tabs.addTab(header_tab, "Header")
|
|
|
|
# Strings Tab
|
|
strings_tab = QWidget()
|
|
strings_layout = QVBoxLayout(strings_tab)
|
|
self.po_table = QTableWidget()
|
|
self.po_table.setColumnCount(2)
|
|
self.po_table.setHorizontalHeaderLabels(["msgid", "msgstr"])
|
|
self.po_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
|
self.po_table.verticalHeader().setMinimumWidth(22)
|
|
self.po_table.verticalHeader().setDefaultAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
|
strings_layout.addWidget(self.po_table)
|
|
row_btn_layout = QHBoxLayout()
|
|
add_row_btn = QPushButton("Add Row")
|
|
remove_row_btn = QPushButton("Remove Row")
|
|
row_btn_layout.addWidget(add_row_btn)
|
|
row_btn_layout.addWidget(remove_row_btn)
|
|
strings_layout.addLayout(row_btn_layout)
|
|
tabs.addTab(strings_tab, "Strings")
|
|
|
|
layout.addWidget(tabs)
|
|
|
|
add_row_btn.clicked.connect(self.add_row)
|
|
remove_row_btn.clicked.connect(self.remove_row)
|
|
self.add_row_btn = add_row_btn
|
|
self.remove_row_btn = remove_row_btn
|
|
|
|
self.setCentralWidget(central)
|
|
|
|
# Connect edits to dirty flag
|
|
self.language_edit.textChanged.connect(self.set_dirty)
|
|
self.plural_edit.textChanged.connect(self.set_dirty)
|
|
self.content_type_edit.textChanged.connect(self.set_dirty)
|
|
self.po_table.itemChanged.connect(self.set_dirty)
|
|
|
|
def set_dirty(self):
|
|
self.dirty = True
|
|
self.update_save_action()
|
|
|
|
def init_menu(self):
|
|
menubar = self.menuBar()
|
|
file_menu = menubar.addMenu("File")
|
|
|
|
new_action = QAction("New", self)
|
|
open_action = QAction("Open", self)
|
|
save_action = QAction("Save", self)
|
|
save_as_action = QAction("Save As", self)
|
|
|
|
new_action.triggered.connect(lambda: self.handle_file_action("new"))
|
|
open_action.triggered.connect(lambda: self.handle_file_action("open"))
|
|
save_action.triggered.connect(self.handle_save)
|
|
save_as_action.triggered.connect(self.handle_save_as)
|
|
|
|
file_menu.addAction(new_action)
|
|
file_menu.addAction(open_action)
|
|
file_menu.addAction(save_action)
|
|
file_menu.addAction(save_as_action)
|
|
|
|
self.save_action = save_action # Store reference for enabling/disabling
|
|
self.update_save_action()
|
|
|
|
def update_save_action(self):
|
|
self.save_action.setEnabled(self.current_file is not None)
|
|
|
|
def handle_file_action(self, action):
|
|
if self.dirty:
|
|
reply = QMessageBox.question(self, "Save Changes?", "Do you want to save changes before proceeding?", QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
|
|
if reply == QMessageBox.Cancel:
|
|
return
|
|
elif reply == QMessageBox.Yes:
|
|
self.handle_save()
|
|
if action == "new":
|
|
self.new_file()
|
|
elif action == "open":
|
|
default_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../assets/locale"))
|
|
file_path, _ = QFileDialog.getOpenFileName(self, "Open Language File", default_dir, "PO Files (*.po)")
|
|
if file_path:
|
|
self.open_file(file_path)
|
|
|
|
def new_file(self):
|
|
self.current_file = None
|
|
self.dirty = False
|
|
self.language_edit.setText("")
|
|
self.plural_edit.setText("")
|
|
self.po_table.setRowCount(0)
|
|
self.update_save_action()
|
|
|
|
def open_file(self, file_path):
|
|
self.current_file = file_path
|
|
self.dirty = False
|
|
self.update_save_action()
|
|
self.load_po_file(file_path)
|
|
|
|
def load_po_file(self, file_path):
|
|
po = polib.pofile(file_path)
|
|
language = po.metadata.get('Language', '')
|
|
plural = po.metadata.get('Plural-Forms', '')
|
|
content_type = po.metadata.get('Content-Type', 'text/plain; charset=UTF-8')
|
|
self.language_edit.setText(language)
|
|
self.plural_edit.setText(plural)
|
|
self.content_type_edit.setText(content_type)
|
|
self.po_table.setRowCount(len(po))
|
|
for row, entry in enumerate(po):
|
|
self.po_table.setItem(row, 0, QTableWidgetItem(entry.msgid))
|
|
self.po_table.setItem(row, 1, QTableWidgetItem(entry.msgstr))
|
|
|
|
def save_file(self, file_path):
|
|
po = polib.POFile()
|
|
po.metadata = {
|
|
'Language': self.language_edit.text(),
|
|
'Content-Type': self.content_type_edit.text(),
|
|
'Plural-Forms': self.plural_edit.text(),
|
|
}
|
|
for row in range(self.po_table.rowCount()):
|
|
msgid_item = self.po_table.item(row, 0)
|
|
msgstr_item = self.po_table.item(row, 1)
|
|
msgid = msgid_item.text() if msgid_item else ''
|
|
msgstr = msgstr_item.text() if msgstr_item else ''
|
|
if msgid or msgstr:
|
|
entry = polib.POEntry(msgid=msgid, msgstr=msgstr)
|
|
po.append(entry)
|
|
po.save(file_path)
|
|
self.dirty = False
|
|
self.update_save_action()
|
|
|
|
def handle_save(self):
|
|
if self.current_file:
|
|
self.save_file(self.current_file)
|
|
else:
|
|
self.handle_save_as()
|
|
|
|
def handle_save_as(self):
|
|
default_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../assets/locale"))
|
|
file_path, _ = QFileDialog.getSaveFileName(self, "Save Language File As", default_dir, "PO Files (*.po)")
|
|
if file_path:
|
|
self.current_file = file_path
|
|
self.update_save_action()
|
|
self.save_file(file_path)
|
|
|
|
def add_row(self):
|
|
row = self.po_table.rowCount()
|
|
self.po_table.insertRow(row)
|
|
self.po_table.setItem(row, 0, QTableWidgetItem(""))
|
|
self.po_table.setItem(row, 1, QTableWidgetItem(""))
|
|
self.po_table.setCurrentCell(row, 0)
|
|
self.set_dirty()
|
|
|
|
def remove_row(self):
|
|
row = self.po_table.currentRow()
|
|
if row >= 0:
|
|
self.po_table.removeRow(row)
|
|
self.set_dirty()
|
|
|
|
def closeEvent(self, event):
|
|
if self.dirty:
|
|
reply = QMessageBox.question(self, "Save Changes?", "Do you want to save changes before exiting?", QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
|
|
if reply == QMessageBox.Cancel:
|
|
event.ignore()
|
|
return
|
|
elif reply == QMessageBox.Yes:
|
|
self.handle_save()
|
|
event.accept()
|
|
|
|
if __name__ == "__main__":
|
|
app = QApplication(sys.argv)
|
|
window = LangToolWindow()
|
|
window.show()
|
|
sys.exit(app.exec_())
|