New feature: i18n

初步实现界面控件的国际化翻译功能;
初步完成界面的全英文翻译;
This commit is contained in:
muzing 2024-01-04 20:46:18 +08:00
parent cea7f5ba2a
commit c42fbaecc9
13 changed files with 1300 additions and 185 deletions

View File

@ -11,13 +11,6 @@ Py2exe-GUI 启动方式:
python -m py2exe_gui
"""
import sys
from py2exe_gui.__main__ import main
from PySide6.QtWidgets import QApplication
from py2exe_gui.__main__ import MainApp
app = QApplication(sys.argv)
window = MainApp()
window.show()
sys.exit(app.exec())
main()

View File

@ -6,6 +6,478 @@
from PySide6 import QtCore
qt_resource_data = b"\
\x00\x00\x1d^\
<\
\xb8d\x18\xca\xef\x9c\x95\xcd!\x1c\xbf`\xa1\xbd\xdd\xa7\
\x00\x00\x00\x05zh_CNB\x00\x00\x03\x00\x00\x00\
+;\x00\x00\x01\x82\x00\x00+;\x00\x00\x11\xbd\x00\x02\
\xb4\xc7\x00\x00\x01P\x00\x02\xb4\xc7\x00\x00\x11\x85\x00\x04\
\xa6y\x00\x00\x02&\x00\x05H5\x00\x00\x12w\x00\x05\
f\xbe\x00\x00\x0b\xc1\x00\x05f\xbe\x00\x00\x13\xa8\x00\x10\
\xcan\x00\x00\x04h\x00\x13U\xee\x00\x00\x0a;\x00*\
\xcf\x04\x00\x00\x0eN\x00*\xd0%\x00\x00\x0e~\x00*\
\xec0\x00\x00\x0e\xae\x00G\x96\xc4\x00\x00\x00\x00\x00I\
l\x0e\x00\x00\x03L\x00J+~\x00\x00\x05\x02\x00J\
6\x95\x00\x00\x14\xf0\x00Kdq\x00\x00\x15\x1b\x00L\
\x99b\x00\x00\x05\xa0\x00L\x99b\x00\x00\x17\xc3\x01*\
\xbc^\x00\x00\x04\xb4\x01\x8a\xa33\x00\x00\x11\xf4\x01\xdb\
\xb2\x8f\x00\x00\x07B\x01\xf3(\xfe\x00\x00\x15\xfd\x02$\
\x06\xee\x00\x00\x19E\x02TK\xfa\x00\x00\x03\x98\x02o\
\xeej\x00\x00\x17X\x02r\xf7\xfe\x00\x00\x05,\x02\xa7\
\x96\xc4\x00\x00\x0e\x1d\x02\xa7\xdeU\x00\x00\x0f\x81\x02\xb6\
\xee\xd3\x00\x00\x10\x7f\x03\x8aRY\x00\x00\x0bb\x03\xbc\
\xb9r\x00\x00\x01\xe6\x04\x13\xa2*\x00\x00\x08\x93\x04a\
\xc9p\x00\x00\x18T\x04t\xcbE\x00\x00\x06G\x04\x98\
I\xbc\x00\x00\x0b\x07\x04\x98I\xbc\x00\x00\x13|\x04\x98\
I\xbc\x00\x00\x14\xc4\x04\x99n\x95\x00\x00\x03\xcc\x04\x99\
n\x95\x00\x00\x17\x92\x04\xcfv\x94\x00\x00\x02S\x04\xd1\
N\xb2\x00\x00\x06~\x05g\xb0^\x00\x00\x13\x08\x05\x8b\
{\xbe\x00\x00\x0d\xf5\x06\x04\x81\x85\x00\x00\x0b1\x06L\
\xc5c\x00\x00\x01\xb3\x06\x5c\xc6\xd5\x00\x00\x14\x19\x06m\
\x81M\x00\x00\x0fF\x06\xc6l\x14\x00\x00\x0f\x12\x07$\
\xfe\xde\x00\x00\x0a\xdb\x07?\xfd\xfe\x00\x00\x18\xdf\x07\xca\
r\x11\x00\x00\x09x\x08\x05\x1f\xb0\x00\x00\x06\xfd\x08\xa1\
\x96\xd9\x00\x00\x0cm\x09\x07[\x85\x00\x00\x0f\xd4\x09\x08\
b\x8a\x00\x00\x08X\x09 \x93N\x00\x00\x10+\x09(\
n\x13\x00\x00\x02\xc1\x09<\x5c\x83\x00\x00\x10\xd9\x09M\
g\xfe\x00\x00\x12\xce\x09pU\x99\x00\x00\x14X\x09\xc4\
\xb21\x00\x00\x03\xf7\x09\xd8%U\x00\x00\x0c-\x09\xf2\
5X\x00\x00\x08\x05\x0a\x0f\xec\x8e\x00\x00\x00&\x0a\x1e\
\xda\xd4\x00\x00\x05\xca\x0ae\xa8\xe3\x00\x00\x15L\x0a\x98\
I\x9c\x00\x00\x00\xe6\x0a\x98I\x9c\x00\x00\x11\x0f\x0a\xac\
,\x85\x00\x00\x01\x1b\x0a\xac,\x85\x00\x00\x11J\x0a\xb8\
\xc2\xa1\x00\x00\x08\xe3\x0a\xebf\x09\x00\x00\x0a\x9e\x0a\xeb\
f\x09\x00\x00\x0b\xe9\x0a\xebf\x09\x00\x00\x13=\x0b\x05\
MN\x00\x00\x06\x00\x0b\xab\x22\xae\x00\x00\x02\xfc\x0b\xd4\
\xbf\xa1\x00\x00\x16\xa2\x0b\xddZ\xc5\x00\x00\x00\xa8\x0b\xe1\
gZ\x00\x00\x16\xf4\x0c\x05\x06\xc4\x00\x00\x15\xc6\x0c\x0a\
\xbe\xf5\x00\x00\x04%\x0c\x1b\xd1\xa1\x00\x00\x19\xb1\x0cP\
\xa0*\x00\x00\x06\xb7\x0c~`9\x00\x00\x0d\x87\x0c\xa8\
?b\x00\x00\x0c\xc6\x0c\xba\xefs\x00\x00\x0e\xde\x0c\xc9\
\xa0\x0e\x00\x00\x12\xa1\x0d\x89P\x17\x00\x00\x0a\x0f\x0e\x01\
+e\x00\x00\x18\x9f\x0ef\xfa\x7f\x00\x00\x17\xf3\x0e\x81\
2\x09\x00\x00\x0d\x13\x0f\xc0\xd03\x00\x00\x02\x82\x0f\xcf\
\xb2#\x00\x00\x129\x0f\xe8\x01e\x00\x00\x13\xd2i\x00\
\x00\x1a:\x03\x00\x00\x00\x04QsN\x8e\x08\x00\x00\x00\
\x00\x06\x00\x00\x00\x05About\x07\x00\x00\x00\x08\
AboutDlg\x01\x03\x00\x00\x00(e\xe0\
l\xd5bS_\x00QsN\x8ee\x87hc\xff\x0c\
\x8b\xf7\x5c\x1d\x8b\xd5\x91\xcde\xb0\x83\xb7S\xd6g,\
z\x0b^\x8f0\x02\x08\x00\x00\x00\x00\x06\x00\x00\x00=\
Can't open the A\
bout document, t\
ry to reinstall \
this program.\x07\x00\x00\
\x00\x08AboutDlg\x01\x03\x00\x00\x00\x10\
mO\x89\xc8e\x87N\xf6\x00(\x00&\x00B\x00)\
\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0c&Brows\
e File\x07\x00\x00\x00\x0dAddDa\
taWindow\x01\x03\x00\x00\x00\x0cS\xd6\
m\x88\x00(\x00&\x00C\x00)\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x07&Cancel\x07\x00\x00\x00\x0d\
AddDataWindow\x01\x03\x00\
\x00\x00\x0cR \x96d\x00(\x00&\x00D\x00)\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x07&Delete\
\x07\x00\x00\x00\x0dAddDataWind\
ow\x01\x03\x00\x00\x00\x0ce\xb0^\xfa\x00(\x00&\
\x00N\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04&N\
ew\x07\x00\x00\x00\x0dAddDataWi\
ndow\x01\x03\x00\x00\x00\x0cxn\x8b\xa4\x00(\
\x00&\x00O\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x03\
&OK\x07\x00\x00\x00\x0dAddDataW\
indow\x01\x03\x00\x00\x00\x08m\xfbR\xa0e\
\x87N\xf6\x08\x00\x00\x00\x00\x06\x00\x00\x00\x09Add\
Files\x07\x00\x00\x00\x0dAddDa\
taWindow\x01\x03\x00\x00\x00\x10mO\
\x89\xc8v\xee_U\x00(\x00&\x00F\x00)\x08\x00\
\x00\x00\x00\x06\x00\x00\x00\x0eBrowse &\
Folder\x07\x00\x00\x00\x0dAddDa\
taWindow\x01\x03\x00\x00\x00\x04Y\x0d\
R6\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04Copy\
\x07\x00\x00\x00\x10ArgumentsBr\
owser\x01\x03\x00\x00\x00\x04[\xfcQ\xfa\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x06Export\x07\
\x00\x00\x00\x10ArgumentsBro\
wser\x01\x03\x00\x00\x00\x0em\xfbR\xa0N\x8c\
\x8f\xdbR6e\x87N\xf6\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x10Add Binary Fil\
es\x07\x00\x00\x00\x0cCenterWid\
get\x01\x03\x00\x00\x00\x0cm\xfbR\xa0epc\
ne\x87N\xf6\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0eA\
dd Data Files\x07\x00\x00\
\x00\x0cCenterWidget\x01\x03\
\x00\x00\x00\x16m\xfbR\xa0N\x8c\x8f\xdbR6e\x87\
N\xf6]\xf2f\xf4e\xb00\x02\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x19Add binary f\
iles updated.\x07\x00\x00\
\x00\x0cCenterWidget\x01\x03\
\x00\x00\x00\x14m\xfbR\xa0epcne\x87N\xf6\
]\xf2f\xf4e\xb00\x02\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x17Add data files\
updated.\x07\x00\x00\x00\x0cCe\
nterWidget\x01\x03\x00\x00\x00\x0a\
\x98yv\xeeT\x0dy\xf0\xff\x1a\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x09App Name:\x07\x00\x00\
\x00\x0cCenterWidget\x01\x03\
\x00\x00\x00\x04mO\x89\xc8\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x06Browse\x07\x00\x00\x00\x0cCen\
terWidget\x01\x03\x00\x00\x00\x06b\
SS\x05\xff\x01\x08\x00\x00\x00\x00\x06\x00\x00\x00\x07B\
undle!\x07\x00\x00\x00\x0cCente\
rWidget\x01\x03\x00\x00\x00\x12bSS\
\x05v\x84^\x94u(z\x0b^\x8fT\x0dy\xf0\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x10Bundled\
app name\x07\x00\x00\x00\x0cCe\
nterWidget\x01\x03\x00\x00\x00\x14\
\x5c\x06bSS\x05\x81\xf3SUN*e\x87N\xf6\
N-0\x02\x08\x00\x00\x00\x00\x06\x00\x00\x00\x17Bu\
ndling into one \
file.\x07\x00\x00\x00\x0cCenter\
Widget\x01\x03\x00\x00\x00\x14\x5c\x06bS\
S\x05\x81\xf3SUN*v\xee_UN-0\x02\
\x08\x00\x00\x00\x00\x06\x00\x00\x00\x19Bundli\
ng into one fold\
er.\x07\x00\x00\x00\x0cCenterWi\
dget\x01\x03\x00\x00\x00\x04n\x05t\x06\x08\x00\
\x00\x00\x00\x06\x00\x00\x00\x05Clean\x07\x00\x00\
\x00\x0cCenterWidget\x01\x03\
\x00\x00\x00\x1cg\x84^\xfaRM\x5c\x06n\x05\x96d\
\x7f\x13[XN\x0eN4e\xf6v\xee_U0\x02\
\x08\x00\x00\x00\x00\x06\x00\x00\x007Clean \
cache and remove\
temporary files\
before building\
.\x07\x00\x00\x00\x0cCenterWidg\
et\x01\x03\x00\x00\x00\x04\x95\x19\x8b\xef\x08\x00\x00\x00\
\x00\x06\x00\x00\x00\x05Error\x07\x00\x00\x00\x0c\
CenterWidget\x01\x03\x00\x00\
\x00\x08\x96\x90_\x0f[\xfcQe\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x0dHidden Impor\
t\x07\x00\x00\x00\x0cCenterWidg\
et\x01\x03\x00\x00\x00\x10\x96\x90_\x0f[\xfcQe\
]\xf2f\xf4e\xb00\x02\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x16Hidden import \
updated.\x07\x00\x00\x00\x0cCen\
terWidget\x01\x03\x00\x00\x00\x0eb\
SS\x05\x81\xf3SUN*e\x87N\xf6\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x08One File\x07\
\x00\x00\x00\x0cCenterWidget\
\x01\x03\x00\x00\x00\x0ebSS\x05\x81\xf3SUN*\
v\xee_U\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0aOn\
e Folder\x07\x00\x00\x00\x0cCen\
terWidget\x01\x03\x00\x00\x00\x10S\
Uv\xee_U\x00/SUe\x87N\xf6\xff\x1a\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x15One Fol\
der/ One File:\x07\x00\
\x00\x00\x0cCenterWidget\x01\
\x03\x00\x00\x00\x10bS_\x00\x81\x1ag,\x8d\xef_\
\x84\xff\x1a\x00 \x08\x00\x00\x00\x00\x06\x00\x00\x00\x14O\
pened script pat\
h: \x07\x00\x00\x00\x0cCenterWi\
dget\x01\x03\x00\x00\x00NW(\x8b\xe5\x00 \
\x00P\x00y\x00t\x00h\x00o\x00n\x00 s\xaf\
X\x83N-O<NNl\xa1g\x09[\x89\x88\xc5\
\x00 \x00P\x00y\x00i\x00n\x00s\x00t\x00a\
\x00l\x00l\x00e\x00r\xff\x0cf/T&N\xcd\
\x89\x81~\xe7~\xed\xff\x1f\x08\x00\x00\x00\x00\x06\x00\x00\
\x00TPyinstaller do\
esn't seem to be\
installed in th\
is Python enviro\
nment, still con\
tinue?\x07\x00\x00\x00\x0cCente\
rWidget\x01\x03\x00\x00\x00\x1a\x00P\x00\
y\x00t\x00h\x00o\x00n\x00 QeS\xe3\x81\
\x1ag,\x8d\xef_\x84\x08\x00\x00\x00\x00\x06\x00\x00\x00\
\x18Python entry sc\
ript path\x07\x00\x00\x00\x0cCe\
nterWidget\x01\x03\x00\x00\x00\x0c\
_\x85bSS\x05\x81\x1ag,\xff\x1a\x08\x00\x00\x00\
\x00\x06\x00\x00\x00\x0ePython scr\
ipt:\x07\x00\x00\x00\x0cCenterW\
idget\x01\x03\x00\x00\x00\x12]\xf2\x5c\x06\x98\
yv\xeeT\x0d\x8b\xbe\x7fnN:\xff\x1a\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x1dThe app n\
ame has been set\
to:\x07\x00\x00\x00\x0cCenterW\
idget\x01\x03\x00\x00\x000\x90\x09b\xe9v\
\x84N\x0df/g\x09eHv\x84\x00P\x00y\x00\
t\x00h\x00o\x00n\x89\xe3\x91\xcaVh\xff\x0c\x8b\
\xf7\x91\xcde\xb0\x90\x09b\xe9\xff\x01\x08\x00\x00\x00\x00\
\x06\x00\x00\x00DThe selecti\
on is not a vali\
d Python interpr\
eter, please res\
elect it!\x07\x00\x00\x00\x0cCe\
nterWidget\x01\x03\x00\x00\x002\
\x90\x09b\xe9v\x84N\x0df/g\x09eHv\x84\
\x00P\x00y\x00t\x00h\x00o\x00n\x81\x1ag,\
e\x87N\xf6\xff\x0c\x8b\xf7\x91\xcde\xb0\x90\x09b\xe9\
\xff\x01\x08\x00\x00\x00\x00\x06\x00\x00\x00DThe \
selection is not\
a valid Python \
script file, ple\
ase reselect it!\
\x07\x00\x00\x00\x0cCenterWidge\
t\x01\x03\x00\x00\x00\x04\x8bfTJ\x08\x00\x00\x00\x00\
\x06\x00\x00\x00\x07Warning\x07\x00\x00\x00\
\x0cCenterWidget\x01\x03\x00\
\x00\x00\x18N\x0dO\x1aR \x96d\x7f\x13[XN\
\x0eN4e\xf6e\x87N\xf60\x02\x08\x00\x00\x00\x00\
\x06\x00\x00\x00*Will not de\
lete cache and t\
emporary files.\x07\
\x00\x00\x00\x0cCenterWidget\
\x01\x03\x00\x00\x00\x10b@g\x09e\x87N\xf6\x00 \
\x00(\x00*\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0d\
All Files (*)\x07\x00\x00\
\x00\x0bIconFileDlg\x01\x03\x00\
\x00\x00\x04V\xfeh\x07\x08\x00\x00\x00\x00\x06\x00\x00\x00\
\x08App Icon\x07\x00\x00\x00\x0bIc\
onFileDlg\x01\x03\x00\x00\x00\x04S\
\xd6m\x88\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06Can\
cel\x07\x00\x00\x00\x0bIconFile\
Dlg\x01\x03\x00\x00\x00\x08V\xfeh\x07e\x87N\
\xf6\x08\x00\x00\x00\x00\x06\x00\x00\x00\x09Icon \
File\x07\x00\x00\x00\x0bIconFil\
eDlg\x01\x03\x00\x00\x00&V\xfeh\x07e\x87\
N\xf6\x00 \x00(\x00*\x00.\x00i\x00c\x00o\
\x00 \x00*\x00.\x00i\x00c\x00n\x00s\x00)\
\x08\x00\x00\x00\x00\x06\x00\x00\x00\x19Icon F\
iles (*.ico *.ic\
ns)\x07\x00\x00\x00\x0bIconFile\
Dlg\x01\x03\x00\x00\x00\x04bS_\x00\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x04Open\x07\x00\x00\x00\x0b\
IconFileDlg\x01\x03\x00\x00\x00\
\x10b@g\x09e\x87N\xf6\x00 \x00(\x00*\x00\
)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0dAll F\
iles (*)\x07\x00\x00\x00\x12Int\
erpreterFileDlg\x01\
\x03\x00\x00\x00\x0aS\xefbg\x88Le\x87N\xf6\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x0fExecuta\
ble File\x07\x00\x00\x00\x12Int\
erpreterFileDlg\x01\
\x03\x00\x00\x00\x1aS\xefbg\x88Le\x87N\xf6\x00\
\x00(\x00*\x00.\x00e\x00x\x00e\x00)\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x18Executa\
ble Files (*.exe\
)\x07\x00\x00\x00\x12Interprete\
rFileDlg\x01\x03\x00\x00\x00\x14\x00P\
\x00y\x00t\x00h\x00o\x00n\x00 \x89\xe3\x91\xca\
Vh\x08\x00\x00\x00\x00\x06\x00\x00\x00\x12Pyth\
on Interpreter\x07\x00\
\x00\x00\x12InterpreterFi\
leDlg\x01\x03\x00\x00\x00.\x00P\x00y\x00\
t\x00h\x00o\x00n\x00 \x89\xe3\x91\xcaVh\x00\
\x00(\x00p\x00y\x00t\x00h\x00o\x00n\x00\
.\x00e\x00x\x00e\x00)\x08\x00\x00\x00\x00\x06\x00\
\x00\x00\x1fPython Interp\
reter (python.ex\
e)\x07\x00\x00\x00\x12Interpret\
erFileDlg\x01\x03\x00\x00\x00*\x00\
P\x00y\x00t\x00h\x00o\x00n\x00 \x89\xe3\x91\
\xcaVh\x00 \x00(\x00p\x00y\x00t\x00h\x00\
o\x00n\x003\x00*\x00)\x08\x00\x00\x00\x00\x06\x00\
\x00\x00\x1dPython Interp\
reter (python3*)\
\x07\x00\x00\x00\x12Interpreter\
FileDlg\x01\x03\x00\x00\x00\x06\x5c1~\
\xea0\x02\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06Rea\
dy.\x07\x00\x00\x00\x07MainApp\x01\
\x03\x00\x00\x00\x0cQsN\x8e\x00(\x00&\x00A\x00\
)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06&Abou\
t\x07\x00\x00\x00\x0aMainWindow\
\x01\x03\x00\x00\x00\x0c\x90\x00Q\xfa\x00(\x00&\x00E\
\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05&Exi\
t\x07\x00\x00\x00\x0aMainWindow\
\x01\x03\x00\x00\x00\x0ce\x87N\xf6\x00(\x00&\x00F\
\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05&Fil\
e\x07\x00\x00\x00\x0aMainWindow\
\x01\x03\x00\x00\x00\x0c^.R\xa9\x00(\x00&\x00H\
\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05&Hel\
p\x07\x00\x00\x00\x0aMainWindow\
\x01\x03\x00\x00\x00\x0c\x8b\xbe\x7fn\x00(\x00&\x00S\
\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x09&Set\
tings\x07\x00\x00\x00\x0aMainWi\
ndow\x01\x03\x00\x00\x00\x0cQsN\x8e\x00 \
\x00&\x00Q\x00t\x08\x00\x00\x00\x00\x06\x00\x00\x00\x09\
About &Qt\x07\x00\x00\x00\x0aMa\
inWindow\x01\x03\x00\x00\x00\x0aQs\
N\x8ekdz\x0b^\x8f\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x12About This Pro\
gram\x07\x00\x00\x00\x0aMainWin\
dow\x01\x03\x00\x00\x00\x1a[\xfcQ\xfa\x91M\x7f\
n\x81\xf3\x00 \x00J\x00S\x00O\x00N\x00 e\
\x87N\xf6\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1aExp\
ort Config To JS\
ON File\x07\x00\x00\x00\x0aMain\
Window\x01\x03\x00\x00\x00\x1cN\xce\x00 \
\x00J\x00S\x00O\x00N\x00 e\x87N\xf6N-\
[\xfcQe\x91M\x7fn\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x1cImport Config \
From JSON File\x07\x00\
\x00\x00\x0aMainWindow\x01\x03\x00\
\x00\x00\x1c\x00P\x00y\x00I\x00n\x00s\x00t\x00\
a\x00l\x00l\x00e\x00r\x00 e\x87hc\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x19PyInsta\
ller Documentati\
on\x07\x00\x00\x00\x0aMainWindo\
w\x01\x03\x00\x00\x00 \x00P\x00y\x00I\x00n\x00\
s\x00t\x00a\x00l\x00l\x00e\x00r\x00 \x90\
\x09\x98y\x8b\xe6`\xc5\x08\x00\x00\x00\x00\x06\x00\x00\x00\
\x1bPyInstaller Opt\
ions Details\x07\x00\x00\x00\
\x0aMainWindow\x01\x03\x00\x00\x00\
\x0cb\xa5TJ\x00 \x00B\x00u\x00g\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x0bReport Bu\
gs\x07\x00\x00\x00\x0aMainWindo\
w\x01\x03\x00\x00\x00\x0cS\xd6m\x88\x00(\x00&\x00\
C\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x07&Ca\
ncel\x07\x00\x00\x00\x13MultiIt\
emEditWindow\x01\x03\x00\x00\
\x00\x0cR \x96d\x00(\x00&\x00D\x00)\x08\x00\
\x00\x00\x00\x06\x00\x00\x00\x07&Delete\x07\
\x00\x00\x00\x13MultiItemEdi\
tWindow\x01\x03\x00\x00\x00\x0ce\xb0^\
\xfa\x00(\x00&\x00N\x00)\x08\x00\x00\x00\x00\x06\x00\
\x00\x00\x04&New\x07\x00\x00\x00\x13Mult\
iItemEditWindow\x01\
\x03\x00\x00\x00\x0cxn\x8b\xa4\x00(\x00&\x00O\x00\
)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x03&OK\x07\x00\
\x00\x00\x13MultiItemEdit\
Window\x01\x03\x00\x00\x00\x0emO\x89\xc8\
S\x05\x00(\x00&\x00B\x00)\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x10&Browse pack\
ages\x07\x00\x00\x00\x12MultiPk\
gEditWindow\x01\x03\x00\x00\x00\
\x0a]\xf2[\x89\x88\xc5v\x84S\x05\x08\x00\x00\x00\x00\
\x06\x00\x00\x00\x12Installed P\
ackages\x07\x00\x00\x00\x0dPkgB\
rowserDlg\x01\x03\x00\x00\x00\x04S\
\x05T\x0d\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04Nam\
e\x07\x00\x00\x00\x0dPkgBrowser\
Dlg\x01\x03\x00\x00\x00\x04rHg,\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x07Version\x07\x00\
\x00\x00\x0dPkgBrowserDlg\
\x01\x03\x00\x00\x00\x04c\xcf\x8f\xf0\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x0bDescription\x07\
\x00\x00\x00\x16PyinstallerO\
ptionTable\x01\x03\x00\x00\x00\x04\
\x90\x09\x98y\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06Op\
tion\x07\x00\x00\x00\x16Pyinsta\
llerOptionTable\x01\
\x03\x00\x00\x00\x10b@g\x09e\x87N\xf6\x00 \x00\
(\x00*\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0dA\
ll Files (*)\x07\x00\x00\x00\
\x0dScriptFileDlg\x01\x03\
\x00\x00\x00\x04S\xd6m\x88\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x06Cancel\x07\x00\x00\x00\x0dScr\
iptFileDlg\x01\x03\x00\x00\x00\x04\
bS_\x00\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04Op\
en\x07\x00\x00\x00\x0dScriptFil\
eDlg\x01\x03\x00\x00\x00\x14\x00P\x00y\x00t\
\x00h\x00o\x00nQeS\xe3e\x87N\xf6\x08\x00\
\x00\x00\x00\x06\x00\x00\x00\x11Python E\
ntry File\x07\x00\x00\x00\x0dSc\
riptFileDlg\x01\x03\x00\x00\x00\
\x12\x00P\x00y\x00t\x00h\x00o\x00n\x00 e\
\x87N\xf6\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0bPyt\
hon File\x07\x00\x00\x00\x0dScr\
iptFileDlg\x01\x03\x00\x00\x000\
\x00P\x00y\x00t\x00h\x00o\x00n\x00 \x81\x1a\
g,e\x87N\xf6\x00 \x00(\x00*\x00.\x00p\
\x00y\x00 \x00*\x00.\x00p\x00y\x00w\x00)\
\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1aPython\
Script (*.py *.\
pyw)\x07\x00\x00\x00\x0dScriptF\
ileDlg\x01\x03\x00\x00\x00\x04S\xd6m\x88\
\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06Cancel\
\x07\x00\x00\x00\x0dSubProcessD\
lg\x01\x03\x00\x00\x00\x04Qs\x95\xed\x08\x00\x00\x00\
\x00\x06\x00\x00\x00\x05Close\x07\x00\x00\x00\x0d\
SubProcessDlg\x01\x03\x00\
\x00\x00\x0abSS\x05[\x8cb\x10\xff\x01\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x05Done!\x07\x00\x00\x00\
\x0dSubProcessDlg\x01\x03\
\x00\x00\x00 \x8f\xd0\x88L~\xd3g_\xff\x0cOF\
g\x09\x95\x19\x8b\xefS\xd1u\x1f\xff\x0c\x90\x00Q\xfa\
x\x01N:\x08\x00\x00\x00\x00\x06\x00\x00\x008Ex\
ecution ends, bu\
t an error occur\
s and the exit c\
ode is\x07\x00\x00\x00\x0dSubPr\
ocessDlg\x01\x03\x00\x00\x00\x0cbS\
_\x00\x8f\x93Q\xfaOM\x7fn\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x09Open Dist\x07\x00\x00\
\x00\x0dSubProcessDlg\x01\
\x03\x00\x00\x006\x8b\xf7h\xc0g\xe5f/T&]\
\xf2~\xcf[\x89\x88\xc5kcxnrHg,v\
\x84\x00 \x00P\x00y\x00I\x00n\x00s\x00t\x00\
a\x00l\x00l\x00e\x00r0\x02\x08\x00\x00\x00\x00\
\x06\x00\x00\x00MPlease chec\
k if you have in\
stalled the corr\
ect version of P\
yInstaller or no\
t.\x07\x00\x00\x00\x0dSubProces\
sDlg\x01\x03\x00\x00\x00\x1e\x00P\x00y\x00I\
\x00n\x00s\x00t\x00a\x00l\x00l\x00e\x00r\
\x00 \x95\x19\x8b\xef\xff\x01\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x12PyInstaller Er\
ror!\x07\x00\x00\x00\x0dSubProc\
essDlg\x01\x03\x00\x00\x00$\x00P\x00y\
\x00I\x00n\x00s\x00t\x00a\x00l\x00l\x00e\
\x00r\x00 [P\x8f\xdbz\x0b\x8f\x93Q\xfa\xff\x1a\
\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1ePyInst\
aller subprocess\
output:\x07\x00\x00\x00\x0dSub\
ProcessDlg\x01\x03\x00\x00\x00\x0a\
^\x94u(V\xfeh\x07\xff\x1a\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x09App icon:\x07\x00\x00\
\x00\x12WinMacCenterWi\
dget\x01\x03\x00\x00\x00\x04mO\x89\xc8\x08\x00\
\x00\x00\x00\x06\x00\x00\x00\x06Browse\x07\x00\
\x00\x00\x12WinMacCenterW\
idget\x01\x03\x00\x00\x00\x04\x95\x19\x8b\xef\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x05Error\x07\x00\
\x00\x00\x12WinMacCenterW\
idget\x01\x03\x00\x00\x00\x14N:h\x07Q\
\xc6\x00I\x00/\x00OT/u(~\xc8z\xef\x08\
\x00\x00\x00\x00\x06\x00\x00\x00&Open a \
console window f\
or standard I/O\x07\
\x00\x00\x00\x12WinMacCenter\
Widget\x01\x03\x00\x00\x00\x12bS_\x00\
v\x84V\xfeh\x07\x8d\xef_\x84\xff\x1a\x00 \x08\x00\
\x00\x00\x00\x06\x00\x00\x00\x12Opened i\
con path: \x07\x00\x00\x00\x12W\
inMacCenterWidge\
t\x01\x03\x00\x00\x00\x08V\xfeh\x07\x8d\xef_\x84\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x11Path to\
icon file\x07\x00\x00\x00\x12W\
inMacCenterWidge\
t\x01\x03\x00\x00\x00&\x5c\x06N:bSS\x05z\
\x0b^\x8fv\x84\x00 \x00s\x00t\x00d\x00i\x00\
o\x00 T/u(~\xc8z\xef0\x02\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x19Terminal \
will be enabled.\
\x07\x00\x00\x00\x12WinMacCente\
rWidget\x01\x03\x00\x00\x00(N\x0dO\
\x1aN:bSS\x05z\x0b^\x8fv\x84\x00 \x00\
s\x00t\x00d\x00i\x00o\x00 T/u(~\
\xc8z\xef0\x02\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1dT\
erminal will not\
be enabled.\x07\x00\x00\x00\
\x12WinMacCenterWid\
get\x01\x03\x00\x00\x00&\x90\x09b\xe9v\x84N\
\x0df/g\x09eHv\x84V\xfeh\x07e\x87N\
\xf6\xff\x0c\x8b\xf7\x91\xcde\xb0\x90\x09b\xe9\xff\x01\x08\
\x00\x00\x00\x00\x06\x00\x00\x00<The sel\
ection is not a \
valid icon file,\
please re-selec\
t it!\x07\x00\x00\x00\x12WinMac\
CenterWidget\x01\
\x00\x00\x0c\xf9\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
@ -3680,7 +4152,7 @@ tware Foundation\
3 of the Licens\
e, or any later \
version.\x0a\x0aCopyri\
ght \xc2\xa9 2022-2023\
ght \xc2\xa9 2022-2024\
[Muzing \x5c<muzi\
2001@foxmail.com\
\x5c>](https://muzi\
@ -3726,7 +4198,7 @@ e) \xe7\x9a\x84\xe7\xba\xa6\xe6\x9d\x9f\xe4\xb8\x8b\xef\
\xb6\xe8\xbf\x9b\xe8\xa1\x8c\xe5\x86\x8d\xe5\x8f\x91\xe5\xb8\x83\
\xe5\x92\x8c/\xe6\x88\x96\xe4\xbf\xae\xe6\x94\xb9\xe3\x80\x82\
\x0a\x0a\xe7\x89\x88\xe6\x9d\x83\xe6\x89\x80\xe6\x9c\x89 \xc2\
\xa9 2022-2023 [Mu\
\xa9 2022-2024 [Mu\
zing \x5c<muzi2001@\
foxmail.com\x5c>](h\
ttps://muzing.to\
@ -3742,6 +4214,14 @@ qt_resource_name = b"\
\x00O\xa6S\
\x00I\
\x00c\x00o\x00n\x00s\
\x00\x04\
\x00\x06\xc4\xee\
\x00i\
\x001\x008\x00n\
\x00\x08\
\x0e8\x05}\
\x00z\
\x00h\x00_\x00C\x00N\x00.\x00q\x00m\
\x00\x14\
\x01O\xad\x98\
\x00P\
@ -3779,32 +4259,36 @@ qt_resource_name = b"\
"
qt_resource_struct = b"\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x10\x00\x02\x00\x00\x00\x06\x00\x00\x00\x07\
\x00\x00\x00 \x00\x02\x00\x00\x00\x01\x00\x00\x00\x0e\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x03\
\x00\x00\x00\x10\x00\x02\x00\x00\x00\x06\x00\x00\x00\x08\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\xc6\x00\x00\x00\x00\x00K\x00\x00\x80\xaa\
\x00\x00\x01\x8c\x9a\xb7\xd3\xac\
\x00\x00\x00\xc6\x00\x00\x00\x00\x00:\x00\x00\xb2A\
\x00\x00\x01\x8c\x9a\xb7\xd3\xac\
\x00\x00\x00\xf2\x00\x00\x00\x00\x00K\x00\x00\xe1\x9d\
\x00\x00\x01\x8c\x9a\xb7\xd3\xac\
\x00\x00\x00\xf2\x00\x00\x00\x00\x00:\x00\x00\xe4\xb0\
\x00\x00\x01\x8c\x9a\xb7\xd3\xac\
\x00\x00\x00\x9a\x00\x00\x00\x00\x00\x01\x00\x00f\x93\
\x00\x00\x01\x8c\xbd[\xc8Z\
\x00\x00\x00 \x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x01\x8c\x9a\xb7\xd3\xaa\
\x00\x00\x00l\x00\x00\x00\x00\x00\x01\x00\x00\x19\xb6\
\x00\x00\x01\x8c\x9a\xb7\xd3\xab\
\x00\x00\x00\xaa\x00\x00\x00\x00\x00\x01\x00\x00w_\
\x00\x00\x01\x8c\xb3\xa0\x98\xeb\
\x00\x00\x00~\x00\x00\x00\x00\x00\x01\x00\x00<\x13\
\x00\x00\x01\x8c\x9a\xb7\xd3\xab\
\x00\x00\x00N\x00\x00\x00\x00\x00\x01\x00\x00\x0c\xfd\
\x00\x00\x01\x8c\x9a\xb7\xd3\xaa\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x04\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\xea\x00\x00\x00\x00\x00K\x00\x00\x9e\x0c\
\x00\x00\x01\x8c\x9fP\xce\x07\
\x00\x00\x00\xea\x00\x00\x002\x00:\x00\x00\xcf\xa3\
\x00\x00\x01\x8c\x9fP\xce\x07\
\x00\x00\x01\x16\x00\x00\x00\x00\x00K\x00\x00\xfe\xff\
\x00\x00\x01\x8c\xd4u\x1b\xc8\
\x00\x00\x01\x16\x00\x00\x002\x00:\x00\x01\x02\x12\
\x00\x00\x01\x8c\xd4u\x1b\xcf\
\x00\x00\x00\xbe\x00\x00\x00\x00\x00\x01\x00\x00\x83\xf5\
\x00\x00\x01\x8c\xbd\xfa\xbd\x88\
\x00\x00\x00D\x00\x00\x00\x00\x00\x01\x00\x00\x1db\
\x00\x00\x01\x8b\xbd\x8a$\x9a\
\x00\x00\x00\x90\x00\x00\x00\x00\x00\x01\x00\x007\x18\
\x00\x00\x01\x8cz\xef\xd4\x05\
\x00\x00\x00\xce\x00\x00\x00\x00\x00\x01\x00\x00\x94\xc1\
\x00\x00\x01\x8c\xb3\x93\xcb\xe3\
\x00\x00\x00\xa2\x00\x00\x00\x00\x00\x01\x00\x00Yu\
\x00\x00\x01\x8c\xbd\xfa\xbd\x88\
\x00\x00\x00r\x00\x00\x00\x00\x00\x01\x00\x00*_\
\x00\x00\x01\x8b\xbd\x8a$\x9a\
\x00\x00\x00.\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x01\x8c\xd3\xb8s\xe7\
"

Binary file not shown.

View File

@ -0,0 +1,540 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN" sourcelanguage="en">
<context>
<name>AboutDlg</name>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="138"/>
<source>About</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="163"/>
<source>Can&apos;t open the About document, try to reinstall this program.</source>
<translation></translation>
</message>
</context>
<context>
<name>AddDataWindow</name>
<message>
<location filename="../../Widgets/add_data_widget.py" line="71"/>
<source>Add Files</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/add_data_widget.py" line="88"/>
<source>&amp;New</source>
<translation>(&amp;N)</translation>
</message>
<message>
<location filename="../../Widgets/add_data_widget.py" line="89"/>
<source>&amp;Browse File</source>
<translation>(&amp;B)</translation>
</message>
<message>
<location filename="../../Widgets/add_data_widget.py" line="90"/>
<source>Browse &amp;Folder</source>
<translation>(&amp;F)</translation>
</message>
<message>
<location filename="../../Widgets/add_data_widget.py" line="91"/>
<source>&amp;Delete</source>
<translation>(&amp;D)</translation>
</message>
<message>
<location filename="../../Widgets/add_data_widget.py" line="93"/>
<source>&amp;OK</source>
<translation>(&amp;O)</translation>
</message>
<message>
<location filename="../../Widgets/add_data_widget.py" line="94"/>
<source>&amp;Cancel</source>
<translation>(&amp;C)</translation>
</message>
</context>
<context>
<name>ArgumentsBrowser</name>
<message>
<location filename="../../Widgets/arguments_browser.py" line="65"/>
<source>Copy</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/arguments_browser.py" line="67"/>
<source>Export</source>
<translation></translation>
</message>
</context>
<context>
<name>CenterWidget</name>
<message>
<location filename="../../Widgets/center_widget.py" line="128"/>
<source>Python entry script path</source>
<translation>Python </translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="129"/>
<location filename="../../Widgets/center_widget.py" line="132"/>
<source>Browse</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="124"/>
<source>Python script:</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="135"/>
<source>App Name:</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="136"/>
<source>Bundled app name</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="138"/>
<source>One Folder/ One File:</source>
<translation>/</translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="139"/>
<source>One Folder</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="141"/>
<source>One File</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="145"/>
<location filename="../../Widgets/center_widget.py" line="147"/>
<source>Add Data Files</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="146"/>
<location filename="../../Widgets/center_widget.py" line="148"/>
<source>Add Binary Files</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="150"/>
<source>Hidden Import</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="153"/>
<source>Clean</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="157"/>
<source>Bundle!</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="212"/>
<source>Bundling into one folder.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="215"/>
<source>Bundling into one file.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="229"/>
<source>Add data files updated.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="244"/>
<source>Add binary files updated.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="261"/>
<source>Hidden import updated.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="277"/>
<source>Clean cache and remove temporary files before building.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="282"/>
<source>Will not delete cache and temporary files.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="375"/>
<source>Opened script path: </source>
<translation> </translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="383"/>
<source>The app name has been set to:</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="399"/>
<location filename="../../Widgets/center_widget.py" line="472"/>
<source>Error</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="403"/>
<source>The selection is not a valid Python script file, please reselect it!</source>
<translation>Python脚本文件</translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="450"/>
<source>Warning</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="454"/>
<source>Pyinstaller doesn&apos;t seem to be installed in this Python environment, still continue?</source>
<translation> Python Pyinstaller</translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="476"/>
<source>The selection is not a valid Python interpreter, please reselect it!</source>
<translation>Python解释器</translation>
</message>
</context>
<context>
<name>IconFileDlg</name>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="78"/>
<source>Icon Files (*.ico *.icns)</source>
<translation> (*.ico *.icns)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="79"/>
<source>All Files (*)</source>
<translation> (*)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="83"/>
<source>App Icon</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="84"/>
<source>Icon File</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="85"/>
<source>Open</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="86"/>
<source>Cancel</source>
<translation></translation>
</message>
</context>
<context>
<name>InterpreterFileDlg</name>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="104"/>
<source>Python Interpreter</source>
<translation>Python </translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="108"/>
<source>Executable File</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="113"/>
<source>Python Interpreter (python.exe)</source>
<translation>Python (python.exe)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="114"/>
<source>Executable Files (*.exe)</source>
<translation> (*.exe)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="115"/>
<location filename="../../Widgets/dialog_widgets.py" line="122"/>
<source>All Files (*)</source>
<translation> (*)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="121"/>
<source>Python Interpreter (python3*)</source>
<translation>Python (python3*)</translation>
</message>
</context>
<context>
<name>MainApp</name>
<message>
<location filename="../../__main__.py" line="36"/>
<source>Ready.</source>
<translation></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../../Widgets/main_window.py" line="67"/>
<source>&amp;File</source>
<translation>(&amp;F)</translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="68"/>
<source>Import Config From JSON File</source>
<translation> JSON </translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="69"/>
<source>Export Config To JSON File</source>
<translation> JSON </translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="71"/>
<source>&amp;Settings</source>
<translation>(&amp;S)</translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="73"/>
<source>&amp;Exit</source>
<translation>退(&amp;E)</translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="75"/>
<source>&amp;Help</source>
<translation>(&amp;H)</translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="78"/>
<source>PyInstaller Documentation</source>
<translation>PyInstaller </translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="82"/>
<source>PyInstaller Options Details</source>
<translation>PyInstaller </translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="87"/>
<source>Report Bugs</source>
<translation> Bug</translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="90"/>
<source>&amp;About</source>
<translation>(&amp;A)</translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="91"/>
<source>About This Program</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="92"/>
<source>About &amp;Qt</source>
<translation> &amp;Qt</translation>
</message>
</context>
<context>
<name>MultiItemEditWindow</name>
<message>
<location filename="../../Widgets/multi_item_edit_widget.py" line="72"/>
<source>&amp;New</source>
<translation>(&amp;N)</translation>
</message>
<message>
<location filename="../../Widgets/multi_item_edit_widget.py" line="73"/>
<source>&amp;Delete</source>
<translation>(&amp;D)</translation>
</message>
<message>
<location filename="../../Widgets/multi_item_edit_widget.py" line="75"/>
<source>&amp;OK</source>
<translation>(&amp;O)</translation>
</message>
<message>
<location filename="../../Widgets/multi_item_edit_widget.py" line="76"/>
<source>&amp;Cancel</source>
<translation>(&amp;C)</translation>
</message>
</context>
<context>
<name>MultiPkgEditWindow</name>
<message>
<location filename="../../Widgets/multi_item_edit_widget.py" line="192"/>
<source>&amp;Browse packages</source>
<translation>(&amp;B)</translation>
</message>
</context>
<context>
<name>PkgBrowserDlg</name>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="184"/>
<source>Installed Packages</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="189"/>
<source>Name</source>
<translatorcomment></translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="190"/>
<source>Version</source>
<translation></translation>
</message>
</context>
<context>
<name>PyinstallerOptionTable</name>
<message>
<location filename="../../Widgets/pyinstaller_option_widget.py" line="76"/>
<source>Option</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/pyinstaller_option_widget.py" line="77"/>
<source>Description</source>
<translation></translation>
</message>
</context>
<context>
<name>ScriptFileDlg</name>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="49"/>
<source>Python Script (*.py *.pyw)</source>
<translation>Python (*.py *.pyw)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="50"/>
<source>All Files (*)</source>
<translation> (*)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="56"/>
<source>Python Entry File</source>
<translation>Python入口文件</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="59"/>
<source>Python File</source>
<translation>Python </translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="60"/>
<source>Open</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="61"/>
<source>Cancel</source>
<translation></translation>
</message>
</context>
<context>
<name>SubProcessDlg</name>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="78"/>
<source>Done!</source>
<translatorcomment>PyInstaller运行完成</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="79"/>
<location filename="../../__main__.py" line="94"/>
<source>Open Dist</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="85"/>
<source>Execution ends, but an error occurs and the exit code is</source>
<translation>退</translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="68"/>
<location filename="../../Widgets/subprocess_widget.py" line="87"/>
<location filename="../../__main__.py" line="91"/>
<source>Cancel</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="90"/>
<source>PyInstaller Error!</source>
<translation>PyInstaller </translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="92"/>
<source>PyInstaller subprocess output:</source>
<translation>PyInstaller </translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="99"/>
<source>Please check if you have installed the correct version of PyInstaller or not.</source>
<translation> PyInstaller</translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="100"/>
<location filename="../../__main__.py" line="100"/>
<source>Close</source>
<translation></translation>
</message>
</context>
<context>
<name>WinMacCenterWidget</name>
<message>
<location filename="../../Widgets/center_widget.py" line="519"/>
<source>App icon:</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="521"/>
<source>Path to icon file</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="522"/>
<source>Browse</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="527"/>
<source>Open a console window for standard I/O</source>
<translation>I/O启用终端</translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="565"/>
<source>Terminal will be enabled.</source>
<translation> stdio </translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="570"/>
<source>Terminal will not be enabled.</source>
<translation> stdio </translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="615"/>
<source>Opened icon path: </source>
<translation> </translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="632"/>
<source>Error</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="635"/>
<source>The selection is not a valid icon file, please re-select it!</source>
<translation></translation>
</message>
</context>
</TS>

View File

@ -6,14 +6,12 @@
__all__ = ["AddDataWindow"]
import sys
from pathlib import Path
from typing import Optional
from PySide6.QtCore import QItemSelectionModel, Qt, Signal, Slot
from PySide6.QtGui import QIcon, QPixmap
from PySide6.QtWidgets import (
QApplication,
QFileDialog,
QHBoxLayout,
QHeaderView,
@ -24,8 +22,10 @@ from PySide6.QtWidgets import (
QWidget,
)
from ..Utilities import QObjTr
class AddDataWindow(QWidget):
class AddDataWindow(QObjTr, QWidget):
"""用于提供 PyInstaller --add-data 和 --add-binary 功能的窗口"""
# 类型别名
@ -68,7 +68,7 @@ class AddDataWindow(QWidget):
def _setup_ui(self) -> None:
"""处理 UI 内容"""
self.setWindowTitle("添加文件")
self.setWindowTitle(AddDataWindow.tr("Add Files"))
self.setMinimumWidth(550)
self.setWindowIcon(QIcon(QPixmap(":/Icons/Py2exe-GUI_icon_72px")))
@ -85,13 +85,13 @@ class AddDataWindow(QWidget):
1, QHeaderView.ResizeMode.ResizeToContents
)
self.new_btn.setText("新建(&N)")
self.browse_btn.setText("浏览文件(&B)")
self.browse_dir_btn.setText("浏览目录(&F)")
self.delete_btn.setText("删除(&D)")
self.new_btn.setText(AddDataWindow.tr("&New"))
self.browse_btn.setText(AddDataWindow.tr("&Browse File"))
self.browse_dir_btn.setText(AddDataWindow.tr("Browse &Folder"))
self.delete_btn.setText(AddDataWindow.tr("&Delete"))
self.ok_btn.setText("确定")
self.cancel_btn.setText("取消")
self.ok_btn.setText(AddDataWindow.tr("&OK"))
self.cancel_btn.setText(AddDataWindow.tr("&Cancel"))
# noinspection DuplicatedCode
def _setup_layout(self) -> None:
@ -119,6 +119,7 @@ class AddDataWindow(QWidget):
self.setLayout(main_layout)
# noinspection DuplicatedCode
def _connect_slots(self) -> None:
"""构建各槽函数、连接信号"""
@ -212,7 +213,6 @@ class AddDataWindow(QWidget):
self.data_selected.emit(self._submit())
self.close()
# noinspection DuplicatedCode
self.new_btn.clicked.connect(handle_new_btn)
self.delete_btn.clicked.connect(handle_delete_btn)
self.browse_btn.clicked.connect(handel_browse_btn)
@ -261,10 +261,3 @@ class AddDataWindow(QWidget):
)
self.item_table.setItem(row, 0, source_item)
self.item_table.setItem(row, 1, QTableWidgetItem(data_item[1]))
if __name__ == "__main__":
app = QApplication(sys.argv)
window = AddDataWindow()
window.show()
sys.exit(app.exec())

View File

@ -4,7 +4,10 @@
"""此模块主要包含用于在界面上预览显示 PyInstaller 命令选项的 `ArgumentsBrowser` 类
"""
__all__ = ["get_line_continuation", "ArgumentsBrowser"]
__all__ = [
"get_line_continuation",
"ArgumentsBrowser",
]
from typing import Optional
@ -12,6 +15,7 @@ from PySide6.QtGui import QContextMenuEvent
from PySide6.QtWidgets import QMenu, QTextBrowser, QWidget
from ..Constants import RUNTIME_INFO, Platform
from ..Utilities import QObjTr
# 一组适合浅色背景的颜色
colors = ["#FD6D5A", "#FEB40B", "#6DC354", "#994487", "#518CD8", "#443295"]
@ -46,7 +50,7 @@ def wrap_font_tag(raw_text: str, color: str, **kwargs):
return f"<font {tag_attributes}>{raw_text}</font>"
class ArgumentsBrowser(QTextBrowser):
class ArgumentsBrowser(QObjTr, QTextBrowser):
"""针对命令行参数列表特别优化的文本浏览器"""
def __init__(self, parent: Optional[QWidget] = None) -> None:
@ -58,9 +62,9 @@ class ArgumentsBrowser(QTextBrowser):
# 右键菜单
self.context_menu = QMenu(self)
copy_action = self.context_menu.addAction("复制")
copy_action = self.context_menu.addAction(ArgumentsBrowser.tr("Copy"))
copy_action.triggered.connect(self._handle_copy_action)
export_action = self.context_menu.addAction("导出")
export_action = self.context_menu.addAction(ArgumentsBrowser.tr("Export"))
export_action.triggered.connect(self._handle_export_action)
def contextMenuEvent(self, event: QContextMenuEvent) -> None:

View File

@ -31,7 +31,7 @@ from PySide6.QtWidgets import (
from ..Constants import PyInstOpt
from ..Core import InterpreterValidator
from ..Utilities import ALL_PY_ENVs, PyEnv
from ..Utilities import ALL_PY_ENVs, PyEnv, QObjTr
from .add_data_widget import AddDataWindow
from .arguments_browser import ArgumentsBrowser
from .dialog_widgets import (
@ -45,7 +45,7 @@ from .pyenv_combobox import PyEnvComboBox
from .pyinstaller_option_widget import PyinstallerOptionTable
class CenterWidget(QWidget):
class CenterWidget(QObjTr, QWidget):
"""主界面的中央控件
此类为可以实例化的基类适用于所有平台
@ -54,7 +54,6 @@ class CenterWidget(QWidget):
# 自定义信号
option_selected = QtCore.Signal(tuple) # 用户通过界面控件选择选项后发射此信号
# option_selected 实际类型为 tuple[PyinstallerArgs, str]
def __init__(self, parent: QMainWindow) -> None:
@ -122,38 +121,40 @@ class CenterWidget(QWidget):
def _setup_ui(self) -> None:
"""设置各种控件的属性"""
self.script_path_label.setText("待打包脚本:")
self.script_path_label.setText(CenterWidget.tr("Python script:"))
self.script_path_le.setReadOnly(True)
self.script_path_le.setPlaceholderText("Python入口文件路径")
self.script_browse_btn.setText("浏览")
self.script_path_le.setPlaceholderText(
CenterWidget.tr("Python entry script path")
)
self.script_browse_btn.setText(CenterWidget.tr("Browse"))
self.script_browse_btn.setFixedWidth(80)
self.pyenv_browse_btn.setText("浏览")
self.pyenv_browse_btn.setText(CenterWidget.tr("Browse"))
self.pyenv_browse_btn.setFixedWidth(80)
self.project_name_label.setText("项目名称:")
self.project_name_le.setPlaceholderText("打包的应用程序名称")
self.project_name_label.setText(CenterWidget.tr("App Name:"))
self.project_name_le.setPlaceholderText(CenterWidget.tr("Bundled app name"))
self.fd_label.setText("单文件/单目录:")
self.one_dir_btn.setText("打包至单个目录")
self.fd_label.setText(CenterWidget.tr("One Folder/ One File:"))
self.one_dir_btn.setText(CenterWidget.tr("One Folder"))
self.one_dir_btn.setChecked(True) # 默认值
self.one_file_btn.setText("打包至单个文件")
self.one_file_btn.setText(CenterWidget.tr("One File"))
self.fd_group.addButton(self.one_dir_btn, 0)
self.fd_group.addButton(self.one_file_btn, 1)
self.add_data_btn.setText("添加数据文件")
self.add_binary_btn.setText("添加二进制文件")
self.add_data_dlg.setWindowTitle("添加数据文件")
self.add_binary_dlg.setWindowTitle("添加二进制文件")
self.add_data_btn.setText(CenterWidget.tr("Add Data Files"))
self.add_binary_btn.setText(CenterWidget.tr("Add Binary Files"))
self.add_data_dlg.setWindowTitle(CenterWidget.tr("Add Data Files"))
self.add_binary_dlg.setWindowTitle(CenterWidget.tr("Add Binary Files"))
self.hidden_import_btn.setText("隐式导入")
self.hidden_import_dlg.setWindowTitle("Hidden import")
self.hidden_import_btn.setText(CenterWidget.tr("Hidden Import"))
self.hidden_import_dlg.setWindowTitle("Hidden Import")
self.clean_checkbox.setText("清理")
self.clean_checkbox.setText(CenterWidget.tr("Clean"))
self.clean_checkbox.setChecked(False)
self.pyinstaller_args_browser.setMaximumHeight(80)
self.run_packaging_btn.setText("打包!")
self.run_packaging_btn.setText(CenterWidget.tr("Bundle!"))
self.run_packaging_btn.setEnabled(False)
# 将 PyInstaller 选项详情设置成各控件的 ToolTip
@ -183,16 +184,13 @@ class CenterWidget(QWidget):
self.option_selected.emit((PyInstOpt.script_path, file_path))
@QtCore.Slot(int)
def handle_pyenv_change(new_index: int) -> None:
"""处理用户通过选择不同的 Python 解释器时的响应
:param new_index: 选择的 Python 解释器在 `pyenv_combobox` 中的索引
"""
@QtCore.Slot()
def handle_pyenv_change() -> None:
"""处理用户通过选择不同的 Python 解释器时的响应"""
current_pyenv = self.pyenv_combobox.get_current_pyenv()
# TODO 设置为懒加载,用户打开“已安装的包”对话框时才运行
# 首次调用 current_pyenv.installed_packages 为重大性能热点,优化时应首先考虑
self.pkg_browser_dlg.load_pkg_list(current_pyenv.installed_packages)
@QtCore.Slot()
@ -211,10 +209,10 @@ class CenterWidget(QWidget):
if btn_id == 0:
self.option_selected.emit((PyInstOpt.FD, "--onedir"))
self.parent_widget.statusBar().showMessage("将打包至单个目录中")
self.show_status_msg(CenterWidget.tr("Bundling into one folder."))
elif btn_id == 1:
self.option_selected.emit((PyInstOpt.FD, "--onefile"))
self.parent_widget.statusBar().showMessage("将打包至单个文件中")
self.show_status_msg(CenterWidget.tr("Bundling into one file."))
@QtCore.Slot()
def handle_add_data_btn_clicked() -> None:
@ -228,7 +226,7 @@ class CenterWidget(QWidget):
"""用户完成了添加数据操作的槽函数"""
self.data_item_list = data_item_list
self.parent_widget.statusBar().showMessage("添加数据文件已更新")
self.show_status_msg(CenterWidget.tr("Add data files updated."))
self.option_selected.emit((PyInstOpt.add_data, data_item_list))
@QtCore.Slot()
@ -243,7 +241,7 @@ class CenterWidget(QWidget):
"""用户完成了添加二进制文件操作的槽函数"""
self.binary_item_list = binary_item_list
self.parent_widget.statusBar().showMessage("添加二进制文件已更新")
self.show_status_msg(CenterWidget.tr("Add binary files updated."))
self.option_selected.emit((PyInstOpt.add_binary, binary_item_list))
@QtCore.Slot()
@ -260,7 +258,7 @@ class CenterWidget(QWidget):
"""
self.hidden_import_list = hidden_import_list
self.parent_widget.statusBar().showMessage("隐式导入已更新")
self.show_status_msg(CenterWidget.tr("Hidden import updated."))
self.option_selected.emit((PyInstOpt.hidden_import, hidden_import_list))
@QtCore.Slot(bool)
@ -272,10 +270,16 @@ class CenterWidget(QWidget):
if selected:
self.option_selected.emit((PyInstOpt.clean, "--clean"))
self.parent_widget.statusBar().showMessage("构建前将清理缓存与临时文件")
self.show_status_msg(
CenterWidget.tr(
"Clean cache and remove temporary files before building."
)
)
else:
self.option_selected.emit((PyInstOpt.clean, ""))
self.parent_widget.statusBar().showMessage("不会删除缓存与临时文件")
self.show_status_msg(
CenterWidget.tr("Will not delete cache and temporary files.")
)
# 连接信号与槽
# 入口脚本文件
@ -285,7 +289,7 @@ class CenterWidget(QWidget):
# 添加与选择 Python 解释器
self.pyenv_browse_btn.clicked.connect(self.itp_dlg.open)
self.itp_dlg.fileSelected.connect(self._handle_itp_file_selected)
handle_pyenv_change(0) # 显式调用一次,为默认项设置相关内容
handle_pyenv_change() # 显式调用一次,为默认项设置相关内容
self.pyenv_combobox.currentIndexChanged.connect(handle_pyenv_change)
# 项目名称
@ -366,15 +370,18 @@ class CenterWidget(QWidget):
if option_key == PyInstOpt.script_path:
script_path = Path(option_value)
self.script_path_le.setText(script_path.name)
self.parent_widget.statusBar().showMessage(
f"打开脚本路径:{str(script_path.absolute())}"
self.show_status_msg(
CenterWidget.tr("Opened script path: ")
+ f"{str(script_path.absolute())}"
)
self.add_data_dlg.set_work_dir(script_path.parent)
self.add_binary_dlg.set_work_dir(script_path.parent)
elif option_key == PyInstOpt.out_name:
self.project_name_le.setText(option_value)
self.parent_widget.statusBar().showMessage(f"已将项目名设置为:{option_value}")
self.show_status_msg(
CenterWidget.tr("The app name has been set to:") + f"{option_value}"
)
@QtCore.Slot(PyInstOpt)
def handle_option_error(self, option: PyInstOpt) -> None:
@ -389,8 +396,11 @@ class CenterWidget(QWidget):
# 警告对话框
result = QMessageBox.critical(
self,
"错误",
"选择的不是有效的Python脚本文件请重新选择",
CenterWidget.tr("Error"),
CenterWidget.tr(
"The selection is not a valid Python script file, "
"please reselect it!"
),
QMessageBox.StandardButton.Cancel,
QMessageBox.StandardButton.Ok,
)
@ -437,8 +447,11 @@ class CenterWidget(QWidget):
# TODO 自实现 MessageBox包含"仍要使用"、"取消"、"尝试安装PyInstaller"三个按钮
result = QMessageBox.warning(
self,
"警告",
"在该 Python 环境中似乎没有安装 Pyinstaller" "是否仍要继续?",
CenterWidget.tr("Warning"),
CenterWidget.tr(
"Pyinstaller doesn't seem to be installed in this Python "
"environment, still continue?"
),
QMessageBox.StandardButton.Ok,
QMessageBox.StandardButton.Cancel,
)
@ -456,14 +469,25 @@ class CenterWidget(QWidget):
self.itp_dlg.close()
result = QMessageBox.critical(
self,
"错误",
"选择的不是有效的Python解释器请重新选择",
CenterWidget.tr("Error"),
CenterWidget.tr(
"The selection is not a valid Python interpreter, "
"please reselect it!"
),
QMessageBox.StandardButton.Cancel,
QMessageBox.StandardButton.Ok,
)
if result == QMessageBox.StandardButton.Ok:
self.itp_dlg.exec()
def show_status_msg(self, msg: str) -> None:
"""向父控件QMainWindow的状态栏显示信息
:param msg: 要在状态栏显示的信息
"""
self.parent_widget.statusBar().showMessage(msg)
class WinMacCenterWidget(CenterWidget):
"""包含 Windows 与 MacOS 特有功能的主界面中央控件
@ -492,13 +516,15 @@ class WinMacCenterWidget(CenterWidget):
super()._setup_ui()
self.icon_path_label.setText("应用图标:")
self.icon_path_label.setText(WinMacCenterWidget.tr("App icon:"))
self.icon_path_le.setReadOnly(True)
self.icon_path_le.setPlaceholderText("图标文件路径")
self.icon_browse_btn.setText("浏览")
self.icon_path_le.setPlaceholderText(WinMacCenterWidget.tr("Path to icon file"))
self.icon_browse_btn.setText(WinMacCenterWidget.tr("Browse"))
self.icon_browse_btn.setFixedWidth(80)
self.console_checkbox.setText("为标准I/O启用终端")
self.console_checkbox.setText(
WinMacCenterWidget.tr("Open a console window for standard I/O")
)
self.console_checkbox.setChecked(True) # 默认值
# 将 PyInstaller 选项详情设置成各控件的 ToolTip
@ -520,8 +546,8 @@ class WinMacCenterWidget(CenterWidget):
@QtCore.Slot(str)
def handle_icon_file_selected(file_path: str) -> None:
"""
图标文件完成选择的槽函数 \n
"""图标文件完成选择的槽函数
:param file_path: 图标路径
"""
@ -536,10 +562,12 @@ class WinMacCenterWidget(CenterWidget):
if console:
self.option_selected.emit((PyInstOpt.console, "--console"))
self.parent_widget.statusBar().showMessage("将为打包程序的 stdio 启用终端")
self.show_status_msg(WinMacCenterWidget.tr("Terminal will be enabled."))
else:
self.option_selected.emit((PyInstOpt.console, "--windowed"))
self.parent_widget.statusBar().showMessage("不会为打包程序的 stdio 启用终端")
self.show_status_msg(
WinMacCenterWidget.tr("Terminal will not be enabled.")
)
# 图标文件
self.icon_browse_btn.clicked.connect(self.icon_file_dlg.open)
@ -582,9 +610,11 @@ class WinMacCenterWidget(CenterWidget):
elif option_key == PyInstOpt.icon_path:
icon_path = Path(option_value)
self.icon_path_le.setText(icon_path.name)
self.parent_widget.statusBar().showMessage(
f"打开图标路径:{str(icon_path.absolute())}"
msg = (
WinMacCenterWidget.tr("Opened icon path: ")
+ f"{str(icon_path.absolute())}"
)
self.show_status_msg(msg)
@QtCore.Slot(PyInstOpt)
def handle_option_error(self, option: PyInstOpt) -> None:
@ -599,8 +629,10 @@ class WinMacCenterWidget(CenterWidget):
self.icon_file_dlg.close()
result = QMessageBox.critical(
self.parent_widget,
"错误",
"选择的不是有效的图标文件,请重新选择!",
WinMacCenterWidget.tr("Error"),
WinMacCenterWidget.tr(
"The selection is not a valid icon file, please re-select it!"
),
QMessageBox.StandardButton.Cancel,
QMessageBox.StandardButton.Ok,
)

View File

@ -29,10 +29,10 @@ from PySide6.QtWidgets import (
)
from ..Constants import RUNTIME_INFO, Platform
from ..Utilities import QtFileOpen
from ..Utilities import QObjTr, QtFileOpen
class ScriptFileDlg(QFileDialog):
class ScriptFileDlg(QObjTr, QFileDialog):
"""用于获取入口脚本文件的对话框"""
def __init__(self, parent: Optional[QWidget] = None) -> None:
@ -44,15 +44,24 @@ class ScriptFileDlg(QFileDialog):
self.setAcceptMode(QFileDialog.AcceptMode.AcceptOpen)
self.setViewMode(QFileDialog.ViewMode.Detail)
self.setNameFilters(("Python脚本文件 (*.py *.pyw)", "所有文件 (*)"))
self.setNameFilters(
(
ScriptFileDlg.tr("Python Script (*.py *.pyw)"),
ScriptFileDlg.tr("All Files (*)"),
)
)
self.setFileMode(QFileDialog.FileMode.ExistingFiles)
self.setLabelText(QFileDialog.DialogLabel.FileName, "Python入口文件")
self.setLabelText(QFileDialog.DialogLabel.FileType, "Python文件")
self.setLabelText(QFileDialog.DialogLabel.Accept, "打开")
self.setLabelText(QFileDialog.DialogLabel.Reject, "取消")
self.setLabelText(
QFileDialog.DialogLabel.FileName, ScriptFileDlg.tr("Python Entry File")
)
self.setLabelText(
QFileDialog.DialogLabel.FileType, ScriptFileDlg.tr("Python File")
)
self.setLabelText(QFileDialog.DialogLabel.Accept, ScriptFileDlg.tr("Open"))
self.setLabelText(QFileDialog.DialogLabel.Reject, ScriptFileDlg.tr("Cancel"))
class IconFileDlg(QFileDialog):
class IconFileDlg(QObjTr, QFileDialog):
"""用于获取应用图标文件的对话框"""
def __init__(self, parent: Optional[QWidget] = None) -> None:
@ -64,15 +73,20 @@ class IconFileDlg(QFileDialog):
self.setAcceptMode(QFileDialog.AcceptMode.AcceptOpen)
self.setViewMode(QFileDialog.ViewMode.Detail)
self.setNameFilters(("图标文件 (*.ico *.icns)", "所有文件 (*)"))
self.setNameFilters(
(
IconFileDlg.tr("Icon Files (*.ico *.icns)"),
IconFileDlg.tr("All Files (*)"),
)
)
self.setFileMode(QFileDialog.FileMode.ExistingFile)
self.setLabelText(QFileDialog.DialogLabel.FileName, "图标")
self.setLabelText(QFileDialog.DialogLabel.FileType, "图标文件")
self.setLabelText(QFileDialog.DialogLabel.Accept, "打开")
self.setLabelText(QFileDialog.DialogLabel.Reject, "取消")
self.setLabelText(QFileDialog.DialogLabel.FileName, IconFileDlg.tr("App Icon"))
self.setLabelText(QFileDialog.DialogLabel.FileType, IconFileDlg.tr("Icon File"))
self.setLabelText(QFileDialog.DialogLabel.Accept, IconFileDlg.tr("Open"))
self.setLabelText(QFileDialog.DialogLabel.Reject, IconFileDlg.tr("Cancel"))
class InterpreterFileDlg(QFileDialog):
class InterpreterFileDlg(QObjTr, QFileDialog):
"""用于获取 Python 解释器可执行文件的对话框"""
def __init__(self, parent: Optional[QWidget] = None) -> None:
@ -85,17 +99,32 @@ class InterpreterFileDlg(QFileDialog):
self.setAcceptMode(QFileDialog.AcceptMode.AcceptOpen)
self.setViewMode(QFileDialog.ViewMode.Detail)
self.setFileMode(QFileDialog.FileMode.ExistingFile)
self.setLabelText(QFileDialog.DialogLabel.FileName, "Python解释器")
self.setLabelText(QFileDialog.DialogLabel.FileType, "可执行文件")
self.setLabelText(
QFileDialog.DialogLabel.FileName,
InterpreterFileDlg.tr("Python Interpreter"),
)
self.setLabelText(
QFileDialog.DialogLabel.FileType, InterpreterFileDlg.tr("Executable File")
)
# 进行一定的文件过滤
# 目前已知的可行方法只有 Windows 下按文件后缀Linux 下似乎不可行
# https://stackoverflow.com/questions/50213049/
if RUNTIME_INFO.platform == Platform.windows:
self.setNameFilters(("可执行文件 (*.exe)", "所有文件 (*)"))
self.setNameFilters(
(
InterpreterFileDlg.tr("Python Interpreter (python.exe)"),
InterpreterFileDlg.tr("Executable Files (*.exe)"),
InterpreterFileDlg.tr("All Files (*)"),
)
)
else:
self.setNameFilters(
(
InterpreterFileDlg.tr("Python Interpreter (python3*)"),
InterpreterFileDlg.tr("All Files (*)"),
)
)
class AboutDlg(QMessageBox):
class AboutDlg(QObjTr, QMessageBox):
"""用于显示关于信息的对话框"""
def __init__(self, parent: Optional[QWidget] = None) -> None:
@ -106,7 +135,7 @@ class AboutDlg(QMessageBox):
super().__init__(parent)
self._about_text: str = ""
self.setWindowTitle("关于")
self.setWindowTitle(AboutDlg.tr("About"))
self.setStandardButtons(QMessageBox.StandardButton.Ok)
self.setTextFormat(Qt.TextFormat.MarkdownText)
self.setText(self.about_text)
@ -124,13 +153,17 @@ class AboutDlg(QMessageBox):
with QtFileOpen(":/Texts/About_Text", encoding="utf-8") as about_file:
self._about_text = about_file.read()
except OSError as e:
warnings.warn(f"无法打开关于文档,错误信息:{e}", RuntimeWarning, stacklevel=1)
self._about_text = "无法打开关于文档,请尝试重新获取本程序。"
warnings.warn(
f"Cannot open About document: {e}", RuntimeWarning, stacklevel=1
)
self._about_text = AboutDlg.tr(
"Can't open the About document, try to reinstall this program."
)
return self._about_text
class PkgBrowserDlg(QDialog):
class PkgBrowserDlg(QObjTr, QDialog):
"""浏览已安装的所有包的对话框"""
def __init__(self, parent: Optional[QWidget] = None) -> None:
@ -148,11 +181,13 @@ class PkgBrowserDlg(QDialog):
def _setup_ui(self) -> None:
"""处理 UI"""
self.setWindowTitle("已安装的包")
self.setWindowTitle(PkgBrowserDlg.tr("Installed Packages"))
self.setWindowIcon(QIcon(QPixmap(":/Icons/Python_128px")))
self.pkg_table.setColumnCount(2)
self.pkg_table.setHorizontalHeaderLabels(["包名", "版本"])
self.pkg_table.setHorizontalHeaderLabels(
[PkgBrowserDlg.tr("Name"), PkgBrowserDlg.tr("Version")]
)
self.pkg_table.horizontalHeader().setSectionResizeMode(
0, QHeaderView.ResizeMode.Stretch
)

View File

@ -13,9 +13,9 @@ from PySide6.QtGui import QDesktopServices, QIcon, QPixmap
from PySide6.QtWidgets import QApplication, QLabel, QMainWindow, QMenuBar, QStatusBar
from ..Constants import RUNTIME_INFO, APP_URLs, AppConstant, Platform
from ..Utilities.qobject_tr import QObjTr
from .center_widget import CenterWidget, WinMacCenterWidget
from .dialog_widgets import AboutDlg
from .pyinstaller_option_widget import PyinstallerOptionTable
def open_url(url: str) -> None:
@ -27,7 +27,7 @@ def open_url(url: str) -> None:
QDesktopServices.openUrl(QUrl(url))
class MainWindow(QMainWindow):
class MainWindow(QObjTr, QMainWindow):
"""
主界面主窗口
"""
@ -64,29 +64,32 @@ class MainWindow(QMainWindow):
def _setup_menu_bar(self) -> None:
"""配置主窗口菜单栏"""
file_menu = self.menu_bar.addMenu("文件(&F)")
file_menu.addAction("打开打包任务") # 暂时只为占位
file_menu.addAction("保存当前打包任务") # 暂时只为占位
file_menu = self.menu_bar.addMenu(MainWindow.tr("&File"))
file_menu.addAction(MainWindow.tr("Import Config From JSON File")) # 暂时只为占位
file_menu.addAction(MainWindow.tr("Export Config To JSON File")) # 暂时只为占位
file_menu.addSeparator()
file_menu.addAction("设置") # 暂时只为占位
file_menu.addAction(MainWindow.tr("&Settings")) # 暂时只为占位
file_menu.addSeparator()
file_menu.addAction("退出(&X)", self.close)
file_menu.addAction(MainWindow.tr("&Exit"), self.close)
help_menu = self.menu_bar.addMenu("帮助(&H)")
help_menu = self.menu_bar.addMenu(MainWindow.tr("&Help"))
help_menu.addAction(
"PyInstaller官方文档",
MainWindow.tr("PyInstaller Documentation"),
lambda: open_url(APP_URLs["Pyinstaller_doc"]),
)
help_menu.addAction(
"PyInstaller选项详情", self.center_widget.pyinstaller_option_table.show
MainWindow.tr("PyInstaller Options Details"),
self.center_widget.pyinstaller_option_table.show,
)
help_menu.addSeparator()
help_menu.addAction("报告Bug", lambda: open_url(APP_URLs["BugTracker"]))
help_menu.addAction(
MainWindow.tr("Report Bugs"), lambda: open_url(APP_URLs["BugTracker"])
)
about_menu = self.menu_bar.addMenu("关于(&A)")
about_menu.addAction("关于本程序", AboutDlg(self).exec)
about_menu.addAction("关于 &Qt", QApplication.aboutQt)
about_menu = self.menu_bar.addMenu(MainWindow.tr("&About"))
about_menu.addAction(MainWindow.tr("About This Program"), AboutDlg(self).exec)
about_menu.addAction(MainWindow.tr("About &Qt"), QApplication.aboutQt)
def _setup_status_bar(self) -> None:
"""配置主窗口状态栏"""

View File

@ -8,7 +8,10 @@
`MultiPkgEditWindow` 继承自 `MultiItemEditWindow`多了一个浏览当前 Python 环境中已安装 Python 包的功能
"""
__all__ = ["MultiItemEditWindow", "MultiPkgEditWindow"]
__all__ = [
"MultiItemEditWindow",
"MultiPkgEditWindow",
]
from typing import Optional
@ -23,10 +26,11 @@ from PySide6.QtWidgets import (
QWidget,
)
from ..Utilities import QObjTr
from .dialog_widgets import PkgBrowserDlg
class MultiItemEditWindow(QWidget):
class MultiItemEditWindow(QObjTr, QWidget):
"""用于添加多个条目的窗口控件,实现如 --hidden-import、--collect-submodules 等功能"""
items_selected = Signal(list) # 用户在添加条目窗口完成所有编辑后,提交的信号.完整数据类型为 list[str]
@ -65,11 +69,11 @@ class MultiItemEditWindow(QWidget):
self.setWindowIcon(QIcon(QPixmap(":/Icons/Py2exe-GUI_icon_72px")))
self.new_btn.setText("新建(&N)")
self.delete_btn.setText("删除(&D)")
self.new_btn.setText(MultiItemEditWindow.tr("&New"))
self.delete_btn.setText(MultiItemEditWindow.tr("&Delete"))
self.ok_btn.setText("确定")
self.cancel_btn.setText("取消")
self.ok_btn.setText(MultiItemEditWindow.tr("&OK"))
self.cancel_btn.setText(MultiItemEditWindow.tr("&Cancel"))
# noinspection DuplicatedCode
def _setup_layout(self) -> None:
@ -185,7 +189,7 @@ class MultiPkgEditWindow(MultiItemEditWindow):
"""处理 UI"""
super()._setup_ui()
self.browse_pkg_button.setText("浏览包(&B)")
self.browse_pkg_button.setText(MultiPkgEditWindow.tr("&Browse packages"))
def _setup_layout(self) -> None:
"""构建与设置布局管理器"""

