diff --git a/README.md b/README.md
index 8a89f9b..e6b78a0 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-![Py2exe-GUI Logo](docs/source/images/py2exe-gui_logo_big.png)
+![Py2exe-GUI Logo](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/py2exe-gui_logo_big.png)
Easy-to-use Python GUI packaging tool
@@ -24,9 +24,9 @@ English | 简体中文
Py2exe-GUI is an assist tool based on [PySide6](https://doc.qt.io/qtforpython/index.html), designed to provide a
complete yet easy-to-use GUI for [PyInstaller](https://pyinstaller.org/).
-![Screenshot](docs/source/images/Py2exe-GUI_v0.3.0_mainwindow_screenshot.png)
+![Screenshot](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/Py2exe-GUI_v0.3.1_mainwindow_screenshot_en.png)
-![Screenshot](docs/source/images/Py2exe-GUI_v0.2.0_screenshot.png)
+![Screenshot](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/Py2exe-GUI_v0.2.0_screenshot.png)
It has the following features:
@@ -36,11 +36,6 @@ It has the following features:
in each interpreter environment to be packaged.
- Cross-platform, supports Windows, Linux and macOS.
-> Note: As you can see, I am not an English speaker. Py2exe-GUI is currently only available in Simplified Chinese.
-> However, I've reserved some interfaces in the code for internationalization, and the translation is slowly progressing.
-> If you are interested in this project, you can star it. In a few months it will provide full English support and
-> interfaces for translators to provide translations in more languages.
-
## How to install
> Note: Py2exe-GUI is still in the early stages of development, and the distributions provided are *beta versions*.
@@ -112,7 +107,7 @@ the [checks](dev_scripts/check_funcs.py).
## License
-![GPLv3](docs/source/images/gplv3-127x51.png)
+![GPLv3](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/gplv3-127x51.png)
Py2exe-GUI is licensed under the GPLv3 open source license, see the [LICENSE](LICENSE) file for details.
diff --git a/README_zh.md b/README_zh.md
index af22ba7..c2dc6a9 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -1,4 +1,4 @@
-![Py2exe-GUI Logo](docs/source/images/py2exe-gui_logo_big.png)
+![Py2exe-GUI Logo](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/py2exe-gui_logo_big.png)
强大易用的 Python 图形界面打包工具
@@ -23,9 +23,9 @@
Py2exe-GUI 是一个基于 [PySide6](https://doc.qt.io/qtforpython/index.html)
开发的辅助工具,旨在为 [PyInstaller](https://pyinstaller.org/) 提供完整易用的图形化界面,方便用户进行 Python 项目的打包。
-![界面截图](docs/source/images/Py2exe-GUI_v0.3.0_mainwindow_screenshot.png)
+![界面截图](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/Py2exe-GUI_v0.3.0_mainwindow_screenshot.png)
-![界面截图](docs/source/images/Py2exe-GUI_v0.2.0_screenshot.png)
+![界面截图](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/Py2exe-GUI_v0.2.0_screenshot.png)
有如下特性:
@@ -101,7 +101,7 @@ request。请尽可能遵守原有的代码风格,并确保新增代码能通
## 开源许可
-![GPLv3](docs/source/images/gplv3-127x51.png)
+![GPLv3](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/gplv3-127x51.png)
Py2exe-GUI 采用 GPLv3 开源许可证,详情请参见 [LICENSE](LICENSE) 文件。
diff --git a/dev_scripts/build.py b/dev_scripts/build.py
index 85c1231..2d0e46d 100644
--- a/dev_scripts/build.py
+++ b/dev_scripts/build.py
@@ -2,7 +2,6 @@
"""
import subprocess
-from pathlib import Path
from dev_scripts.check_funcs import (
check_license_statement,
@@ -11,63 +10,7 @@ from dev_scripts.check_funcs import (
check_version_num,
)
from dev_scripts.clear_cache import clear_pycache, clear_pyinstaller_dist
-from dev_scripts.path_constants import (
- PROJECT_ROOT,
- README_FILE_LIST,
- RESOURCES_PATH,
- SRC_PATH,
-)
-
-
-def process_md_images(md_file_list: list[Path]) -> None:
- """处理 Markdown 文档中的图片链接
-
- 在构建前替换为 GitHub 图床链接,在构建后替换回本地目录中的路径
-
- :param md_file_list: Markdown 文件列表
- """
-
- md_uri = "docs/source/images/"
- github_uri = (
- "https://github.com/muziing/Py2exe-GUI/raw/main" + "/docs/source/images/"
- )
-
- for md_file in md_file_list:
- with open(md_file, "r+", encoding="UTF-8") as f:
- all_text = f.read()
- if github_uri not in all_text:
- print(f"将 {md_file} 中的本地图片路径替换为GitHub在线路径")
- all_text_new = all_text.replace(md_uri, github_uri)
- else:
- print(f"将 {md_file} 中的GitHub在线路径替换为本地图片路径")
- all_text_new = all_text.replace(github_uri, md_uri)
- f.seek(0)
- f.write(all_text_new)
- # FIXME 会在文件尾部多出来莫名其妙的行
-
-
-def compile_resources() -> int:
- """调用 RCC 工具编译静态资源
-
- :return: rcc 进程返回码
- """
-
- compiled_file_path = RESOURCES_PATH / "COMPILED_RESOURCES.py"
- qrc_file_path = RESOURCES_PATH / "resources.qrc"
- cmd = [
- "pyside6-rcc",
- "-o",
- str(compiled_file_path.absolute()),
- str(qrc_file_path.absolute()),
- ]
- try:
- result = subprocess.run(cmd)
- except subprocess.SubprocessError as e:
- print(f"RCC编译进程错误:{e}")
- raise e
- else:
- print(f"已完成静态资源文件编译,RCC返回码:{result.returncode}。")
- return result.returncode
+from dev_scripts.path_constants import PROJECT_ROOT, SRC_PATH
def export_requirements() -> int:
@@ -102,23 +45,26 @@ def build_py2exe_gui() -> None:
# 准备工作
clear_pyinstaller_dist(SRC_PATH)
clear_pycache(SRC_PATH)
- process_md_images(README_FILE_LIST)
# compile_resources()
export_requirements()
print(f"pre-commit 检查完毕,返回码:{check_pre_commit()}。")
print(f"mypy 检查完毕,返回码:{check_mypy()}。")
# 正式构建
- subprocess.run(["poetry", "build"]) # TODO 处理异常与返回值
-
- # 清理
- process_md_images(README_FILE_LIST)
+ try:
+ result = subprocess.run(["poetry", "build"], check=True)
+ except subprocess.SubprocessError as e:
+ print(f"Poetry build 失败:{e}")
+ raise
+ else:
+ print(f"Poetry build 完毕,返回码:{result.returncode}。")
+ finally:
+ # 清理
+ pass
else:
- print("构建失败,有未通过的检查项")
+ print("有未通过的检查项,不进行构建")
if __name__ == "__main__":
- # process_md_images()
- # compile_resources()
# export_requirements()
build_py2exe_gui()
diff --git a/dev_scripts/path_constants.py b/dev_scripts/path_constants.py
index 3a50770..891b3b5 100644
--- a/dev_scripts/path_constants.py
+++ b/dev_scripts/path_constants.py
@@ -1,15 +1,16 @@
-"""
-开发脚本中使用的相对路径常量
+"""开发脚本中使用的相对路径常量
+
所有脚本应以项目根目录为工作目录运行
"""
from pathlib import Path
-PROJECT_ROOT = Path("../") # 项目根目录
+PROJECT_ROOT = Path(__file__).parent.parent # 项目根目录
SRC_PATH = PROJECT_ROOT / "src" # 源码目录
-SRC_PKG_PATH = SRC_PATH / "py2exe_gui"
+SRC_PKG_PATH = SRC_PATH / "py2exe_gui" # 包目录
RESOURCES_PATH = SRC_PKG_PATH / "Resources" # 静态资源文件目录
COMPILED_RESOURCES = RESOURCES_PATH / "COMPILED_RESOURCES.py" # 编译静态资源文件
+WIDGETS_PATH = SRC_PKG_PATH / "Widgets" # 控件目录
README_FILE_LIST = [
PROJECT_ROOT / "README.md",
PROJECT_ROOT / "README_zh.md",
diff --git a/dev_scripts/pyside6_tools_script.py b/dev_scripts/pyside6_tools_script.py
new file mode 100644
index 0000000..df4bdbe
--- /dev/null
+++ b/dev_scripts/pyside6_tools_script.py
@@ -0,0 +1,85 @@
+"""开发脚本,便于调用 PySide6 提供的各种工具程序
+"""
+
+import subprocess
+
+from dev_scripts.path_constants import (
+ COMPILED_RESOURCES,
+ PROJECT_ROOT,
+ RESOURCES_PATH,
+ SRC_PKG_PATH,
+ WIDGETS_PATH,
+)
+
+
+def compile_resources() -> int:
+ """调用 RCC 工具编译静态资源
+
+ :return: rcc 进程返回码
+ """
+
+ compiled_file_path = COMPILED_RESOURCES
+ qrc_file_path = RESOURCES_PATH / "resources.qrc"
+ cmd = [
+ "pyside6-rcc",
+ "-o",
+ compiled_file_path,
+ qrc_file_path,
+ ]
+
+ try:
+ result = subprocess.run(cmd, cwd=PROJECT_ROOT, check=True)
+ except subprocess.SubprocessError as e:
+ print(f"RCC 编译进程错误:{e}")
+ raise e
+ else:
+ print(f"已完成静态资源文件编译,RCC 返回码:{result.returncode}。")
+ return result.returncode
+
+
+def gen_ts(lang: str = "zh_CN") -> int:
+ """调用 lupdate 工具分析源码,生成 .ts 文本翻译文件
+
+ :param lang: 目标翻译语言代码
+ :return: lupdate 返回码
+ """
+
+ source = [*list(WIDGETS_PATH.glob("**/*.py")), SRC_PKG_PATH / "__main__.py"]
+ target = RESOURCES_PATH / "i18n" / f"{lang.replace('-', '_')}.ts"
+ cmd = ["pyside6-lupdate", *source, "-ts", target]
+
+ try:
+ result = subprocess.run(cmd, cwd=PROJECT_ROOT, check=True)
+ except subprocess.SubprocessError as e:
+ print(f"lupdate 进程错误:{e}")
+ raise
+ else:
+ print(f"已完成文本翻译文件生成,lupdate 返回码:{result.returncode}。")
+ return result.returncode
+
+
+def gen_qm(lang: str = "zh_CN") -> int:
+ """调用 lrelease 工具编译.ts 文本翻译文件
+
+ :param lang: 目标翻译语言代码
+ :return: lrelease 返回码
+ """
+
+ source = RESOURCES_PATH / "i18n" / f"{lang.replace('-', '_')}.ts"
+ target = RESOURCES_PATH / "i18n" / f"{lang.replace('-', '_')}.qm"
+ cmd = ["pyside6-lrelease", source, "-qm", target]
+
+ try:
+ result = subprocess.run(cmd, cwd=PROJECT_ROOT, check=True)
+ except subprocess.SubprocessError as e:
+ print(f"lrelease 进程错误:{e}")
+ raise
+ else:
+ print(f"已完成文本翻译文件编译,lrelease 返回码:{result.returncode}。")
+ return result.returncode
+
+
+if __name__ == "__main__":
+ # compile_resources()
+ gen_ts("zh_CN")
+ # gen_qm("zh_CN")
diff --git a/docs/source/images/Py2exe-GUI_v0.3.1_mainwindow_screenshot_en.png b/docs/source/images/Py2exe-GUI_v0.3.1_mainwindow_screenshot_en.png
new file mode 100644
index 0000000..4b55209
Binary files /dev/null and b/docs/source/images/Py2exe-GUI_v0.3.1_mainwindow_screenshot_en.png differ
diff --git a/poetry.lock b/poetry.lock
index 8f36dab..b200185 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -428,15 +428,20 @@ hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"]
[[package]]
name = "pyinstaller-hooks-contrib"
-version = "2023.11"
+version = "2023.12"
description = "Community maintained hooks for PyInstaller"
optional = false
python-versions = ">=3.7"
files = [
- {file = "pyinstaller-hooks-contrib-2023.11.tar.gz", hash = "sha256:5dd7a8a054a65c19cdaa381cabcfbe76f44d5f88d18214b0c570a0cd139be77f"},
- {file = "pyinstaller_hooks_contrib-2023.11-py2.py3-none-any.whl", hash = "sha256:f2a75dac2968ec81f92dcd3768906f654fa4204bc496126ae8483e87a5d89602"},
+ {file = "pyinstaller-hooks-contrib-2023.12.tar.gz", hash = "sha256:11a9d59d903723dd693e8c10b054f3ea1ecad390623c9fa527c731d715fc5b3f"},
+ {file = "pyinstaller_hooks_contrib-2023.12-py2.py3-none-any.whl", hash = "sha256:6a601a0d783fa725327fc6ac712779475dc8979f639419c7fcd460dd8d0a6d2a"},
]
+[package.dependencies]
+importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""}
+packaging = ">=22.0"
+setuptools = ">=42.0.0"
+
[[package]]
name = "pyside6"
version = "6.6.1"
@@ -560,28 +565,28 @@ files = [
[[package]]
name = "ruff"
-version = "0.1.9"
+version = "0.1.11"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
- {file = "ruff-0.1.9-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e6a212f436122ac73df851f0cf006e0c6612fe6f9c864ed17ebefce0eff6a5fd"},
- {file = "ruff-0.1.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:28d920e319783d5303333630dae46ecc80b7ba294aeffedf946a02ac0b7cc3db"},
- {file = "ruff-0.1.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:104aa9b5e12cb755d9dce698ab1b97726b83012487af415a4512fedd38b1459e"},
- {file = "ruff-0.1.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e63bf5a4a91971082a4768a0aba9383c12392d0d6f1e2be2248c1f9054a20da"},
- {file = "ruff-0.1.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4d0738917c203246f3e275b37006faa3aa96c828b284ebfe3e99a8cb413c8c4b"},
- {file = "ruff-0.1.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:69dac82d63a50df2ab0906d97a01549f814b16bc806deeac4f064ff95c47ddf5"},
- {file = "ruff-0.1.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2aec598fb65084e41a9c5d4b95726173768a62055aafb07b4eff976bac72a592"},
- {file = "ruff-0.1.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:744dfe4b35470fa3820d5fe45758aace6269c578f7ddc43d447868cfe5078bcb"},
- {file = "ruff-0.1.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:479ca4250cab30f9218b2e563adc362bd6ae6343df7c7b5a7865300a5156d5a6"},
- {file = "ruff-0.1.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:aa8344310f1ae79af9ccd6e4b32749e93cddc078f9b5ccd0e45bd76a6d2e8bb6"},
- {file = "ruff-0.1.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:837c739729394df98f342319f5136f33c65286b28b6b70a87c28f59354ec939b"},
- {file = "ruff-0.1.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e6837202c2859b9f22e43cb01992373c2dbfeae5c0c91ad691a4a2e725392464"},
- {file = "ruff-0.1.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:331aae2cd4a0554667ac683243b151c74bd60e78fb08c3c2a4ac05ee1e606a39"},
- {file = "ruff-0.1.9-py3-none-win32.whl", hash = "sha256:8151425a60878e66f23ad47da39265fc2fad42aed06fb0a01130e967a7a064f4"},
- {file = "ruff-0.1.9-py3-none-win_amd64.whl", hash = "sha256:c497d769164df522fdaf54c6eba93f397342fe4ca2123a2e014a5b8fc7df81c7"},
- {file = "ruff-0.1.9-py3-none-win_arm64.whl", hash = "sha256:0e17f53bcbb4fff8292dfd84cf72d767b5e146f009cccd40c2fad27641f8a7a9"},
- {file = "ruff-0.1.9.tar.gz", hash = "sha256:b041dee2734719ddbb4518f762c982f2e912e7f28b8ee4fe1dee0b15d1b6e800"},
+ {file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a7f772696b4cdc0a3b2e527fc3c7ccc41cdcb98f5c80fdd4f2b8c50eb1458196"},
+ {file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:934832f6ed9b34a7d5feea58972635c2039c7a3b434fe5ba2ce015064cb6e955"},
+ {file = "ruff-0.1.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea0d3e950e394c4b332bcdd112aa566010a9f9c95814844a7468325290aabfd9"},
+ {file = "ruff-0.1.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9bd4025b9c5b429a48280785a2b71d479798a69f5c2919e7d274c5f4b32c3607"},
+ {file = "ruff-0.1.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1ad00662305dcb1e987f5ec214d31f7d6a062cae3e74c1cbccef15afd96611d"},
+ {file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4b077ce83f47dd6bea1991af08b140e8b8339f0ba8cb9b7a484c30ebab18a23f"},
+ {file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a88efecec23c37b11076fe676e15c6cdb1271a38f2b415e381e87fe4517f18"},
+ {file = "ruff-0.1.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b25093dad3b055667730a9b491129c42d45e11cdb7043b702e97125bcec48a1"},
+ {file = "ruff-0.1.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:231d8fb11b2cc7c0366a326a66dafc6ad449d7fcdbc268497ee47e1334f66f77"},
+ {file = "ruff-0.1.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:09c415716884950080921dd6237767e52e227e397e2008e2bed410117679975b"},
+ {file = "ruff-0.1.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0f58948c6d212a6b8d41cd59e349751018797ce1727f961c2fa755ad6208ba45"},
+ {file = "ruff-0.1.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:190a566c8f766c37074d99640cd9ca3da11d8deae2deae7c9505e68a4a30f740"},
+ {file = "ruff-0.1.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6464289bd67b2344d2a5d9158d5eb81025258f169e69a46b741b396ffb0cda95"},
+ {file = "ruff-0.1.11-py3-none-win32.whl", hash = "sha256:9b8f397902f92bc2e70fb6bebfa2139008dc72ae5177e66c383fa5426cb0bf2c"},
+ {file = "ruff-0.1.11-py3-none-win_amd64.whl", hash = "sha256:eb85ee287b11f901037a6683b2374bb0ec82928c5cbc984f575d0437979c521a"},
+ {file = "ruff-0.1.11-py3-none-win_arm64.whl", hash = "sha256:97ce4d752f964ba559c7023a86e5f8e97f026d511e48013987623915431c7ea9"},
+ {file = "ruff-0.1.11.tar.gz", hash = "sha256:f9d4d88cb6eeb4dfe20f9f0519bd2eaba8119bde87c3d5065c541dbae2b5a2cb"},
]
[[package]]
@@ -684,4 +689,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
[metadata]
lock-version = "2.0"
python-versions = ">=3.8,<3.13"
-content-hash = "a3e9cf4400a33e8958cc148c575a23017ff036c2dbd7a1185baadf8ad4d5e611"
+content-hash = "73b33938229a7a1fa491c925f43bcd0c9d65b1ba4c0518d145420e254eaf8a9a"
diff --git a/pyproject.toml b/pyproject.toml
index 753e8f2..a7925fa 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,13 +1,14 @@
[tool.poetry]
name = "py2exe-gui"
-version = "0.3.0"
+version = "0.3.1"
description = "GUI for PyInstaller, based on PySide6"
keywords = ["PyInstaller", "GUI", "PySide6"]
authors = ["muzing "]
license = "GPL-3.0-or-later"
readme = ["README.md", "README_zh.md"]
repository = "https://github.com/muziing/Py2exe-GUI"
-exclude = ["src/py2exe_gui/Resources/Icons", "src/py2exe_gui/Resources/Texts"]
+exclude = ["src/py2exe_gui/Resources"]
+include = ["src/py2exe_gui/Resources/COMPILED_RESOURCES.py"]
classifiers = [
"Development Status :: 4 - Beta",
"Operating System :: Microsoft :: Windows",
@@ -32,12 +33,11 @@ PySide6 = "^6.6.0"
pyyaml = "^6.0.1"
[tool.poetry.group.dev]
-
[tool.poetry.group.dev.dependencies]
pre-commit = "^3.5.0"
black = "^23.12.0"
isort = "^5.13.0"
-ruff = "^0.1.9"
+ruff = "^0.1.11"
mypy = "^1.8.0"
pyinstaller = "^6.2.0"
types-pyyaml = "^6.0.12.12"
diff --git a/src/Py2exe-GUI.py b/src/Py2exe-GUI.py
index e2c6bd1..e8bb244 100644
--- a/src/Py2exe-GUI.py
+++ b/src/Py2exe-GUI.py
@@ -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()
diff --git a/src/py2exe_gui/Constants/app_constants.py b/src/py2exe_gui/Constants/app_constants.py
index ecce7d0..a578c30 100644
--- a/src/py2exe_gui/Constants/app_constants.py
+++ b/src/py2exe_gui/Constants/app_constants.py
@@ -24,7 +24,7 @@ class AppConstant:
"""应用程序级的常量"""
NAME = "Py2exe-GUI"
- VERSION = "0.3.0"
+ VERSION = "0.3.1"
AUTHORS = ["muzing "]
LICENSE = "GPL-3.0-or-later"
HOME_PAGE = APP_URLs["HOME_PAGE"]
diff --git a/src/py2exe_gui/Resources/COMPILED_RESOURCES.py b/src/py2exe_gui/Resources/COMPILED_RESOURCES.py
index c031515..fec0379 100644
--- a/src/py2exe_gui/Resources/COMPILED_RESOURCES.py
+++ b/src/py2exe_gui/Resources/COMPILED_RESOURCES.py
@@ -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](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](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\
"
diff --git a/src/py2exe_gui/Resources/Texts/About_en.md b/src/py2exe_gui/Resources/Texts/About_en.md
index a8a5efe..fb8c4b2 100644
--- a/src/py2exe_gui/Resources/Texts/About_en.md
+++ b/src/py2exe_gui/Resources/Texts/About_en.md
@@ -6,4 +6,4 @@ This program is **open source software**: all source code is hosted on [GitHub](
This program is **free software**: you can redistribute it and/or modify it under the terms of the [GNU General Public License](https://github.com/muziing/Py2exe-GUI/blob/main/README.md#license) as published by the Free Software Foundation, either version 3 of the License, or any later version.
-Copyright © 2022-2023 [Muzing \](https://muzing.top/about)
+Copyright © 2022-2024 [Muzing \](https://muzing.top/about)
diff --git a/src/py2exe_gui/Resources/Texts/About_zh.md b/src/py2exe_gui/Resources/Texts/About_zh_CN.md
similarity index 90%
rename from src/py2exe_gui/Resources/Texts/About_zh.md
rename to src/py2exe_gui/Resources/Texts/About_zh_CN.md
index 892ceb4..56eed36 100644
--- a/src/py2exe_gui/Resources/Texts/About_zh.md
+++ b/src/py2exe_gui/Resources/Texts/About_zh_CN.md
@@ -6,4 +6,4 @@ Py2exe-GUI 是一个基于 [PyInstaller](https://pyinstaller.org/) 的图形化
本程序为**自由软件**:在自由软件联盟发布的 [*GNU 通用公共许可协议(第3版或更新的版本)*](https://github.com/muziing/Py2exe-GUI/blob/main/README.md#license) 的约束下,你可以对其进行再发布和/或修改。
-版权所有 © 2022-2023 [Muzing \](https://muzing.top/about)
+版权所有 © 2022-2024 [Muzing \](https://muzing.top/about)
diff --git a/src/py2exe_gui/Resources/Texts/pyinstaller_options_zh.yaml b/src/py2exe_gui/Resources/Texts/pyinstaller_options_zh_CN.yaml
similarity index 100%
rename from src/py2exe_gui/Resources/Texts/pyinstaller_options_zh.yaml
rename to src/py2exe_gui/Resources/Texts/pyinstaller_options_zh_CN.yaml
diff --git a/src/py2exe_gui/Resources/i18n/zh_CN.qm b/src/py2exe_gui/Resources/i18n/zh_CN.qm
new file mode 100644
index 0000000..97675eb
Binary files /dev/null and b/src/py2exe_gui/Resources/i18n/zh_CN.qm differ
diff --git a/src/py2exe_gui/Resources/i18n/zh_CN.ts b/src/py2exe_gui/Resources/i18n/zh_CN.ts
new file mode 100644
index 0000000..1dfa8c8
--- /dev/null
+++ b/src/py2exe_gui/Resources/i18n/zh_CN.ts
@@ -0,0 +1,540 @@
+
+
+
+
+ AboutDlg
+
+
+ About
+ 关于
+
+
+
+ Can't open the About document, try to reinstall this program.
+ 无法打开关于文档,请尝试重新获取本程序。
+
+
+
+ AddDataWindow
+
+
+ Add Files
+ 添加文件
+
+
+
+ &New
+ 新建(&N)
+
+
+
+ &Browse File
+ 浏览文件(&B)
+
+
+
+ Browse &Folder
+ 浏览目录(&F)
+
+
+
+ &Delete
+ 删除(&D)
+
+
+
+ &OK
+ 确认(&O)
+
+
+
+ &Cancel
+ 取消(&C)
+
+
+
+ ArgumentsBrowser
+
+
+ Copy
+ 复制
+
+
+
+ Export
+ 导出
+
+
+
+ CenterWidget
+
+
+ Python entry script path
+ Python 入口脚本路径
+
+
+
+
+ Browse
+ 浏览
+
+
+
+ Python script:
+ 待打包脚本:
+
+
+
+ App Name:
+ 项目名称:
+
+
+
+ Bundled app name
+ 打包的应用程序名称
+
+
+
+ One Folder/ One File:
+ 单目录/单文件:
+
+
+
+ One Folder
+ 打包至单个目录
+
+
+
+ One File
+ 打包至单个文件
+
+
+
+
+ Add Data Files
+ 添加数据文件
+
+
+
+
+ Add Binary Files
+ 添加二进制文件
+
+
+
+ Hidden Import
+ 隐式导入
+
+
+
+ Clean
+ 清理
+
+
+
+ Bundle!
+ 打包!
+
+
+
+ Bundling into one folder.
+ 将打包至单个目录中。
+
+
+
+ Bundling into one file.
+ 将打包至单个文件中。
+
+
+
+ Add data files updated.
+ 添加数据文件已更新。
+
+
+
+ Add binary files updated.
+ 添加二进制文件已更新。
+
+
+
+ Hidden import updated.
+ 隐式导入已更新。
+
+
+
+ Clean cache and remove temporary files before building.
+ 构建前将清除缓存与临时目录。
+
+
+
+ Will not delete cache and temporary files.
+ 不会删除缓存与临时文件。
+
+
+
+ Opened script path:
+ 打开脚本路径:
+
+
+
+ The app name has been set to:
+ 已将项目名设置为:
+
+
+
+
+ Error
+ 错误
+
+
+
+ The selection is not a valid Python script file, please reselect it!
+ 选择的不是有效的Python脚本文件,请重新选择!
+
+
+
+ Warning
+ 警告
+
+
+
+ Pyinstaller doesn't seem to be installed in this Python environment, still continue?
+ 在该 Python 环境中似乎没有安装 Pyinstaller,是否仍要继续?
+
+
+
+ The selection is not a valid Python interpreter, please reselect it!
+ 选择的不是有效的Python解释器,请重新选择!
+
+
+
+ IconFileDlg
+
+
+ Icon Files (*.ico *.icns)
+ 图标文件 (*.ico *.icns)
+
+
+
+ All Files (*)
+ 所有文件 (*)
+
+
+
+ App Icon
+ 图标
+
+
+
+ Icon File
+ 图标文件
+
+
+
+ Open
+ 打开
+
+
+
+ Cancel
+ 取消
+
+
+
+ InterpreterFileDlg
+
+
+ Python Interpreter
+ Python 解释器
+
+
+
+ Executable File
+ 可执行文件
+
+
+
+ Python Interpreter (python.exe)
+ Python 解释器 (python.exe)
+
+
+
+ Executable Files (*.exe)
+ 可执行文件 (*.exe)
+
+
+
+
+ All Files (*)
+ 所有文件 (*)
+
+
+
+ Python Interpreter (python3*)
+ Python 解释器 (python3*)
+
+
+
+ MainApp
+
+
+ Ready.
+ 就绪。
+
+
+
+ MainWindow
+
+
+ &File
+ 文件(&F)
+
+
+
+ Import Config From JSON File
+ 从 JSON 文件中导入配置
+
+
+
+ Export Config To JSON File
+ 导出配置至 JSON 文件
+
+
+
+ &Settings
+ 设置(&S)
+
+
+
+ &Exit
+ 退出(&E)
+
+
+
+ &Help
+ 帮助(&H)
+
+
+
+ PyInstaller Documentation
+ PyInstaller 文档
+
+
+
+ PyInstaller Options Details
+ PyInstaller 选项详情
+
+
+
+ Report Bugs
+ 报告 Bug
+
+
+
+ &About
+ 关于(&A)
+
+
+
+ About This Program
+ 关于此程序
+
+
+
+ About &Qt
+ 关于 &Qt
+
+
+
+ MultiItemEditWindow
+
+
+ &New
+ 新建(&N)
+
+
+
+ &Delete
+ 删除(&D)
+
+
+
+ &OK
+ 确认(&O)
+
+
+
+ &Cancel
+ 取消(&C)
+
+
+
+ MultiPkgEditWindow
+
+
+ &Browse packages
+ 浏览包(&B)
+
+
+
+ PkgBrowserDlg
+
+
+ Installed Packages
+ 已安装的包
+
+
+
+ Name
+ 这里专指软件包的名称
+ 包名
+
+
+
+ Version
+ 版本
+
+
+
+ PyinstallerOptionTable
+
+
+ Option
+ 选项
+
+
+
+ Description
+ 描述
+
+
+
+ ScriptFileDlg
+
+
+ Python Script (*.py *.pyw)
+ Python 脚本文件 (*.py *.pyw)
+
+
+
+ All Files (*)
+ 所有文件 (*)
+
+
+
+ Python Entry File
+ Python入口文件
+
+
+
+ Python File
+ Python 文件
+
+
+
+ Open
+ 打开
+
+
+
+ Cancel
+ 取消
+
+
+
+ SubProcessDlg
+
+
+ Done!
+ 此处专指PyInstaller运行完成。
+ 打包完成!
+
+
+
+
+ Open Dist
+ 打开输出位置
+
+
+
+ Execution ends, but an error occurs and the exit code is
+ 运行结束,但有错误发生,退出码为
+
+
+
+
+
+ Cancel
+ 取消
+
+
+
+ PyInstaller Error!
+ PyInstaller 错误!
+
+
+
+ PyInstaller subprocess output:
+ PyInstaller 子进程输出:
+
+
+
+ Please check if you have installed the correct version of PyInstaller or not.
+ 请检查是否已经安装正确版本的 PyInstaller。
+
+
+
+
+ Close
+ 关闭
+
+
+
+ WinMacCenterWidget
+
+
+ App icon:
+ 应用图标:
+
+
+
+ Path to icon file
+ 图标路径
+
+
+
+ Browse
+ 浏览
+
+
+
+ Open a console window for standard I/O
+ 为标准I/O启用终端
+
+
+
+ Terminal will be enabled.
+ 将为打包程序的 stdio 启用终端。
+
+
+
+ Terminal will not be enabled.
+ 不会为打包程序的 stdio 启用终端。
+
+
+
+ Opened icon path:
+ 打开的图标路径:
+
+
+
+ Error
+ 错误
+
+
+
+ The selection is not a valid icon file, please re-select it!
+ 选择的不是有效的图标文件,请重新选择!
+
+
+
diff --git a/src/py2exe_gui/Resources/resources.qrc b/src/py2exe_gui/Resources/resources.qrc
index d8c3185..fae4b4f 100644
--- a/src/py2exe_gui/Resources/resources.qrc
+++ b/src/py2exe_gui/Resources/resources.qrc
@@ -8,9 +8,12 @@
Icons/poetry-icon_128px.png
Icons/conda-icon_72px.png
-
- Texts/About_zh.md
- Texts/pyinstaller_options_zh.yaml
+
+ i18n/zh_CN.qm
+
+
+ Texts/About_zh_CN.md
+ Texts/pyinstaller_options_zh_CN.yaml
Texts/About_en.md
diff --git a/src/py2exe_gui/Utilities/__init__.py b/src/py2exe_gui/Utilities/__init__.py
index 41c5ba1..e769916 100644
--- a/src/py2exe_gui/Utilities/__init__.py
+++ b/src/py2exe_gui/Utilities/__init__.py
@@ -6,3 +6,4 @@
from .open_qfile import QtFileOpen
from .platform_specifc_funcs import get_sys_python, open_dir_in_explorer
from .python_env import ALL_PY_ENVs, PyEnv
+from .qobject_tr import QObjTr
diff --git a/src/py2exe_gui/Utilities/qobject_tr.py b/src/py2exe_gui/Utilities/qobject_tr.py
new file mode 100644
index 0000000..b182e78
--- /dev/null
+++ b/src/py2exe_gui/Utilities/qobject_tr.py
@@ -0,0 +1,48 @@
+# Licensed under the GPLv3 License: https://www.gnu.org/licenses/gpl-3.0.html
+# For details: https://github.com/muziing/Py2exe-GUI/blob/main/README.md#license
+
+"""自实现 QObject.tr() 方法,使得 PyCharm 等静态检查工具不再报错。
+"""
+
+__all__ = [
+ "QObjTr",
+]
+
+from typing import Optional
+
+from PySide6.QtCore import QCoreApplication
+
+
+class QObjTr:
+ """利用 Python 多继承机制,为任何需要Qt翻译的类提供类方法 `tr()`。
+
+ 只能通过类名调用(形如 CLASSNAME.tr()),不能通过实例调用(形如 self.tr())!对于有继承关系的控件,
+ 通过子类的实例调用 tr() 只能得到子类方法中涉及的字符串,而在父类中涉及的字符串都会丢失。
+
+ 假设有名为 MainWindow 的类,继承自 PySide6.QtWidgets.QMainWindow,需要在其实例属性中设置带翻译的文本,
+ 那么应当这样做:
+
+ 1. 将 MainWindow 同时继承自 QObjTr 和 QMainWindow:`class MainWindow(QObjTr, QMainWindow): ...`
+ 2. 在实例属性中,凡需要翻译的字符串,使用 MainWindow.tr()包裹,比如:`MainWindow.tr("&File")`
+ """
+
+ @classmethod
+ def tr(cls, msg: str, disambiguation: Optional[str] = None, n: int = -1) -> str:
+ """Returns a translated version of `msg`
+
+ **Note: Can only be used as `CLASSNAME.tr()`, not as `self.tr()`!**
+
+ **注意:只能通过类名调用,不能通过实例调用!否则会在涉及到继承的控件中失效。**
+
+ Wrap `QCoreApplication.translate()` to `QObject.tr()`.This will make PyCharm
+ happy. Now you can use `CLASSNAME.tr()` freely. For more details, see:
+
+
+
+ :param msg: Origin messages
+ :param disambiguation: Disambiguate identical text, see Qt Docs for details
+ :param n: Handle plural forms, see Qt Docs for details
+ :return: Translated messages
+ """
+
+ return QCoreApplication.translate(cls.__name__, msg, disambiguation, n)
diff --git a/src/py2exe_gui/Widgets/add_data_widget.py b/src/py2exe_gui/Widgets/add_data_widget.py
index 4d9f83c..9d1c7d9 100644
--- a/src/py2exe_gui/Widgets/add_data_widget.py
+++ b/src/py2exe_gui/Widgets/add_data_widget.py
@@ -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())
diff --git a/src/py2exe_gui/Widgets/arguments_browser.py b/src/py2exe_gui/Widgets/arguments_browser.py
index 12ac2f8..c55ddba 100644
--- a/src/py2exe_gui/Widgets/arguments_browser.py
+++ b/src/py2exe_gui/Widgets/arguments_browser.py
@@ -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"{raw_text} "
-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:
diff --git a/src/py2exe_gui/Widgets/center_widget.py b/src/py2exe_gui/Widgets/center_widget.py
index 0f81681..057dda4 100644
--- a/src/py2exe_gui/Widgets/center_widget.py
+++ b/src/py2exe_gui/Widgets/center_widget.py
@@ -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,
)
diff --git a/src/py2exe_gui/Widgets/dialog_widgets.py b/src/py2exe_gui/Widgets/dialog_widgets.py
index 29329c1..27bd24a 100644
--- a/src/py2exe_gui/Widgets/dialog_widgets.py
+++ b/src/py2exe_gui/Widgets/dialog_widgets.py
@@ -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
)
diff --git a/src/py2exe_gui/Widgets/main_window.py b/src/py2exe_gui/Widgets/main_window.py
index c06e9c1..34e543b 100644
--- a/src/py2exe_gui/Widgets/main_window.py
+++ b/src/py2exe_gui/Widgets/main_window.py
@@ -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:
"""配置主窗口状态栏"""
diff --git a/src/py2exe_gui/Widgets/multi_item_edit_widget.py b/src/py2exe_gui/Widgets/multi_item_edit_widget.py
index e94e090..3e7b33c 100644
--- a/src/py2exe_gui/Widgets/multi_item_edit_widget.py
+++ b/src/py2exe_gui/Widgets/multi_item_edit_widget.py
@@ -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:
"""构建与设置布局管理器"""
diff --git a/src/py2exe_gui/Widgets/pyinstaller_option_widget.py b/src/py2exe_gui/Widgets/pyinstaller_option_widget.py
index e012cca..f7c2c08 100644
--- a/src/py2exe_gui/Widgets/pyinstaller_option_widget.py
+++ b/src/py2exe_gui/Widgets/pyinstaller_option_widget.py
@@ -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)
# 存储选项信息的字典
diff --git a/src/py2exe_gui/Widgets/subprocess_widget.py b/src/py2exe_gui/Widgets/subprocess_widget.py
index b74006e..56ef438 100644
--- a/src/py2exe_gui/Widgets/subprocess_widget.py
+++ b/src/py2exe_gui/Widgets/subprocess_widget.py
@@ -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:
"""重写关闭事件,进行收尾清理
diff --git a/src/py2exe_gui/__init__.py b/src/py2exe_gui/__init__.py
index 0aec820..57f0d6f 100644
--- a/src/py2exe_gui/__init__.py
+++ b/src/py2exe_gui/__init__.py
@@ -7,4 +7,4 @@ designed to provide a complete yet easy-to-use GUI for PyInstaller.
HomePage: https://github.com/muziing/Py2exe-GUI
"""
-__version__ = "0.3.0"
+__version__ = "0.3.1"
diff --git a/src/py2exe_gui/__main__.py b/src/py2exe_gui/__main__.py
index d80a38b..24f2c58 100644
--- a/src/py2exe_gui/__main__.py
+++ b/src/py2exe_gui/__main__.py
@@ -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())