mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 22:42:25 -04:00
convert po string extraction to GUI app
This commit is contained in:
parent
440aa129d9
commit
97bf4da6e8
4 changed files with 433 additions and 167 deletions
|
@ -1,167 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: UTF-8 -*-
|
|
||||||
import os
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import polib
|
|
||||||
import shutil
|
|
||||||
from fluent.syntax import parse, serialize
|
|
||||||
from fluent.syntax.ast import Message, TextElement, Identifier, Pattern, Junk
|
|
||||||
|
|
||||||
# extract a translated string from strings.json and insert it into ftl
|
|
||||||
# eg:
|
|
||||||
# $ python extract-po-string.py strings.json /path/to/templates/media-check.ftl delete-unused "Delete Unused Media" ""
|
|
||||||
# $ python extract-po-string.py strings.json /path/to/templates/media-check.ftl delete-unused "%(a)s %(b)s" "%(a)s=$val1,%(b)s=$val2"
|
|
||||||
|
|
||||||
json_filename, ftl_filename, key, msgid_substring, repls = sys.argv[1:]
|
|
||||||
|
|
||||||
# split up replacements
|
|
||||||
replacements = []
|
|
||||||
for repl in repls.split(","):
|
|
||||||
if not repl:
|
|
||||||
continue
|
|
||||||
replacements.append(repl.split("="))
|
|
||||||
|
|
||||||
# add file as prefix to key
|
|
||||||
prefix = os.path.splitext(os.path.basename(ftl_filename))[0]
|
|
||||||
key = f"{prefix}-{key}"
|
|
||||||
|
|
||||||
strings = json.load(open(json_filename, "r"))
|
|
||||||
|
|
||||||
msgids = []
|
|
||||||
if msgid_substring in strings["en"]:
|
|
||||||
# is the ID an exact match?
|
|
||||||
msgids.append(msgid_substring)
|
|
||||||
else:
|
|
||||||
for id in strings["en"].keys():
|
|
||||||
if msgid_substring in id:
|
|
||||||
msgids.append(id)
|
|
||||||
|
|
||||||
msgid = None
|
|
||||||
if len(msgids) == 0:
|
|
||||||
print("no IDs matched")
|
|
||||||
sys.exit(1)
|
|
||||||
elif len(msgids) == 1:
|
|
||||||
msgid = msgids[0]
|
|
||||||
else:
|
|
||||||
for c, id in enumerate(msgids):
|
|
||||||
print(f"* {c}: {id}")
|
|
||||||
msgid = msgids[int(input("number to use? "))]
|
|
||||||
|
|
||||||
|
|
||||||
def transform_entry(entry):
|
|
||||||
if isinstance(entry, str):
|
|
||||||
return transform_string(entry)
|
|
||||||
else:
|
|
||||||
return [transform_string(e) for e in entry]
|
|
||||||
|
|
||||||
|
|
||||||
def transform_string(msg):
|
|
||||||
for (old, new) in replacements:
|
|
||||||
msg = msg.replace(old, f"{new}")
|
|
||||||
# strip leading/trailing whitespace
|
|
||||||
return msg.strip()
|
|
||||||
|
|
||||||
|
|
||||||
to_insert = []
|
|
||||||
for lang in strings.keys():
|
|
||||||
entry = strings[lang].get(msgid)
|
|
||||||
if not entry:
|
|
||||||
continue
|
|
||||||
entry = transform_entry(entry)
|
|
||||||
if entry:
|
|
||||||
print(f"{lang} had translation {entry}")
|
|
||||||
to_insert.append((lang, entry))
|
|
||||||
|
|
||||||
plurals = json.load(open("plurals.json"))
|
|
||||||
|
|
||||||
|
|
||||||
def plural_text(key, lang, translation):
|
|
||||||
lang = re.sub("(_|-).*", "", lang)
|
|
||||||
|
|
||||||
# extract the variable - if there's more than one, use the first one
|
|
||||||
var = re.findall(r"{(\$.*?)}", translation[0])
|
|
||||||
if not len(var) == 1:
|
|
||||||
print("multiple variables found, using first replacement")
|
|
||||||
var = replacements[0][1].replace("{", "").replace("}", "")
|
|
||||||
else:
|
|
||||||
var = var[0]
|
|
||||||
|
|
||||||
buf = f"{key} = {{ {var} ->\n"
|
|
||||||
|
|
||||||
# for each of the plural forms except the last
|
|
||||||
for idx, msg in enumerate(translation[:-1]):
|
|
||||||
plural_form = plurals[lang][idx]
|
|
||||||
buf += f" [{plural_form}] {msg}\n"
|
|
||||||
|
|
||||||
# add the catchall
|
|
||||||
msg = translation[-1]
|
|
||||||
buf += f" *[other] {msg}\n"
|
|
||||||
buf += " }\n"
|
|
||||||
return buf
|
|
||||||
|
|
||||||
|
|
||||||
# add a non-pluralized message. works via fluent.syntax, so can automatically
|
|
||||||
# indent, etc
|
|
||||||
def add_simple_message(fname, key, message):
|
|
||||||
orig = ""
|
|
||||||
if os.path.exists(fname):
|
|
||||||
with open(fname) as file:
|
|
||||||
orig = file.read()
|
|
||||||
|
|
||||||
obj = parse(orig)
|
|
||||||
for ent in obj.body:
|
|
||||||
if isinstance(ent, Junk):
|
|
||||||
raise Exception(f"file had junk! {fname} {ent}")
|
|
||||||
obj.body.append(Message(Identifier(key), Pattern([TextElement(message)])))
|
|
||||||
|
|
||||||
modified = serialize(obj, with_junk=True)
|
|
||||||
# escape leading dots
|
|
||||||
modified = re.sub(r"(?ms)^( +)\.", '\\1{"."}', modified)
|
|
||||||
|
|
||||||
# ensure the resulting serialized file is valid by parsing again
|
|
||||||
obj = parse(modified)
|
|
||||||
for ent in obj.body:
|
|
||||||
if isinstance(ent, Junk):
|
|
||||||
raise Exception(f"introduced junk! {fname} {ent}")
|
|
||||||
|
|
||||||
# it's ok, write it out
|
|
||||||
with open(fname, "w") as file:
|
|
||||||
file.write(modified)
|
|
||||||
|
|
||||||
|
|
||||||
def add_message(fname, key, translation):
|
|
||||||
# simple, non-plural form?
|
|
||||||
if isinstance(translation, str):
|
|
||||||
add_simple_message(fname, key, translation)
|
|
||||||
else:
|
|
||||||
text = plural_text(key, lang, translation)
|
|
||||||
open(fname, "a").write(text)
|
|
||||||
|
|
||||||
print()
|
|
||||||
input("proceed? ctrl+c to abort")
|
|
||||||
|
|
||||||
i18ndir = os.path.join(os.path.dirname(ftl_filename), "..")
|
|
||||||
|
|
||||||
# for each language's translation
|
|
||||||
for lang, translation in to_insert:
|
|
||||||
if lang == "en":
|
|
||||||
# template
|
|
||||||
ftl_path = ftl_filename
|
|
||||||
else:
|
|
||||||
# translation
|
|
||||||
ftl_path = ftl_filename.replace("templates", lang)
|
|
||||||
ftl_dir = os.path.dirname(ftl_path)
|
|
||||||
|
|
||||||
if not os.path.exists(ftl_dir):
|
|
||||||
os.mkdir(ftl_dir)
|
|
||||||
|
|
||||||
add_message(ftl_path, key, translation)
|
|
||||||
|
|
||||||
# copy file from repo into src
|
|
||||||
srcdir = os.path.join(i18ndir, "..", "..")
|
|
||||||
src_filename = os.path.join(srcdir, os.path.basename(ftl_filename))
|
|
||||||
shutil.copy(ftl_filename, src_filename)
|
|
||||||
|
|
||||||
print("done")
|
|
238
qt/po/scripts/extract_po_string.py
Normal file
238
qt/po/scripts/extract_po_string.py
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: UTF-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import polib
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
from extract_po_string_diag import Ui_Dialog
|
||||||
|
from fluent.syntax import parse, serialize
|
||||||
|
from fluent.syntax.ast import Message, TextElement, Identifier, Pattern, Junk
|
||||||
|
|
||||||
|
# the templates folder inside the ftl repo
|
||||||
|
repo_templates_dir = sys.argv[1]
|
||||||
|
assert os.path.abspath(repo_templates_dir).endswith("templates")
|
||||||
|
strings = json.load(open("strings.json"))
|
||||||
|
plurals = json.load(open("plurals.json"))
|
||||||
|
# i18ndir = os.path.join(ftl_dir, "..")
|
||||||
|
|
||||||
|
|
||||||
|
def transform_entry(entry, replacements):
|
||||||
|
if isinstance(entry, str):
|
||||||
|
return transform_string(entry, replacements)
|
||||||
|
else:
|
||||||
|
return [transform_string(e, replacements) for e in entry]
|
||||||
|
|
||||||
|
|
||||||
|
def transform_string(msg, replacements):
|
||||||
|
try:
|
||||||
|
for (old, new) in replacements:
|
||||||
|
msg = msg.replace(old, f"{new}")
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
# strip leading/trailing whitespace
|
||||||
|
return msg.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def plural_text(key, lang, translation):
|
||||||
|
lang = re.sub("(_|-).*", "", lang)
|
||||||
|
|
||||||
|
# extract the variable - if there's more than one, use the first one
|
||||||
|
var = re.findall(r"{(\$.*?)}", translation[0])
|
||||||
|
if not len(var) == 1:
|
||||||
|
print("multiple variables found, using first replacement")
|
||||||
|
var = replacements[0][1].replace("{", "").replace("}", "")
|
||||||
|
else:
|
||||||
|
var = var[0]
|
||||||
|
|
||||||
|
buf = f"{key} = {{ {var} ->\n"
|
||||||
|
|
||||||
|
# for each of the plural forms except the last
|
||||||
|
for idx, msg in enumerate(translation[:-1]):
|
||||||
|
plural_form = plurals[lang][idx]
|
||||||
|
buf += f" [{plural_form}] {msg}\n"
|
||||||
|
|
||||||
|
# add the catchall
|
||||||
|
msg = translation[-1]
|
||||||
|
buf += f" *[other] {msg}\n"
|
||||||
|
buf += " }\n"
|
||||||
|
return buf
|
||||||
|
|
||||||
|
|
||||||
|
def key_from_search(search):
|
||||||
|
return search.replace(" ", "-").replace("'", "")
|
||||||
|
|
||||||
|
|
||||||
|
# add a non-pluralized message. works via fluent.syntax, so can automatically
|
||||||
|
# indent, etc
|
||||||
|
def add_simple_message(fname, key, message):
|
||||||
|
orig = ""
|
||||||
|
if os.path.exists(fname):
|
||||||
|
with open(fname) as file:
|
||||||
|
orig = file.read()
|
||||||
|
|
||||||
|
obj = parse(orig)
|
||||||
|
for ent in obj.body:
|
||||||
|
if isinstance(ent, Junk):
|
||||||
|
raise Exception(f"file had junk! {fname} {ent}")
|
||||||
|
obj.body.append(Message(Identifier(key), Pattern([TextElement(message)])))
|
||||||
|
|
||||||
|
modified = serialize(obj, with_junk=True)
|
||||||
|
# escape leading dots
|
||||||
|
modified = re.sub(r"(?ms)^( +)\.", '\\1{"."}', modified)
|
||||||
|
|
||||||
|
# ensure the resulting serialized file is valid by parsing again
|
||||||
|
obj = parse(modified)
|
||||||
|
for ent in obj.body:
|
||||||
|
if isinstance(ent, Junk):
|
||||||
|
raise Exception(f"introduced junk! {fname} {ent}")
|
||||||
|
|
||||||
|
# it's ok, write it out
|
||||||
|
with open(fname, "w") as file:
|
||||||
|
file.write(modified)
|
||||||
|
|
||||||
|
|
||||||
|
def add_message(fname, key, translation):
|
||||||
|
# simple, non-plural form?
|
||||||
|
if isinstance(translation, str):
|
||||||
|
add_simple_message(fname, key, translation)
|
||||||
|
else:
|
||||||
|
text = plural_text(key, lang, translation)
|
||||||
|
open(fname, "a").write(text)
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QDialog, Ui_Dialog):
|
||||||
|
def __init__(self):
|
||||||
|
QDialog.__init__(self)
|
||||||
|
self.setupUi(self)
|
||||||
|
|
||||||
|
self.matched_strings = []
|
||||||
|
|
||||||
|
self.files = sorted(os.listdir(repo_templates_dir))
|
||||||
|
self.filenames.addItems(self.files)
|
||||||
|
|
||||||
|
self.search.textChanged.connect(self.on_search)
|
||||||
|
self.replacements.textChanged.connect(self.update_preview)
|
||||||
|
self.key.textEdited.connect(self.update_preview)
|
||||||
|
self.filenames.currentIndexChanged.connect(self.update_preview)
|
||||||
|
self.searchMatches.currentItemChanged.connect(self.update_preview)
|
||||||
|
self.replacementsTemplateButton.clicked.connect(self.on_template)
|
||||||
|
self.addButton.clicked.connect(self.on_add)
|
||||||
|
|
||||||
|
def on_template(self):
|
||||||
|
self.replacements.setText("%d={ $value }")
|
||||||
|
# qt macos bug
|
||||||
|
self.replacements.repaint()
|
||||||
|
|
||||||
|
def on_search(self):
|
||||||
|
msgid_substring = self.search.text()
|
||||||
|
self.key.setText(key_from_search(msgid_substring))
|
||||||
|
|
||||||
|
msgids = []
|
||||||
|
exact_idx = None
|
||||||
|
for n, id in enumerate(strings["en"].keys()):
|
||||||
|
if msgid_substring.lower() in id.lower():
|
||||||
|
msgids.append(id)
|
||||||
|
|
||||||
|
# is the ID an exact match?
|
||||||
|
if msgid_substring in strings["en"]:
|
||||||
|
exact_idx = n
|
||||||
|
|
||||||
|
self.matched_strings = msgids
|
||||||
|
self.searchMatches.clear()
|
||||||
|
self.searchMatches.addItems(self.matched_strings)
|
||||||
|
if exact_idx is not None:
|
||||||
|
self.searchMatches.setCurrentRow(exact_idx)
|
||||||
|
elif self.matched_strings:
|
||||||
|
self.searchMatches.setCurrentRow(0)
|
||||||
|
|
||||||
|
self.update_preview()
|
||||||
|
|
||||||
|
def update_preview(self):
|
||||||
|
self.preview.clear()
|
||||||
|
if not self.matched_strings:
|
||||||
|
return
|
||||||
|
|
||||||
|
strings = self.get_adjusted_strings()
|
||||||
|
key = self.get_key()
|
||||||
|
self.preview.setPlainText(
|
||||||
|
f"Key: {key}\n\n"
|
||||||
|
+ "\n".join([f"{lang}: {value}" for (lang, value) in strings])
|
||||||
|
)
|
||||||
|
|
||||||
|
# returns list of (lang, entry)
|
||||||
|
def get_adjusted_strings(self):
|
||||||
|
msgid = self.matched_strings[self.searchMatches.currentRow()]
|
||||||
|
|
||||||
|
# split up replacements
|
||||||
|
replacements = []
|
||||||
|
for repl in self.replacements.text().split(","):
|
||||||
|
if not repl:
|
||||||
|
continue
|
||||||
|
replacements.append(repl.split("="))
|
||||||
|
|
||||||
|
to_insert = []
|
||||||
|
for lang in strings.keys():
|
||||||
|
entry = strings[lang].get(msgid)
|
||||||
|
if not entry:
|
||||||
|
continue
|
||||||
|
entry = transform_entry(entry, replacements)
|
||||||
|
if entry:
|
||||||
|
to_insert.append((lang, entry))
|
||||||
|
|
||||||
|
return to_insert
|
||||||
|
|
||||||
|
def get_key(self):
|
||||||
|
# add file as prefix to key
|
||||||
|
prefix = os.path.splitext(self.filenames.currentText())[0]
|
||||||
|
return f"{prefix}-{self.key.text()}"
|
||||||
|
|
||||||
|
def on_add(self):
|
||||||
|
to_insert = self.get_adjusted_strings()
|
||||||
|
key = self.get_key()
|
||||||
|
# for each language's translation
|
||||||
|
for lang, translation in to_insert:
|
||||||
|
ftl_path = self.filename_for_lang(lang)
|
||||||
|
add_message(ftl_path, key, translation)
|
||||||
|
|
||||||
|
if lang == "en":
|
||||||
|
# copy file from repo into src
|
||||||
|
srcdir = os.path.join(repo_templates_dir, "..", "..", "..")
|
||||||
|
src_filename = os.path.join(srcdir, os.path.basename(ftl_path))
|
||||||
|
shutil.copy(ftl_path, src_filename)
|
||||||
|
|
||||||
|
subprocess.check_call(
|
||||||
|
f"cd {repo_templates_dir} && git add .. && git commit -m 'add {key}'",
|
||||||
|
shell=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.preview.setPlainText(f"Added {key}.")
|
||||||
|
self.preview.repaint()
|
||||||
|
|
||||||
|
def filename_for_lang(self, lang):
|
||||||
|
fname = self.filenames.currentText()
|
||||||
|
if lang == "en":
|
||||||
|
return os.path.join(repo_templates_dir, fname)
|
||||||
|
else:
|
||||||
|
ftl_dir = os.path.join(repo_templates_dir, "..", lang)
|
||||||
|
if not os.path.exists(ftl_dir):
|
||||||
|
os.mkdir(ftl_dir)
|
||||||
|
return os.path.join(ftl_dir, fname)
|
||||||
|
|
||||||
|
|
||||||
|
print("Remember to pull-i18n before making changes.")
|
||||||
|
if subprocess.check_output(f"git status --porcelain {repo_templates_dir}", shell=True):
|
||||||
|
print("Repo has uncommitted changes.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = Window()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec_())
|
86
qt/po/scripts/extract_po_string_diag.py
Normal file
86
qt/po/scripts/extract_po_string_diag.py
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Form implementation generated from reading ui file 'extract_po_string_diag.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt5 UI code generator 5.15.0
|
||||||
|
#
|
||||||
|
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||||
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
|
class Ui_Dialog(object):
|
||||||
|
def setupUi(self, Dialog):
|
||||||
|
Dialog.setObjectName("Dialog")
|
||||||
|
Dialog.resize(879, 721)
|
||||||
|
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
|
||||||
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
|
self.gridLayout = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout.setObjectName("gridLayout")
|
||||||
|
self.label_2 = QtWidgets.QLabel(Dialog)
|
||||||
|
self.label_2.setObjectName("label_2")
|
||||||
|
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1)
|
||||||
|
self.filenames = QtWidgets.QComboBox(Dialog)
|
||||||
|
self.filenames.setObjectName("filenames")
|
||||||
|
self.gridLayout.addWidget(self.filenames, 1, 1, 1, 1)
|
||||||
|
self.label_4 = QtWidgets.QLabel(Dialog)
|
||||||
|
self.label_4.setObjectName("label_4")
|
||||||
|
self.gridLayout.addWidget(self.label_4, 0, 0, 1, 1)
|
||||||
|
self.replacementsTemplateButton = QtWidgets.QPushButton(Dialog)
|
||||||
|
self.replacementsTemplateButton.setObjectName("replacementsTemplateButton")
|
||||||
|
self.gridLayout.addWidget(self.replacementsTemplateButton, 4, 1, 1, 1)
|
||||||
|
self.label = QtWidgets.QLabel(Dialog)
|
||||||
|
self.label.setObjectName("label")
|
||||||
|
self.gridLayout.addWidget(self.label, 1, 0, 1, 1)
|
||||||
|
self.label_3 = QtWidgets.QLabel(Dialog)
|
||||||
|
self.label_3.setObjectName("label_3")
|
||||||
|
self.gridLayout.addWidget(self.label_3, 3, 0, 1, 1)
|
||||||
|
self.replacements = QtWidgets.QLineEdit(Dialog)
|
||||||
|
self.replacements.setObjectName("replacements")
|
||||||
|
self.gridLayout.addWidget(self.replacements, 3, 1, 1, 1)
|
||||||
|
self.key = QtWidgets.QLineEdit(Dialog)
|
||||||
|
self.key.setObjectName("key")
|
||||||
|
self.gridLayout.addWidget(self.key, 2, 1, 1, 1)
|
||||||
|
self.search = QtWidgets.QLineEdit(Dialog)
|
||||||
|
self.search.setObjectName("search")
|
||||||
|
self.gridLayout.addWidget(self.search, 0, 1, 1, 1)
|
||||||
|
self.verticalLayout.addLayout(self.gridLayout)
|
||||||
|
self.label_5 = QtWidgets.QLabel(Dialog)
|
||||||
|
self.label_5.setObjectName("label_5")
|
||||||
|
self.verticalLayout.addWidget(self.label_5)
|
||||||
|
self.searchMatches = QtWidgets.QListWidget(Dialog)
|
||||||
|
self.searchMatches.setObjectName("searchMatches")
|
||||||
|
self.verticalLayout.addWidget(self.searchMatches)
|
||||||
|
self.label_6 = QtWidgets.QLabel(Dialog)
|
||||||
|
self.label_6.setObjectName("label_6")
|
||||||
|
self.verticalLayout.addWidget(self.label_6)
|
||||||
|
self.preview = QtWidgets.QTextEdit(Dialog)
|
||||||
|
self.preview.setObjectName("preview")
|
||||||
|
self.verticalLayout.addWidget(self.preview)
|
||||||
|
self.addButton = QtWidgets.QPushButton(Dialog)
|
||||||
|
self.addButton.setObjectName("addButton")
|
||||||
|
self.verticalLayout.addWidget(self.addButton)
|
||||||
|
|
||||||
|
self.retranslateUi(Dialog)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||||
|
Dialog.setTabOrder(self.search, self.filenames)
|
||||||
|
Dialog.setTabOrder(self.filenames, self.key)
|
||||||
|
Dialog.setTabOrder(self.key, self.replacements)
|
||||||
|
Dialog.setTabOrder(self.replacements, self.replacementsTemplateButton)
|
||||||
|
Dialog.setTabOrder(self.replacementsTemplateButton, self.searchMatches)
|
||||||
|
Dialog.setTabOrder(self.searchMatches, self.preview)
|
||||||
|
Dialog.setTabOrder(self.preview, self.addButton)
|
||||||
|
|
||||||
|
def retranslateUi(self, Dialog):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||||
|
self.label_2.setText(_translate("Dialog", "Fluent key suffix"))
|
||||||
|
self.label_4.setText(_translate("Dialog", "Search:"))
|
||||||
|
self.replacementsTemplateButton.setText(_translate("Dialog", "Template"))
|
||||||
|
self.label.setText(_translate("Dialog", "Target file"))
|
||||||
|
self.label_3.setText(_translate("Dialog", "Replacements"))
|
||||||
|
self.label_5.setText(_translate("Dialog", "Matches"))
|
||||||
|
self.label_6.setText(_translate("Dialog", "Preview"))
|
||||||
|
self.addButton.setText(_translate("Dialog", "Add"))
|
109
qt/po/scripts/extract_po_string_diag.ui
Normal file
109
qt/po/scripts/extract_po_string_diag.ui
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Dialog</class>
|
||||||
|
<widget class="QDialog" name="Dialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>879</width>
|
||||||
|
<height>721</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Fluent key suffix</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QComboBox" name="filenames"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Search:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QPushButton" name="replacementsTemplateButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Template</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Target file</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Replacements</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLineEdit" name="replacements"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="key"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="search"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Matches</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="searchMatches"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>Preview</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="preview"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="addButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>search</tabstop>
|
||||||
|
<tabstop>filenames</tabstop>
|
||||||
|
<tabstop>key</tabstop>
|
||||||
|
<tabstop>replacements</tabstop>
|
||||||
|
<tabstop>replacementsTemplateButton</tabstop>
|
||||||
|
<tabstop>searchMatches</tabstop>
|
||||||
|
<tabstop>preview</tabstop>
|
||||||
|
<tabstop>addButton</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
Loading…
Reference in a new issue