View File

@ -7,7 +7,10 @@
`PyinstallerOptionTable` 类是用于显示 PyInstaller 命令行选项的表格控件窗口界面有待进一步优化
"""
__all__ = ["load_pyinst_options", "PyinstallerOptionTable"]
__all__ = [
"load_pyinst_options",
"PyinstallerOptionTable",
]
import warnings
@ -16,7 +19,7 @@ from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import QHeaderView, QTableWidget, QTableWidgetItem
from ..Constants import RUNTIME_INFO
from ..Utilities import QtFileOpen
from ..Utilities import QObjTr, QtFileOpen
def load_pyinst_options() -> dict[str, str]:
@ -33,7 +36,7 @@ def load_pyinst_options() -> dict[str, str]:
option_file_text = option_file.read()
except OSError as e:
warnings.warn(
f"PyInstaller Options 加载失败,错误信息:{e}", RuntimeWarning, stacklevel=1
f"Failed to load PyInstaller Options: {e}", RuntimeWarning, stacklevel=1
)
return dict()
@ -57,7 +60,7 @@ def load_pyinst_options() -> dict[str, str]:
return option_dict
class PyinstallerOptionTable(QTableWidget):
class PyinstallerOptionTable(QObjTr, QTableWidget):
"""用于显示 PyInstaller 命令行选项的表格控件"""
def __init__(self) -> None:
@ -68,7 +71,12 @@ class PyinstallerOptionTable(QTableWidget):
self.setMinimumSize(700, 430)
self.setWindowIcon(QPixmap(":/Icons/PyInstaller"))
self.setColumnCount(2)
self.setHorizontalHeaderLabels(["选项", "描述"])
self.setHorizontalHeaderLabels(
[
PyinstallerOptionTable.tr("Option"),
PyinstallerOptionTable.tr("Description"),
]
)
self.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
# 存储选项信息的字典

View File

@ -18,9 +18,10 @@ from PySide6.QtWidgets import (
)
from ..Core.subprocess_tool import SubProcessTool
from ..Utilities import QObjTr
class SubProcessDlg(QDialog):
class SubProcessDlg(QObjTr, QDialog):
"""用于显示子进程信息的对话框"""
def __init__(self, parent: QWidget) -> None:
@ -64,7 +65,7 @@ class SubProcessDlg(QDialog):
if output_type == SubProcessTool.OutputType.STATE:
self.info_label.setText(output_text)
if output_text == "The process is running...":
self.multifunction_btn.setText("取消")
self.multifunction_btn.setText(SubProcessDlg.tr("Cancel"))
elif (
output_type == SubProcessTool.OutputType.STDOUT
@ -74,20 +75,32 @@ class SubProcessDlg(QDialog):
elif output_type == SubProcessTool.OutputType.FINISHED:
if output_text == "0":
self.info_label.setText("打包完成!")
self.multifunction_btn.setText("打开输出位置")
self.info_label.setText(SubProcessDlg.tr("Done!"))
self.multifunction_btn.setText(SubProcessDlg.tr("Open Dist"))
else:
self.info_label.setText(f"运行结束,但有错误发生,退出码为 {output_text}")
self.multifunction_btn.setText("取消")
self.info_label.setText(
SubProcessDlg.tr(
"Execution ends, but an error occurs and the exit code is"
)
+ f"{output_text}"
)
self.multifunction_btn.setText(SubProcessDlg.tr("Cancel"))
elif output_type == SubProcessTool.OutputType.ERROR:
self.info_label.setText("PyInstaller错误")
self.text_browser.append(f"PyInstaller 子进程输出信息:{output_text}")
self.text_browser.append("请检查是否已经安装正确版本的 PyInstaller")
self.multifunction_btn.setText("关闭")
self.info_label.setText(SubProcessDlg.tr("PyInstaller Error!"))
self.text_browser.append(
SubProcessDlg.tr("PyInstaller subprocess output:") + f"{output_text}"
)
self.text_browser.append(
SubProcessDlg.tr(
"Please check if you have installed "
"the correct version of PyInstaller or not."
)
)
self.multifunction_btn.setText(SubProcessDlg.tr("Close"))
elif not isinstance(output_type, SubProcessTool.OutputType):
raise ValueError(f"不支持的输出类型:{output_type}")
raise ValueError(f"Unsupported output type: {output_type}")
def closeEvent(self, event: QCloseEvent) -> None:
"""重写关闭事件,进行收尾清理

View File

@ -10,14 +10,14 @@
import sys
from pathlib import Path
from PySide6.QtCore import Slot
from PySide6.QtCore import QTranslator, Slot
from PySide6.QtGui import QCloseEvent
from PySide6.QtWidgets import QApplication
from .Constants import PyInstOpt
from .Constants import RUNTIME_INFO, PyInstOpt
from .Core import Packaging, PackagingTask
from .Resources import COMPILED_RESOURCES # noqa
from .Utilities import PyEnv, open_dir_in_explorer
from .Utilities import open_dir_in_explorer
from .Widgets import MainWindow, SubProcessDlg
@ -27,17 +27,16 @@ class MainApp(MainWindow):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.current_pyenv: PyEnv
self.packaging_task = PackagingTask(self)
self.packager = Packaging(self)
self.subprocess_dlg = SubProcessDlg(self)
self._connect_slots()
self.status_bar.showMessage("就绪")
self.status_bar.showMessage(MainApp.tr("Ready."))
# def show(self):
# """仅供性能分析使用,切勿取消注释!!!
# """仅供分析启动性能使用,切勿取消注释!!!
# """
#
# super().show()
@ -88,16 +87,16 @@ class MainApp(MainWindow):
"""处理子进程窗口多功能按钮点击信号的槽"""
btn_text = self.subprocess_dlg.multifunction_btn.text()
if btn_text == "取消":
if btn_text == SubProcessDlg.tr("Cancel"):
self.packager.subprocess.abort_process()
self.subprocess_dlg.close()
elif btn_text == "打开输出位置":
elif btn_text == SubProcessDlg.tr("Open Dist"):
script_path: Path = self.packaging_task.using_option[
PyInstOpt.script_path
]
dist_path = script_path.parent / "dist"
open_dir_in_explorer(dist_path)
elif btn_text == "关闭":
elif btn_text == SubProcessDlg.tr("Close"):
self.subprocess_dlg.close()
subprocess_dlg.multifunction_btn.clicked.connect(handle_mul_btn_clicked)
@ -116,6 +115,13 @@ def main() -> None:
"""应用程序主入口函数,便于 Poetry 由此函数级入口构建启动脚本"""
app = QApplication(sys.argv)
# TODO 翻译机制待优化
translator = QTranslator()
if RUNTIME_INFO.language_code == "zh_CN":
translator.load(":/i18n/zh_CN.qm")
app.installTranslator(translator)
window = MainApp()
window.show()
sys.exit(app.exec())