diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6ddcd46..8901264 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,6 +4,17 @@ on: push: tags: - 'v*' + workflow_dispatch: + inputs: + version: + description: 'Manual build version tag (e.g. v2.7.5.dev0)' + required: false + default: 'v2.7.5.dev0' + publish_pypi: + description: 'Publish to PyPI during manual test?' + type: boolean + required: false + default: false env: PROJECT_NAME: qpypack @@ -28,8 +39,8 @@ jobs: - name: Checkout source code uses: actions/checkout@v4 with: - ref: main - fetch-depth: 0 + ref: ${{ github.ref }} + fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v5 @@ -42,33 +53,20 @@ jobs: import re import os - tag = "${{ github.ref_name }}" + tag = "${{ inputs.version || github.ref_name }}" version = tag[1:] if tag.lower().startswith('v') else tag - print(f"Target version to sync: {version}") toml_path = 'pyproject.toml' - if not os.path.exists(toml_path): - raise FileNotFoundError(f"Missing critical configuration: {toml_path}") - - with open(toml_path, 'r', encoding='utf-8') as f: - content = f.read() - new_content = re.sub(r'(version\s*=\s*["\'])[^"\']+(["\'])', f'\\g<1>{version}\\g<2>', content, count=1) - with open(toml_path, 'w', encoding='utf-8') as f: - f.write(new_content) - print("Successfully synchronized pyproject.toml.") + if os.path.exists(toml_path): + with open(toml_path, 'r', encoding='utf-8') as f: content = f.read() + new_content = re.sub(r'(version\s*=\s*["\'])[^"\']+(["\'])', f'\\g<1>{version}\\g<2>', content, count=1) + with open(toml_path, 'w', encoding='utf-8') as f: f.write(new_content) main_path = os.environ['MAIN_SCRIPT'] - if not os.path.exists(main_path): - raise FileNotFoundError(f"Missing critical entrypoint: {main_path}") - - with open(main_path, 'r', encoding='utf-8') as f: - content = f.read() - new_content = re.sub(r'(__version__\s*=\s*["\'])[^"\']+(["\'])', f'\\g<1>{version}\\g<2>', content, count=1) - with open(main_path, 'w', encoding='utf-8') as f: - f.write(new_content) - print(f"Successfully synchronized {main_path}.") - - # 已删除原有 git commit & git push 步骤(避免产生多余 Commit) + if os.path.exists(main_path): + with open(main_path, 'r', encoding='utf-8') as f: content = f.read() + new_content = re.sub(r'(__version__\s*=\s*["\'])[^"\']+(["\'])', f'\\g<1>{version}\\g<2>', content, count=1) + with open(main_path, 'w', encoding='utf-8') as f: f.write(new_content) - name: Install build dependencies if: env.BUILD_PIP_PACKAGE == 'true' @@ -88,37 +86,33 @@ jobs: dist/*.whl dist/*.tar.gz generate_release_notes: true + tag_name: ${{ inputs.version || github.ref_name }} + prerelease: ${{ contains(inputs.version || github.ref_name, 'dev') || contains(inputs.version || github.ref_name, 'rc') || contains(inputs.version || github.ref_name, 'alpha') || contains(inputs.version || github.ref_name, 'beta') }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Publish to PyPI - if: env.BUILD_PIP_PACKAGE == 'true' && env.PUBLISH_TO_PYPI == 'true' + if: env.BUILD_PIP_PACKAGE == 'true' && env.PUBLISH_TO_PYPI == 'true' && (github.event_name == 'push' || inputs.publish_pypi == true) uses: pypa/gh-action-pypi-publish@release/v1 with: skip-existing: true build-binaries: name: Build Standalone for ${{ matrix.os }} (${{ matrix.arch }}) - needs: publish-pypi + needs: publish-pypi runs-on: ${{ matrix.os }} permissions: - contents: write + contents: write strategy: fail-fast: false matrix: include: - os: windows-latest arch: x64 - artifact_name: QPyPack.exe - package_extension: zip - os: macos-14 - arch: arm64 - artifact_name: QPyPack.app - package_extension: zip - - os: ubuntu-latest + arch: arm64 + - os: ubuntu-22.04 arch: x64 - artifact_name: QPyPack - package_extension: tar.gz steps: - name: Checkout source code @@ -133,11 +127,10 @@ jobs: - name: Extract version shell: bash run: | - TAG_NAME=${{ github.ref_name }} + TAG_NAME="${{ inputs.version || github.ref_name }}" VERSION=${TAG_NAME#v} echo "VERSION=$VERSION" >> $GITHUB_ENV - # 确保编译二进制文件前,main.py 中的 __version__ 也被同步为 Tag 版本 - name: Sync version to main.py shell: python run: | @@ -145,84 +138,63 @@ jobs: import os version = os.environ['VERSION'] main_path = os.environ['MAIN_SCRIPT'] - with open(main_path, 'r', encoding='utf-8') as f: - content = f.read() + with open(main_path, 'r', encoding='utf-8') as f: content = f.read() new_content = re.sub(r'(__version__\s*=\s*["\'])[^"\']+(["\'])', f'\\g<1>{version}\\g<2>', content, count=1) - with open(main_path, 'w', encoding='utf-8') as f: - f.write(new_content) - - - name: Generate Windows Version Info File - if: runner.os == 'Windows' - shell: python - run: | - import os - import re - - version = os.environ['VERSION'] - parts = re.findall(r'\d+', version) - v_num = (parts + ['0', '0', '0', '0'])[:4] - v_tuple = ",".join(v_num) - print(f"Windows FileVersion tuple parsed: ({v_tuple})") - - info_content = f""" - VSVersionInfo( - ffi=FixedFileInfo( - filevers=({v_tuple}), - prodvers=({v_tuple}), - mask=0x3f, - flags=0x0, - OS=0x40004, - fileType=0x1, - subtype=0x0, - date=(0,0) - ), - kids=[ - StringFileInfo( - [ - StringTable( - '040904B0', - [ - StringStruct('CompanyName', '${{ env.COMPANY_NAME }}'), - StringStruct('FileDescription', '${{ env.FILE_DESCRIPTION }}'), - StringStruct('FileVersion', '{version}'), - StringStruct('InternalName', '${{ env.EXE_NAME_PREFIX }}'), - StringStruct('LegalCopyright', '${{ env.LEGAL_COPYRIGHT }}'), - StringStruct('OriginalFilename', '${{ env.EXE_NAME_PREFIX }}.exe'), - StringStruct('ProductName', '${{ env.PRODUCT_NAME }}'), - StringStruct('ProductVersion', '{version}') - ] - ) - ] - ), - VarFileInfo([VarStruct('Translation', [1033, 1200])]) - ] - ) - """ - with open('file_version_info.txt', 'w', encoding='utf-8') as f: - f.write(info_content.strip()) + with open(main_path, 'w', encoding='utf-8') as f: f.write(new_content) - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install PySide6 Pillow pyinstaller - - name: Build with PyInstaller (Windows with Version Info) - if: runner.os == 'Windows' + - name: Convert ICO to ICNS (macOS Only) + if: runner.os == 'macOS' + shell: python run: | - pyinstaller --clean --onefile --noconsole --version-file=file_version_info.txt --icon=${{ env.ICON_PATH }} --add-data "${{ env.ICON_PATH }};." --add-data "qpypack/locales;locales" --name="${{ env.EXE_NAME_PREFIX }}_Standalone" ${{ env.MAIN_SCRIPT }} - - pyinstaller --clean --onedir --noconsole --version-file=file_version_info.txt --icon=${{ env.ICON_PATH }} --add-data "${{ env.ICON_PATH }};." --add-data "qpypack/locales;locales" --name="${{ env.EXE_NAME_PREFIX }}_Portable" ${{ env.MAIN_SCRIPT }} + import os + from PIL import Image + img = Image.open(os.environ['ICON_PATH']) + icns_path = 'qpypack/icon.icns' + img.save(icns_path, format='ICNS') + with open(os.environ['GITHUB_ENV'], 'a') as f: + f.write(f"MAC_ICON_PATH={icns_path}\n") - - name: Build with PyInstaller (macOS / Linux) - if: runner.os != 'Windows' + - name: Generate Windows Version Info File + if: runner.os == 'Windows' + shell: python + run: | + import os, re + version = os.environ['VERSION'] + parts = re.findall(r'\d+', version) + v_tuple = ",".join((parts + ['0', '0', '0', '0'])[:4]) + info_content = f""" + VSVersionInfo( + ffi=FixedFileInfo(filevers=({v_tuple}),prodvers=({v_tuple}),mask=0x3f,flags=0x0,OS=0x40004,fileType=0x1,subtype=0x0,date=(0,0)), + kids=[ + StringFileInfo([StringTable('040904B0',[StringStruct('CompanyName', '${{ env.COMPANY_NAME }}'),StringStruct('FileDescription', '${{ env.FILE_DESCRIPTION }}'),StringStruct('FileVersion', '{version}'),StringStruct('InternalName', '${{ env.EXE_NAME_PREFIX }}'),StringStruct('LegalCopyright', '${{ env.LEGAL_COPYRIGHT }}'),StringStruct('OriginalFilename', '${{ env.EXE_NAME_PREFIX }}.exe'),StringStruct('ProductName', '${{ env.PRODUCT_NAME }}'),StringStruct('ProductVersion', '{version}')])]), + VarFileInfo([VarStruct('Translation', [1033, 1200])]) + ] + ) + """ + with open('file_version_info.txt', 'w', encoding='utf-8') as f: f.write(info_content.strip()) + + - name: Build with PyInstaller (All Platforms) shell: bash run: | - if [ "${{ runner.os }}" = "macOS" ]; then - pyinstaller --onefile --noconsole --name="${{ env.EXE_NAME_PREFIX }}_Standalone" --icon=${{ env.ICON_PATH }} --add-data "qpypack/locales:locales" ${{ env.MAIN_SCRIPT }} - pyinstaller --onedir --noconsole --name="${{ env.EXE_NAME_PREFIX }}_Portable" --icon=${{ env.ICON_PATH }} --add-data "qpypack/locales:locales" ${{ env.MAIN_SCRIPT }} + if [ "${{ runner.os }}" = "Windows" ]; then + pyinstaller --clean --onefile --noconsole --version-file=file_version_info.txt --icon=${{ env.ICON_PATH }} --add-data "${{ env.ICON_PATH }};." --add-data "qpypack/locales;locales" --name="${{ env.EXE_NAME_PREFIX }}_Standalone" ${{ env.MAIN_SCRIPT }} + pyinstaller --clean --onedir --noconsole --version-file=file_version_info.txt --icon=${{ env.ICON_PATH }} --add-data "${{ env.ICON_PATH }};." --add-data "qpypack/locales;locales" --name="${{ env.EXE_NAME_PREFIX }}_Portable" ${{ env.MAIN_SCRIPT }} + elif [ "${{ runner.os }}" = "macOS" ]; then + pyinstaller --clean --onedir --noconsole --name="${{ env.EXE_NAME_PREFIX }}" --icon=${{ env.MAC_ICON_PATH }} --add-data "${{ env.ICON_PATH }}:." --add-data "qpypack/locales:locales" ${{ env.MAIN_SCRIPT }} + codesign --force --deep --sign - dist/${{ env.EXE_NAME_PREFIX }}.app else - pyinstaller --onefile --noconsole --name="${{ env.EXE_NAME_PREFIX }}_Standalone" --add-data "qpypack/locales:locales" ${{ env.MAIN_SCRIPT }} - pyinstaller --onedir --noconsole --name="${{ env.EXE_NAME_PREFIX }}_Portable" --add-data "qpypack/locales:locales" ${{ env.MAIN_SCRIPT }} + PYSIDE_PLUGINS=$(python -c "import PySide6, os; print(os.path.join(os.path.dirname(PySide6.__file__), 'Qt', 'plugins'))") + mkdir -p qt_plugins + cp -r "$PYSIDE_PLUGINS/platforms" qt_plugins/ + cp -r "$PYSIDE_PLUGINS/wayland"* qt_plugins/ 2>/dev/null || true + + pyinstaller --clean --noupx --onefile --noconsole --name="${{ env.EXE_NAME_PREFIX }}_Standalone" --icon=${{ env.ICON_PATH }} --add-data "${{ env.ICON_PATH }}:." --add-data "qt_plugins:PySide6/Qt/plugins" --add-data "qpypack/locales:locales" ${{ env.MAIN_SCRIPT }} + pyinstaller --clean --noupx --onedir --noconsole --name="${{ env.EXE_NAME_PREFIX }}_Portable" --icon=${{ env.ICON_PATH }} --add-data "${{ env.ICON_PATH }}:." --add-data "qt_plugins:PySide6/Qt/plugins" --add-data "qpypack/locales:locales" ${{ env.MAIN_SCRIPT }} fi - name: Package Artifact (Windows) @@ -230,39 +202,32 @@ jobs: shell: pwsh run: | $BASE_NAME = "${{ env.EXE_NAME_PREFIX }}-${{ env.VERSION }}-windows-${{ matrix.arch }}" - Compress-Archive -Path "dist/${{ env.EXE_NAME_PREFIX }}_Standalone.exe" -DestinationPath "$BASE_NAME-Standalone.zip" -Force - Compress-Archive -Path "dist/${{ env.EXE_NAME_PREFIX }}_Portable" -DestinationPath "$BASE_NAME-Portable.zip" -Force - name: Package Artifact (macOS / Linux) if: runner.os != 'Windows' shell: bash run: | - VERSION=${{ env.VERSION }} OS_NAME=$(echo "${{ runner.os }}" | tr '[:upper:]' '[:lower:]') - BASE_NAME="${{ env.EXE_NAME_PREFIX }}-${VERSION}-${OS_NAME}-${{ matrix.arch }}" cd dist - if [ "${{ runner.os }}" = "macOS" ]; then - TARGET_STANDALONE="${{ env.EXE_NAME_PREFIX }}_Standalone.app" - TARGET_PORTABLE="${{ env.EXE_NAME_PREFIX }}_Portable.app" + BASE_NAME="${{ env.EXE_NAME_PREFIX }}-${{ env.VERSION }}-${OS_NAME}-${{ matrix.arch }}" + mkdir -p dmg_staging + mv "${{ env.EXE_NAME_PREFIX }}.app" dmg_staging/ + ln -s /Applications dmg_staging/Applications + hdiutil create -volname "${{ env.EXE_NAME_PREFIX }}" -srcfolder dmg_staging -ov -format UDZO "../${BASE_NAME}.dmg" else - TARGET_STANDALONE="${{ env.EXE_NAME_PREFIX }}_Standalone" - TARGET_PORTABLE="${{ env.EXE_NAME_PREFIX }}_Portable" - fi - - if [ "${{ matrix.package_extension }}" = "zip" ]; then - zip -r "../${BASE_NAME}-Standalone.zip" "$TARGET_STANDALONE" - zip -r "../${BASE_NAME}-Portable.zip" "$TARGET_PORTABLE" - else - tar -czf "../${BASE_NAME}-Standalone.tar.gz" "$TARGET_STANDALONE" - tar -czf "../${BASE_NAME}-Portable.tar.gz" "$TARGET_PORTABLE" + BASE_NAME="${{ env.EXE_NAME_PREFIX }}-${{ env.VERSION }}-${OS_NAME}-${{ matrix.arch }}" + tar -czf "../${BASE_NAME}-Standalone.tar.gz" "${{ env.EXE_NAME_PREFIX }}_Standalone" + tar -czf "../${BASE_NAME}-Portable.tar.gz" "${{ env.EXE_NAME_PREFIX }}_Portable" fi - name: Append Standalone Binary to GitHub Release uses: softprops/action-gh-release@v2 with: - files: ${{ env.EXE_NAME_PREFIX }}-*.* + files: ${{ env.EXE_NAME_PREFIX }}-*.* + tag_name: ${{ inputs.version || github.ref_name }} + prerelease: ${{ contains(inputs.version || github.ref_name, 'dev') || contains(inputs.version || github.ref_name, 'rc') || contains(inputs.version || github.ref_name, 'alpha') || contains(inputs.version || github.ref_name, 'beta') }} env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index e278247..3f4b1b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,24 @@ QPyPack 项目的所有重要变更都将记录在此文件中。 --- +## [2.7.5] - 2026-08-06 + +#### 新增 +- **代码签名与时间戳**:新增 Windows / macOS 产物自动数字签名功能,支持 `.pfx` 自签名证书生成与商业证书配置;Windows 签名集成微软、DigiCert、Sectigo 等权威时间戳服务器盖章支持。 +- **macOS DMG 构建**:CI/CD 构建流程支持自动生成 macOS 平台的 `.dmg` 安装包镜像。 + +#### 改进 +- **macOS 默认签名**:macOS 平台默认开启 Ad-hoc 伪签名,解决 M 系列芯片上未签名二进制运行报“应用已损坏”的问题。 +- **跨平台构建打包**:重构 CI/CD 自动化构建流程,优化 Linux 平台 PySide6 插件依赖打包与稳定性。 +- **系统兼容性矩阵**:调整解释器检测逻辑,动态评估并展示各操作系统与架构的兼容性要求。 +- **界面与文案优化**:统一跨平台文件选择框渲染机制;默认开发者更名为“独立开发者”,应用描述更名为“桌面应用程序”。 + +#### 修复 +- **多语言与国际化同步**:补全并同步简体/繁体中文、日、韩、德、法、西、葡、俄等 8+ 种语言的签名日志与文本框右键菜单翻译。 +- **进程资源回收**:优化打包任务异常终止时的进程管道与句柄清理逻辑。 + +--- + ## [2.7.4] - 2026-08-05 #### 新增 diff --git a/CHANGELOG_EN.md b/CHANGELOG_EN.md index ef6e65b..aa9382c 100644 --- a/CHANGELOG_EN.md +++ b/CHANGELOG_EN.md @@ -9,6 +9,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 --- +## [2.7.5] - 2026-08-06 + +#### Added +- **Code Signing & Timestamping**: Added automatic digital signing for Windows / macOS build artifacts, supporting `.pfx` self-signed certificate generation and commercial certificate configuration; integrated timestamp server (TSA) stamping for Windows signatures with support for authoritative providers like Microsoft, DigiCert, and Sectigo. +- **macOS DMG Building**: CI/CD build workflows now support automatically generating `.dmg` installer images for macOS. + +#### Improved +- **macOS Default Signing**: Enabled Ad-hoc signing by default on macOS, resolving the "App is damaged and can't be opened" error when running unsigned binaries on M-series Apple Silicon chips. +- **Cross-Platform Packaging**: Refactored CI/CD automated build workflows, optimizing PySide6 plugin dependency bundling and stability on Linux. +- **OS Support Matrix**: Adjusted interpreter detection logic to dynamically evaluate and display compatibility requirements across operating systems and architectures. +- **UI & Copywriting Enhancements**: Unified cross-platform file dialog rendering mechanics; updated default author to "Independent Developer" and app description to "Desktop Application". + +#### Fixed +- **Localization & i18n Sync**: Completed and synchronized signature log entries and text box context menu translations across 8+ languages (Simplified/Traditional Chinese, Japanese, Korean, German, French, Spanish, Portuguese, Russian, etc.). +- **Process Resource Cleanup**: Optimized process pipe and handle cleanup logic when packaging tasks terminate abnormally. + +--- + ## [2.7.4] - 2026-08-05 #### Added diff --git a/qpypack/locales/de_DE.json b/qpypack/locales/de_DE.json index 78595be..19d8444 100644 --- a/qpypack/locales/de_DE.json +++ b/qpypack/locales/de_DE.json @@ -18,7 +18,6 @@ "Engine": "Engine", "Dependencies": "Abhängigkeiten", "Resources": "Ressourcen", - "Optimization": "Optimierung", "Package Map": "Paket-Zuordnung", "Execution Log": "Ausführungsprotokoll", "Loaded: {filename}": "Geladen: {filename}", @@ -79,7 +78,6 @@ "Output Location": "Ausgabeort der Anwendung", "Preferences & System Behavior": "Einstellungen & Systemverhalten", "Build Engine:": "Build-Engine:", - "Python Interpreter:": "Python-Interpreter:", "Output Name:": "Name der Ausgabedatei:", "App Icon:": "Anwendungssymbol:", "Primary PIP Index:": "Primärer PIP-Spiegelserver:", @@ -139,7 +137,6 @@ "
Python {ver} Platform Matrix:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
Legacy OS Full backward compatibility": "
Python {ver} Unterstützung:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
Legacy OS Vollständige Abwärtskompatibilität", "
Python {ver} Platform Matrix:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux": "
Python {ver} Unterstützung:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux", "
Python {ver} Platform Matrix:
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Auto-detecting and managing C backend compiler": "
Python {ver} Unterstützung:
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Automatische Erkennung und Verwaltung des C-Backend-Compilers", - "
Python Interpreter
Auto-detecting system environment for Windows, macOS & Linux...": "
Python Interpreter
Automatische Systemerkennung...", "[INFO] Build Cancelled.": "[INFO] Build abgebrochen.", "[INFO] Performing pre-flight environment checks...": "[INFO] Führe Vorab-Umgebungsprüfungen durch...", "[INFO] Analyzing source code and project dependencies...": "[INFO] Analysiere Quellcode und Abhängigkeiten...", @@ -274,8 +271,6 @@ "One-Click Install": "Ein-Klick-Installation", "[ERROR] Python installation failed or was cancelled.": "[ERROR] Python-Installation fehlgeschlagen oder abgebrochen.", "System Default ({sys_native})": "Systemstandard ({sys_native})", - "My Studio": "My Studio", - "Python Executable": "Python-Ausführbare", "Invalid syntax": "Ungültige Syntax", "[INFO] Downloading Playwright browsers via mirror: {url}": "[INFO] Lade Playwright-Browser über Mirror herunter: {url}", "[INFO] Retrying Playwright browser download via official CDN...": "[INFO] Wiederhole Download der Playwright-Browser über offizielles CDN...", @@ -291,5 +286,50 @@ "Smaller output size. Recommended for 95% of standard apps.": "Kleinere Ausgabegröße. Empfohlen für 95 % der Standard-Apps.", "Tip: Build failed in Lite Mode. You can try switching to [Compatibility Mode] in Build Settings and rebuild.": "Tipp: Erstellung im Lite-Modus fehlgeschlagen. Versuchen Sie in den [Buildeinstellungen] auf [Kompatibilitätsmodus] zu wechseln.", "Keep Virtual Environment (Faster Rebuilds)": "Virtuelle Umgebung behalten (Schnellere Rebuilds)", - "[INFO] Reusing existing virtual environment...": "[INFO] Bestehende virtuelle Umgebung wird wiederverwendet..." + "[INFO] Reusing existing virtual environment...": "[INFO] Bestehende virtuelle Umgebung wird wiederverwendet...", + "Interpreter:": "Interpreter:", + "Optimization & Security": "Optimierung & Sicherheit", + "Independent Developer": "Unabhängiger Entwickler", + "Desktop Application": "Desktop-Anwendung", + "Code Signing": "Code-Signierung", + "Enable Smart Code Signing": "Digitale Signatur aktivieren", + "Auto-applies digital signature to built app, eliminating 'Unknown Publisher' warning": "Fügt der Anwendung automatisch eine digitale Signatur hinzu, um Warnungen zu vermeiden.", + "Use Custom Commercial Cert (Optional) ▸": "Kommerzielles Zertifikat konfigurieren (Optional) ▸", + "Hide Custom Cert Settings ▾": "Zertifikat-Einstellungen ausblenden ▾", + "Commercial PFX File:": "Kommerzielle PFX-Datei:", + "Cert Password:": "Zertifikatspasswort:", + "[INFO] Applying smart digital signature...": "[INFO] Wende digitale Signatur an...", + "[SUCCESS] Digital signature applied successfully!": "[SUCCESS] Digitale Signatur erfolgreich angewendet!", + "[WARN] Smart signing failed, but build output is retained.": "[WARN] Signierung fehlgeschlagen, Build-Ergebnis bleibt erhalten.", + "Create": "Erstellen", + "Create Self-Signed Cert": "Selbstsigniertes Zertifikat erstellen", + "Certificate Subject (e.g. My Company):": "Zertifikatsaussteller (z. B. Meine Firma):", + "Generate": "Generieren", + "Self-Signed Certificate (*.pfx)": "Selbstsigniertes Zertifikat (*.pfx)", + "Passwords do not match!": "Passwörter stimmen nicht überein!", + "Failed to generate certificate.": "Zertifikatserstellung fehlgeschlagen.", + "Certificate generated successfully!": "Zertifikat erfolgreich erstellt!", + "Only supported on Windows.": "Nur unter Windows unterstützt.", + "Save Certificate": "Zertifikat speichern", + "Error": "Fehler", + "Select .pfx / .p12 certificate file": ".pfx / .p12 Zertifikatsdatei auswählen", + "Certificate password": "Zertifikatspasswort", + "Undo": "Rückgängig", + "Cut": "Ausschneiden", + "Paste": "Einfügen", + "QPyPack Developer": "QPyPack-Entwickler", + "Password cannot be empty!": "Passwort darf nicht leer sein!", + "Recommendation: 6+ chars, alphanumeric, '-' and '_' only. Avoid spaces or Chinese to prevent signing errors.": "Empfehlung: 6+ Zeichen, nur alphanumerisch, '-' und '_'. Keine Leerzeichen.", + "OS Support Matrix:": "BS-Unterstützungsmatrix:", + "Platform Support Matrix:": "Plattform-Unterstützungsmatrix:", + "No Windows 7 Support": "Keine Windows 7-Unterstützung", + "Full backward compatibility": "Vollständige Abwärtskompatibilität", + "Legacy macOS Compatible": "Kompatibel mit älterem macOS", + "Apple Silicon (M1/M2) & Intel": "Unterstützt Apple Silicon (M1/M2) & Intel", + "Apple Silicon (M-Series) & Intel": "Unterstützt Apple Silicon (M-Serie) & Intel", + "Compatibility depends on build environment glibc version.": "Kompatibilität hängt von der glibc-Version ab.", + "* Nuitka Auto-manages C Compiler": "* Nuitka verwaltet C-Compiler automatisch", + "
Interpreter
Auto-detecting system environment and OS support matrix...": "
Interpreter
Automatische System- und BS-Erkennung...", + "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Zeitstempel-Server Zeitüberschreitung, führe lokale schnelle Signierung durch...", + "[INFO] Applied digital signature with timestamp ({tsa})...": "[INFO] Digitale Signatur mit Zeitstempel ({tsa}) erfolgreich angewendet..." } \ No newline at end of file diff --git a/qpypack/locales/es_ES.json b/qpypack/locales/es_ES.json index 7f23ecb..f922f00 100644 --- a/qpypack/locales/es_ES.json +++ b/qpypack/locales/es_ES.json @@ -17,7 +17,6 @@ "Engine": "Motor", "Dependencies": "Dependencias", "Resources": "Recursos", - "Optimization": "Optimización", "Package Map": "Mapeo", "Execution Log": "Registro de Ejecución", "Loaded: {filename}": "Cargado: {filename}", @@ -78,7 +77,6 @@ "Output Location": "Ubicación del archivo ejecutable", "Preferences & System Behavior": "Preferencias y comportamiento", "Build Engine:": "Motor de compilación:", - "Python Interpreter:": "Intérprete de Python:", "Output Name:": "Nombre del ejecutable:", "App Icon:": "Icono de la aplicación:", "Primary PIP Index:": "Índice PIP principal:", @@ -138,7 +136,6 @@ "
Python {ver} Platform Matrix:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
Legacy OS Full backward compatibility": "
Python {ver} Soporte:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
SO Heredado Compatibilidad total hacia atrás", "
Python {ver} Platform Matrix:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux": "
Python {ver} Soporte:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10/11    ✔ macOS 10.9+    ✔ Linux", "
Python {ver} Platform Matrix:
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Auto-detecting and managing C backend compiler": "
Python {ver} Soporte:
✖ Windows 7    ✖ Windows 8/8.1    ✔ Windows 10/11    ✔ macOS 10.13+    ✔ Linux
Nuitka Detectando y gestionando automáticamente el compilador backend C", - "
Python Interpreter
Auto-detecting system environment for Windows, macOS & Linux...": "
Intérprete Python
Detectando automáticamente el entorno del sistema...", "[INFO] Build Cancelled.": "[INFO] Compilación cancelada.", "[INFO] Performing pre-flight environment checks...": "[INFO] Realizando controles de seguridad del entorno...", "[INFO] Analyzing source code and project dependencies...": "[INFO] Analizando el código fuente y las dependencias...", @@ -274,8 +271,6 @@ "One-Click Install": "Instalación con un clic", "[ERROR] Python installation failed or was cancelled.": "[ERROR] La instalación de Python falló o fue cancelada.", "System Default ({sys_native})": "Predeterminado del sistema ({sys_native})", - "My Studio": "My Studio", - "Python Executable": "Ejecutable Python", "Invalid syntax": "Sintaxis no válida", "[INFO] Downloading Playwright browsers via mirror: {url}": "[INFO] Descargando navegadores Playwright vía espejo: {url}", "[INFO] Retrying Playwright browser download via official CDN...": "[INFO] Reintentando la descarga del navegador Playwright a través del CDN oficial...", @@ -292,5 +287,50 @@ "Smaller output size. Recommended for 95% of standard apps.": "Menor tamaño de salida. Recomendado para el 95% de las aplicaciones estándar.", "Tip: Build failed in Lite Mode. You can try switching to [Compatibility Mode] in Build Settings and rebuild.": "Consejo: Error al compilar en modo ligero. Intente cambiar a [Modo de compatibilidad] en la configuración y vuelva a compilar.", "Keep Virtual Environment (Faster Rebuilds)": "Conservar entorno virtual (Reconstrucción más rápida)", - "[INFO] Reusing existing virtual environment...": "[INFO] Reutilizando el entorno virtual existente..." -} + "[INFO] Reusing existing virtual environment...": "[INFO] Reutilizando el entorno virtual existente...", + "Interpreter:": "Intérprete:", + "Optimization & Security": "Optimización y Seguridad", + "Independent Developer": "Desarrollador independiente", + "Desktop Application": "Aplicación de escritorio", + "Code Signing": "Firma de código", + "Enable Smart Code Signing": "Habilitar firma digital", + "Auto-applies digital signature to built app, eliminating 'Unknown Publisher' warning": "Aplica automáticamente una firma digital a la app creada, eliminando la advertencia de 'Editor desconocido'.", + "Use Custom Commercial Cert (Optional) ▸": "Configurar certificado comercial (Opcional) ▸", + "Hide Custom Cert Settings ▾": "Ocultar configuración de certificado ▾", + "Commercial PFX File:": "Archivo PFX comercial:", + "Cert Password:": "Contraseña del certificado:", + "[INFO] Applying smart digital signature...": "[INFO] Aplicando firma digital...", + "[SUCCESS] Digital signature applied successfully!": "[SUCCESS] ¡Firma digital aplicada con éxito!", + "[WARN] Smart signing failed, but build output is retained.": "[WARN] La firma digital falló, pero el ejecutable se ha conservado.", + "Create": "Crear", + "Create Self-Signed Cert": "Crear certificado autosignado", + "Certificate Subject (e.g. My Company):": "Emisor del certificado (ej. Mi Empresa):", + "Generate": "Generar", + "Self-Signed Certificate (*.pfx)": "Certificado autosignado (*.pfx)", + "Passwords do not match!": "¡Las contraseñas no coinciden!", + "Failed to generate certificate.": "Error al generar el certificado.", + "Certificate generated successfully!": "¡Certificado generado con éxito!", + "Only supported on Windows.": "Solo compatible con Windows.", + "Save Certificate": "Guardar certificado", + "Error": "Error", + "Select .pfx / .p12 certificate file": "Seleccionar archivo de certificado .pfx / .p12", + "Certificate password": "Contraseña del certificado", + "Undo": "Deshacer", + "Cut": "Cortar", + "Paste": "Pegar", + "QPyPack Developer": "Desarrollador QPyPack", + "Password cannot be empty!": "¡La contraseña no puede estar vacía!", + "Recommendation: 6+ chars, alphanumeric, '-' and '_' only. Avoid spaces or Chinese to prevent signing errors.": "Recomendación: 6+ caracteres, solo alfanuméricos, '-' y '_'. Evite espacios.", + "OS Support Matrix:": "Matriz de compatibilidad de SO:", + "Platform Support Matrix:": "Matriz de compatibilidad de plataforma:", + "No Windows 7 Support": "Sin soporte para Windows 7", + "Full backward compatibility": "Compatibilidad total hacia atrás", + "Legacy macOS Compatible": "Compatible con macOS heredado", + "Apple Silicon (M1/M2) & Intel": "Soporta Apple Silicon (M1/M2) e Intel", + "Apple Silicon (M-Series) & Intel": "Soporta Apple Silicon (Serie M) e Intel", + "Compatibility depends on build environment glibc version.": "La compatibilidad depende de la versión de glibc del entorno.", + "* Nuitka Auto-manages C Compiler": "* Nuitka gestiona automáticamente el compilador C", + "
Interpreter
Auto-detecting system environment and OS support matrix...": "
Intérprete
Detectando automáticamente el entorno y la matriz de soporte...", + "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Tiempo de espera del servidor de sellado agotado, realizando firma rápida local...", + "[INFO] Applied digital signature with timestamp ({tsa})...": "[INFO] Firma digital aplicada con sello de tiempo ({tsa})..." +} \ No newline at end of file diff --git a/qpypack/locales/fr_FR.json b/qpypack/locales/fr_FR.json index f94e575..9359a0f 100644 --- a/qpypack/locales/fr_FR.json +++ b/qpypack/locales/fr_FR.json @@ -18,7 +18,6 @@ "Engine": "Moteur", "Dependencies": "Dépendances", "Resources": "Ressources", - "Optimization": "Optimisation", "Package Map": "Mappage", "Execution Log": "Journal d'exécution", "Loaded: {filename}": "Chargé : {filename}", @@ -79,7 +78,6 @@ "Output Location": "Emplacement de sortie", "Preferences & System Behavior": "Préférences et comportement", "Build Engine:": "Moteur de compilation :", - "Python Interpreter:": "Interprète Python :", "Output Name:": "Nom de l'exécutable :", "App Icon:": "Icône de l'application :", "Primary PIP Index:": "Index PIP principal :", @@ -139,7 +137,6 @@ "
Python {ver} Platform Matrix:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
Legacy OS Full backward compatibility": "
Support Python {ver} :
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
OS Hérités Rétrocompatibilité totale", "
Python {ver} Platform Matrix:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux": "
Support Python {ver} :
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux", "
Python {ver} Platform Matrix:
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Auto-detecting and managing C backend compiler": "
Support Python {ver} :
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Détection et gestion automatiques du compilateur backend C", - "
Python Interpreter
Auto-detecting system environment for Windows, macOS & Linux...": "
Interprète Python
Détection automatique de l'environnement...", "[INFO] Build Cancelled.": "[INFO] Compilation annulée.", "[INFO] Performing pre-flight environment checks...": "[INFO] Vérifications de l'environnement en cours...", "[INFO] Analyzing source code and project dependencies...": "[INFO] Analyse du code source et des dépendances...", @@ -275,8 +272,6 @@ "One-Click Install": "Installation en un clic", "[ERROR] Python installation failed or was cancelled.": "[ERROR] L'installation de Python a échoué ou a été annulée.", "System Default ({sys_native})": "Par défaut ({sys_native})", - "My Studio": "Mon Studio", - "Python Executable": "Exécutable Python", "Invalid syntax": "Syntaxe invalide", "[INFO] Downloading Playwright browsers via mirror: {url}": "[INFO] Téléchargement des navigateurs Playwright via le miroir : {url}", "[INFO] Retrying Playwright browser download via official CDN...": "[INFO] Nouvelle tentative de téléchargement du navigateur Playwright via le CDN officiel...", @@ -293,5 +288,50 @@ "Smaller output size. Recommended for 95% of standard apps.": "Taille de sortie plus petite. Recommandé pour 95 % des applications standard.", "Tip: Build failed in Lite Mode. You can try switching to [Compatibility Mode] in Build Settings and rebuild.": "Conseil : Échec de la compilation en mode léger. Essayez de passer en [Mode de compatibilité] dans les paramètres et recompiler.", "Keep Virtual Environment (Faster Rebuilds)": "Conserver l'environnement virtuel (Recompilation plus rapide)", - "[INFO] Reusing existing virtual environment...": "[INFO] Réutilisation de l'environnement virtuel existant..." -} + "[INFO] Reusing existing virtual environment...": "[INFO] Réutilisation de l'environnement virtuel existant...", + "Interpreter:": "Interprète :", + "Optimization & Security": "Optimisation et Sécurité", + "Independent Developer": "Développeur indépendant", + "Desktop Application": "Application de bureau", + "Code Signing": "Signature de code", + "Enable Smart Code Signing": "Activer la signature numérique", + "Auto-applies digital signature to built app, eliminating 'Unknown Publisher' warning": "Applique automatiquement une signature numérique pour éliminer l'avertissement 'Éditeur inconnu'.", + "Use Custom Commercial Cert (Optional) ▸": "Configurer un certificat commercial (Optionnel) ▸", + "Hide Custom Cert Settings ▾": "Masquer les paramètres du certificat ▾", + "Commercial PFX File:": "Fichier PFX commercial :", + "Cert Password:": "Mot de passe du certificat :", + "[INFO] Applying smart digital signature...": "[INFO] Application de la signature numérique...", + "[SUCCESS] Digital signature applied successfully!": "[SUCCESS] Signature numérique appliquée avec succès !", + "[WARN] Smart signing failed, but build output is retained.": "[WARN] Échec de la signature, mais le produit compilé est conservé.", + "Create": "Créer", + "Create Self-Signed Cert": "Créer un certificat auto-signé", + "Certificate Subject (e.g. My Company):": "Émetteur du certificat (ex : Ma Société) :", + "Generate": "Générer", + "Self-Signed Certificate (*.pfx)": "Certificat auto-signé (*.pfx)", + "Passwords do not match!": "Les mots de passe ne correspondent pas !", + "Failed to generate certificate.": "Échec de la génération du certificat.", + "Certificate generated successfully!": "Certificat généré avec succès !", + "Only supported on Windows.": "Pris en charge uniquement sur Windows.", + "Save Certificate": "Enregistrer le certificat", + "Error": "Erreur", + "Select .pfx / .p12 certificate file": "Sélectionner un fichier de certificat .pfx / .p12", + "Certificate password": "Mot de passe du certificat", + "Undo": "Annuler", + "Cut": "Couper", + "Paste": "Coller", + "QPyPack Developer": "Développeur QPyPack", + "Password cannot be empty!": "Le mot de passe ne peut pas être vide !", + "Recommendation: 6+ chars, alphanumeric, '-' and '_' only. Avoid spaces or Chinese to prevent signing errors.": "Recommandation : 6+ caractères, alphanumériques, '-' et '_' uniquement.", + "OS Support Matrix:": "Matrice de support des OS :", + "Platform Support Matrix:": "Matrice de support des plateformes :", + "No Windows 7 Support": "Pas de support Windows 7", + "Full backward compatibility": "Rétrocompatibilité totale", + "Legacy macOS Compatible": "Compatible anciens macOS", + "Apple Silicon (M1/M2) & Intel": "Supporte Apple Silicon (M1/M2) & Intel", + "Apple Silicon (M-Series) & Intel": "Supporte Apple Silicon (Série M) & Intel", + "Compatibility depends on build environment glibc version.": "La compatibilité dépend de la version glibc de l'environnement.", + "* Nuitka Auto-manages C Compiler": "* Nuitka gère automatiquement le compilateur C", + "
Interpreter
Auto-detecting system environment and OS support matrix...": "
Interprète
Détection automatique de l'environnement et du support OS...", + "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Délai d'attente du serveur d'horodatage dépassé, signature rapide locale en cours...", + "[INFO] Applied digital signature with timestamp ({tsa})...": "[INFO] Signature numérique appliquée avec horodatage ({tsa})..." +} \ No newline at end of file diff --git a/qpypack/locales/ja_JP.json b/qpypack/locales/ja_JP.json index 567fd66..0f9c76b 100644 --- a/qpypack/locales/ja_JP.json +++ b/qpypack/locales/ja_JP.json @@ -17,7 +17,6 @@ "Engine": "エンジン", "Dependencies": "依存関係", "Resources": "リソース", - "Optimization": "最適化", "Package Map": "パッケージマップ", "Execution Log": "実行ログ", "Loaded: {filename}": "読み込み済み: {filename}", @@ -78,7 +77,6 @@ "Output Location": "出力先", "Preferences & System Behavior": "環境設定と動作", "Build Engine:": "ビルドエンジン:", - "Python Interpreter:": "インタープリター:", "Output Name:": "出力アプリ名:", "App Icon:": "アプリアイコン:", "Primary PIP Index:": "メイン PIP インデックス:", @@ -138,7 +136,6 @@ "
Python {ver} Platform Matrix:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
Legacy OS Full backward compatibility": "
Python {ver} サポート:
✔ Windows 7    ✔ Windows 8/8.1    ✔ Windows 10/11    ✔ macOS 10.9+    ✔ Linux
レガシー OS 完全な後方互換性", "
Python {ver} Platform Matrix:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux": "
Python {ver} サポート:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10/11    ✔ macOS 10.9+    ✔ Linux", "
Python {ver} Platform Matrix:
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Auto-detecting and managing C backend compiler": "
Python {ver} サポート:
✖ Windows 7    ✖ Windows 8/8.1    ✔ Windows 10/11    ✔ macOS 10.13+    ✔ Linux
Nuitka C バックエンドコンパイラを自動検出して管理", - "
Python Interpreter
Auto-detecting system environment for Windows, macOS & Linux...": "
Python インタープリター
システム環境を自動検出中...", "[INFO] Build Cancelled.": "[INFO] ビルドがキャンセルされました。", "[INFO] Performing pre-flight environment checks...": "[INFO] 事前環境チェックを実行中...", "[INFO] Analyzing source code and project dependencies...": "[INFO] ソースコードと依存関係を解析中...", @@ -273,8 +270,6 @@ "One-Click Install": "ワンクリックインストール", "[ERROR] Python installation failed or was cancelled.": "[ERROR] Python のインストールが失敗したか、キャンセルされました。", "System Default ({sys_native})": "システム既定 ({sys_native})", - "My Studio": "My Studio", - "Python Executable": "Python 実行ファイル", "Invalid syntax": "無効な構文", "[INFO] Downloading Playwright browsers via mirror: {url}": "[INFO] ミラーから Playwright ブラウザーをダウンロード中: {url}", "[INFO] Retrying Playwright browser download via official CDN...": "[INFO] 公式 CDN 経由で Playwright ブラウザーのダウンロードを再試行中...", @@ -290,5 +285,50 @@ "Smaller output size. Recommended for 95% of standard apps.": "出力サイズを最小化。一般的なアプリに推奨。", "Tip: Build failed in Lite Mode. You can try switching to [Compatibility Mode] in Build Settings and rebuild.": "ヒント: 軽量モードでのビルドに失敗しました。[ビルド設定] で [互換モード] に切り替えて再ビルドをお試しください。", "Keep Virtual Environment (Faster Rebuilds)": "仮想環境を保持 (高速再ビルド)", - "[INFO] Reusing existing virtual environment...": "[INFO] 既存のローカル仮想環境を再利用中..." + "[INFO] Reusing existing virtual environment...": "[INFO] 既存のローカル仮想環境を再利用中...", + "Interpreter:": "インタープリター:", + "Optimization & Security": "最適化とセキュリティ", + "Independent Developer": "個人開発者", + "Desktop Application": "デスクトップアプリケーション", + "Code Signing": "コード署名", + "Enable Smart Code Signing": "デジタル署名を有効化", + "Auto-applies digital signature to built app, eliminating 'Unknown Publisher' warning": "生成されたアプリにデジタル署名を自動適用し、「不明な発行元」警告を回避します。", + "Use Custom Commercial Cert (Optional) ▸": "商用証明書の設定 (オプション) ▸", + "Hide Custom Cert Settings ▾": "証明書の詳細設定を折りたたむ ▾", + "Commercial PFX File:": "商用 PFX ファイル:", + "Cert Password:": "証明書パスワード:", + "[INFO] Applying smart digital signature...": "[INFO] アプリケーションにデジタル署名を適用中...", + "[SUCCESS] Digital signature applied successfully!": "[SUCCESS] デジタル署名が正常に適用されました!", + "[WARN] Smart signing failed, but build output is retained.": "[WARN] デジタル署名に失敗しましたが、ビルド成果物は保持されます。", + "Create": "作成", + "Create Self-Signed Cert": "自己署名証明書の作成", + "Certificate Subject (e.g. My Company):": "証明書の発行者 (例: My Company):", + "Generate": "生成", + "Self-Signed Certificate (*.pfx)": "自己署名証明書 (*.pfx)", + "Passwords do not match!": "パスワードが一致しません!", + "Failed to generate certificate.": "証明書の生成に失敗しました。", + "Certificate generated successfully!": "証明書が正常に生成されました!", + "Only supported on Windows.": "Windows 環境でのみサポートされています。", + "Save Certificate": "証明書を保存", + "Error": "エラー", + "Select .pfx / .p12 certificate file": ".pfx / .p12 形式の証明書を選択してください", + "Certificate password": "証明書のパスワード", + "Undo": "元に戻す", + "Cut": "切り取り", + "Paste": "貼り付け", + "QPyPack Developer": "QPyPack 開発者", + "Password cannot be empty!": "パスワードを入力してください!", + "Recommendation: 6+ chars, alphanumeric, '-' and '_' only. Avoid spaces or Chinese to prevent signing errors.": "推奨: 6文字以上の半角英数字、'-'、'_' のみ。スペースや全角文字は避けてください。", + "OS Support Matrix:": "OS サポート状況:", + "Platform Support Matrix:": "プラットフォームサポート:", + "No Windows 7 Support": "Windows 7 未対応", + "Full backward compatibility": "旧 OS 互換", + "Legacy macOS Compatible": "旧版 macOS 互換", + "Apple Silicon (M1/M2) & Intel": "Apple Silicon (M1/M2) および Intel 対応", + "Apple Silicon (M-Series) & Intel": "Apple Silicon (Mシリーズ) および Intel 対応", + "Compatibility depends on build environment glibc version.": "互換性は現在のシステムの glibc バージョンに依存します。", + "* Nuitka Auto-manages C Compiler": "* Nuitka が C コンパイラを自動管理", + "
Interpreter
Auto-detecting system environment and OS support matrix...": "
インタープリター
システム環境と OS サポート状況を自動検出中...", + "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] タイムスタンプサーバー接続タイムアウト。ローカル高速署名を実行します...", + "[INFO] Applied digital signature with timestamp ({tsa})...": "[INFO] タイムスタンプサーバー ({tsa}) 経由でデジタル署名を適用しました..." } \ No newline at end of file diff --git a/qpypack/locales/ko_KR.json b/qpypack/locales/ko_KR.json index f1ff4b4..9b0fd69 100644 --- a/qpypack/locales/ko_KR.json +++ b/qpypack/locales/ko_KR.json @@ -18,7 +18,6 @@ "Engine": "엔진", "Dependencies": "의존성", "Resources": "리소스", - "Optimization": "최적화", "Package Map": "패키지 매핑", "Execution Log": "실행 기록", "Loaded: {filename}": "로드 완료: {filename}", @@ -79,7 +78,6 @@ "Output Location": "결과물 출력 위치", "Preferences & System Behavior": "환경 설정 및 동작", "Build Engine:": "빌드 엔진:", - "Python Interpreter:": "Python 인터프리터:", "Output Name:": "출력 파일 이름:", "App Icon:": "애플리케이션 아이콘:", "Primary PIP Index:": "기본 PIP 인덱스:", @@ -138,7 +136,6 @@ "
Python {ver} Platform Matrix:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
Legacy OS Full backward compatibility": "
Python {ver} 지원:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
레거시 OS 완벽한 하위 호환성", "
Python {ver} Platform Matrix:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux": "
Python {ver} 지원:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux", "
Python {ver} Platform Matrix:
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Auto-detecting and managing C backend compiler": "
Python {ver} 지원:
✖ Windows 7    ✖ Windows 8/8.1    ✔ Windows 10/11    ✔ macOS 10.13+    ✔ Linux
Nuitka C 백엔드 컴파일러 자동 감지 및 관리 중", - "
Python Interpreter
Auto-detecting system environment for Windows, macOS & Linux...": "
Python 인터프리터
시스템 환경 자동 감지 중...", "[INFO] Build Cancelled.": "[INFO] 빌드가 취소되었습니다.", "[INFO] Performing pre-flight environment checks...": "[INFO] 환경 사전 점검 수행 중...", "[INFO] Analyzing source code and project dependencies...": "[INFO] 소스 코드 및 의존성 분석 중...", @@ -274,8 +271,6 @@ "One-Click Install": "원클릭 설치", "[ERROR] Python installation failed or was cancelled.": "[ERROR] Python 설치가 실패했거나 취소되었습니다.", "System Default ({sys_native})": "시스템 기본값 ({sys_native})", - "My Studio": "My Studio", - "Python Executable": "Python 실행 파일", "Invalid syntax": "잘못된 구문", "[INFO] Downloading Playwright browsers via mirror: {url}": "[INFO] 미러를 통해 Playwright 브라우저를 다운로드하는 중: {url}", "[INFO] Retrying Playwright browser download via official CDN...": "[INFO] 공식 CDN을 통해 Playwright 브라우저 다운로드를 재시도하는 중...", @@ -292,5 +287,50 @@ "Smaller output size. Recommended for 95% of standard apps.": "최소 출력 용량. 95%의 일반 앱에 권장.", "Tip: Build failed in Lite Mode. You can try switching to [Compatibility Mode] in Build Settings and rebuild.": "팁: 경량 모드에서 빌드에 실패했습니다. [빌드 설정]에서 [호환 모드]로 전환 후 다시 시도해 보세요.", "Keep Virtual Environment (Faster Rebuilds)": "가상 환경 유지 (빠른 재빌드)", - "[INFO] Reusing existing virtual environment...": "[INFO] 기존 로컬 가상 환경 재사용 중..." + "[INFO] Reusing existing virtual environment...": "[INFO] 기존 로컬 가상 환경 재사용 중...", + "Interpreter:": "인터프리터:", + "Optimization & Security": "최적화 및 보안", + "Independent Developer": "독립 개발자", + "Desktop Application": "데스크톱 애플리케이션", + "Code Signing": "코드 서명", + "Enable Smart Code Signing": "디지털 서명 활성화", + "Auto-applies digital signature to built app, eliminating 'Unknown Publisher' warning": "생성된 앱에 디지털 서명을 자동으로 적용하여 '알 수 없는 게시자' 경고를 방지합니다.", + "Use Custom Commercial Cert (Optional) ▸": "상용 디지털 인증서 구성 (선택 사항) ▸", + "Hide Custom Cert Settings ▾": "인증서 고급 설정 접기 ▾", + "Commercial PFX File:": "상용 PFX 파일:", + "Cert Password:": "인증서 비밀번호:", + "[INFO] Applying smart digital signature...": "[INFO] 애플리케이션에 디지털 서명 적용 중...", + "[SUCCESS] Digital signature applied successfully!": "[SUCCESS] 디지털 서명이 성공적으로 적용되었습니다!", + "[WARN] Smart signing failed, but build output is retained.": "[WARN] 디지털 서명 실패, 결과물은 정상적으로 보존됩니다.", + "Create": "생성", + "Create Self-Signed Cert": "자체 서명 인증서 생성", + "Certificate Subject (e.g. My Company):": "인증서 발급자 (예: My Company):", + "Generate": "생성", + "Self-Signed Certificate (*.pfx)": "자체 서명 인증서 (*.pfx)", + "Passwords do not match!": "비밀번호가 일치하지 않습니다!", + "Failed to generate certificate.": "인증서 생성 실패.", + "Certificate generated successfully!": "인증서가 성공적으로 생성되었습니다!", + "Only supported on Windows.": "Windows 환경에서만 지원됩니다.", + "Save Certificate": "인증서 저장", + "Error": "오류", + "Select .pfx / .p12 certificate file": ".pfx / .p12 형식의 인증서 파일을 선택하세요", + "Certificate password": "인증서 비밀번호", + "Undo": "실행 취소", + "Cut": "잘라내기", + "Paste": "붙여넣기", + "QPyPack Developer": "QPyPack 개발자", + "Password cannot be empty!": "비밀번호를 입력해야 합니다!", + "Recommendation: 6+ chars, alphanumeric, '-' and '_' only. Avoid spaces or Chinese to prevent signing errors.": "권장: 6자 이상, 영문자, 숫자, '-' 및 '_'만 사용. 공백이나 특수문자 제외.", + "OS Support Matrix:": "OS 지원 현황:", + "Platform Support Matrix:": "플랫폼 지원:", + "No Windows 7 Support": "Windows 7 미지원", + "Full backward compatibility": "구형 OS 호환", + "Legacy macOS Compatible": "구형 macOS 호환", + "Apple Silicon (M1/M2) & Intel": "Apple Silicon (M1/M2) 및 Intel 지원", + "Apple Silicon (M-Series) & Intel": "Apple Silicon (M 시리즈) 및 Intel 지원", + "Compatibility depends on build environment glibc version.": "호환성은 현재 시스템의 glibc 버전에 따라 달라집니다.", + "* Nuitka Auto-manages C Compiler": "* Nuitka가 C 컴파일러를 자동으로 관리함", + "
Interpreter
Auto-detecting system environment and OS support matrix...": "
인터프리터
시스템 환경 및 OS 지원 현황 자동 감지 중...", + "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] 타임스탬프 서버 연결 시간 초과, 로컬 빠른 서명을 진행합니다...", + "[INFO] Applied digital signature with timestamp ({tsa})...": "[INFO] 타임스탬프 서버({tsa})를 통해 디지털 서명을 완료했습니다..." } \ No newline at end of file diff --git a/qpypack/locales/pt_BR.json b/qpypack/locales/pt_BR.json index 36a9df3..edb4f34 100644 --- a/qpypack/locales/pt_BR.json +++ b/qpypack/locales/pt_BR.json @@ -17,7 +17,6 @@ "Engine": "Motor", "Dependencies": "Dependências", "Resources": "Recursos", - "Optimization": "Otimização", "Package Map": "Mapeamento", "Execution Log": "Log de Execução", "Loaded: {filename}": "Carregado: {filename}", @@ -78,7 +77,6 @@ "Output Location": "Local de saída", "Preferences & System Behavior": "Preferências e comportamento", "Build Engine:": "Motor de compilação:", - "Python Interpreter:": "Intérprete Python:", "Output Name:": "Nome do executável:", "App Icon:": "Ícone do aplicativo:", "Primary PIP Index:": "Servidor PIP principal:", @@ -138,7 +136,6 @@ "
Python {ver} Platform Matrix:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
Legacy OS Full backward compatibility": "
Python {ver} Suporte:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
SO Legado Compatibilidade total", "
Python {ver} Platform Matrix:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux": "
Python {ver} Suporte:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux", "
Python {ver} Platform Matrix:
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Auto-detecting and managing C backend compiler": "
Python {ver} Suporte:
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Detectando e gerenciando automaticamente o compilador backend C", - "
Python Interpreter
Auto-detecting system environment for Windows, macOS & Linux...": "
Intérprete Python
Detectando ambiente do sistema...", "[INFO] Build Cancelled.": "[INFO] Compilação cancelada.", "[INFO] Performing pre-flight environment checks...": "[INFO] Realizando verificações do ambiente...", "[INFO] Analyzing source code and project dependencies...": "[INFO] Analisando código fonte e dependências...", @@ -273,8 +270,6 @@ "One-Click Install": "Instalação com Um Clique", "[ERROR] Python installation failed or was cancelled.": "[ERROR] A instalação do Python falhou ou foi cancelada.", "System Default ({sys_native})": "Padrão do Sistema ({sys_native})", - "My Studio": "My Studio", - "Python Executable": "Executável Python", "Invalid syntax": "Sintaxe inválida", "[INFO] Downloading Playwright browsers via mirror: {url}": "[INFO] Baixando navegadores Playwright via espelho: {url}", "[INFO] Retrying Playwright browser download via official CDN...": "[INFO] Tentando novamente baixar os navegadores Playwright via CDN oficial...", @@ -290,5 +285,50 @@ "Smaller output size. Recommended for 95% of standard apps.": "Menor tamanho de saída. Recomendado para 95% dos aplicativos padrão.", "Tip: Build failed in Lite Mode. You can try switching to [Compatibility Mode] in Build Settings and rebuild.": "Dica: Falha ao compilar no Modo Leve. Tente alternar para o [Modo de Compatibilidade] nas Configurações e recompilar.", "Keep Virtual Environment (Faster Rebuilds)": "Manter ambiente virtual (Recompilação mais rápida)", - "[INFO] Reusing existing virtual environment...": "[INFO] Reutilizando o ambiente virtual existente..." -} + "[INFO] Reusing existing virtual environment...": "[INFO] Reutilizando o ambiente virtual existente...", + "Interpreter:": "Intérprete:", + "Optimization & Security": "Otimização e Segurança", + "Independent Developer": "Desenvolvedor Independente", + "Desktop Application": "Aplicativo de Trabalho", + "Code Signing": "Assinatura de Código", + "Enable Smart Code Signing": "Habilitar Assinatura Digital", + "Auto-applies digital signature to built app, eliminating 'Unknown Publisher' warning": "Aplica automaticamente assinatura digital ao app, eliminando o aviso de 'Editor Desconhecido'.", + "Use Custom Commercial Cert (Optional) ▸": "Configurar Certificado Comercial (Opcional) ▸", + "Hide Custom Cert Settings ▾": "Ocultar Configurações do Certificado ▾", + "Commercial PFX File:": "Arquivo PFX Comercial:", + "Cert Password:": "Senha do Certificado:", + "[INFO] Applying smart digital signature...": "[INFO] Aplicando assinatura digital...", + "[SUCCESS] Digital signature applied successfully!": "[SUCCESS] Assinatura digital aplicada com sucesso!", + "[WARN] Smart signing failed, but build output is retained.": "[WARN] Assinatura digital falhou, mas o executável foi mantido.", + "Create": "Criar", + "Create Self-Signed Cert": "Criar Certificado Autoassinado", + "Certificate Subject (e.g. My Company):": "Emissor do Certificado (ex: Minha Empresa):", + "Generate": "Gerar", + "Self-Signed Certificate (*.pfx)": "Certificado Autoassinado (*.pfx)", + "Passwords do not match!": "As senhas não coincidem!", + "Failed to generate certificate.": "Falha ao gerar o certificado.", + "Certificate generated successfully!": "Certificado gerado com sucesso!", + "Only supported on Windows.": "Suportado apenas no Windows.", + "Save Certificate": "Salvar Certificado", + "Error": "Erro", + "Select .pfx / .p12 certificate file": "Selecionar arquivo de certificado .pfx / .p12", + "Certificate password": "Senha do certificado", + "Undo": "Desfazer", + "Cut": "Recortar", + "Paste": "Colar", + "QPyPack Developer": "Desenvolvedor QPyPack", + "Password cannot be empty!": "A senha não pode estar vazia!", + "Recommendation: 6+ chars, alphanumeric, '-' and '_' only. Avoid spaces or Chinese to prevent signing errors.": "Recomendação: 6+ caracteres, apenas alfanuméricos, '-' e '_'. Evite espaços.", + "OS Support Matrix:": "Matriz de Suporte a SO:", + "Platform Support Matrix:": "Matriz de Suporte a Plataforma:", + "No Windows 7 Support": "Sem Suporte ao Windows 7", + "Full backward compatibility": "Compatibilidade total com versões anteriores", + "Legacy macOS Compatible": "Compatível com macOS legado", + "Apple Silicon (M1/M2) & Intel": "Suporta Apple Silicon (M1/M2) e Intel", + "Apple Silicon (M-Series) & Intel": "Suporta Apple Silicon (Série M) e Intel", + "Compatibility depends on build environment glibc version.": "A compatibilidade depende da versão da glibc do ambiente.", + "* Nuitka Auto-manages C Compiler": "* Nuitka gerencia o compilador C automaticamente", + "
Interpreter
Auto-detecting system environment and OS support matrix...": "
Intérprete
Detectando automaticamente o ambiente e matriz de suporte...", + "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Tempo limite do servidor de carimbo esgotado, realizando assinatura rápida local...", + "[INFO] Applied digital signature with timestamp ({tsa})...": "[INFO] Assinatura digital aplicada com carimbo de data/hora ({tsa})..." +} \ No newline at end of file diff --git a/qpypack/locales/ru_RU.json b/qpypack/locales/ru_RU.json index 215a853..b52c521 100644 --- a/qpypack/locales/ru_RU.json +++ b/qpypack/locales/ru_RU.json @@ -17,7 +17,6 @@ "Engine": "Движок", "Dependencies": "Зависимости", "Resources": "Ресурсы", - "Optimization": "Оптимизация", "Package Map": "Сопоставление", "Execution Log": "Журнал работы", "Loaded: {filename}": "Загружено: {filename}", @@ -78,7 +77,6 @@ "Output Location": "Расположение файла", "Preferences & System Behavior": "Предпочтения и поведение", "Build Engine:": "Движок сборки:", - "Python Interpreter:": "Интерпретатор Python:", "Output Name:": "Имя файла:", "App Icon:": "Иконка:", "Primary PIP Index:": "Основное зеркало PIP:", @@ -138,7 +136,6 @@ "
Python {ver} Platform Matrix:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
Legacy OS Full backward compatibility": "
Python {ver} Поддержка:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
Устаревшая ОС Полная совместимость", "
Python {ver} Platform Matrix:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux": "
Python {ver} Поддержка:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux", "
Python {ver} Platform Matrix:
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Auto-detecting and managing C backend compiler": "
Python {ver} Поддержка:
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Автоопределение и управление C-компилятором", - "
Python Interpreter
Auto-detecting system environment for Windows, macOS & Linux...": "
Интерпретатор Python
Автоопределение среды...", "[INFO] Build Cancelled.": "[INFO] Сборка отменена.", "[INFO] Performing pre-flight environment checks...": "[INFO] Выполнение проверок среды...", "[INFO] Analyzing source code and project dependencies...": "[INFO] Анализ исходного кода и зависимостей...", @@ -274,8 +271,6 @@ "One-Click Install": "Установка в один клик", "[ERROR] Python installation failed or was cancelled.": "[ERROR] Установка Python не удалась или была отменена.", "System Default ({sys_native})": "Системный ({sys_native})", - "My Studio": "My Studio", - "Python Executable": "Исполняемый файл Python", "Invalid syntax": "Неверный синтаксис", "[INFO] Downloading Playwright browsers via mirror: {url}": "[INFO] Загрузка браузеров Playwright через зеркало: {url}", "[INFO] Retrying Playwright browser download via official CDN...": "[INFO] Повторная попытка загрузки браузера Playwright через официальный CDN...", @@ -291,5 +286,50 @@ "Smaller output size. Recommended for 95% of standard apps.": "Меньший размер файла. Рекомендуется для 95% стандартных приложений.", "Tip: Build failed in Lite Mode. You can try switching to [Compatibility Mode] in Build Settings and rebuild.": "Совет: Сборка в облегченном режиме не удалась. Попробуйте переключиться на [Режим совместимости] в настройках и повторить сборку.", "Keep Virtual Environment (Faster Rebuilds)": "Сохранять виртуальное окружение (Ускоряет пересборку)", - "[INFO] Reusing existing virtual environment...": "[INFO] Повторное использование существующего виртуального окружения..." + "[INFO] Reusing existing virtual environment...": "[INFO] Повторное использование существующего виртуального окружения...", + "Interpreter:": "Интерпретатор:", + "Optimization & Security": "Оптимизация и безопасность", + "Independent Developer": "Независимый разработчик", + "Desktop Application": "Настольное приложение", + "Code Signing": "Подпись кода", + "Enable Smart Code Signing": "Включить цифровую подпись", + "Auto-applies digital signature to built app, eliminating 'Unknown Publisher' warning": "Автоматически подписывает приложение, устраняя предупреждение о «Неизвестном издателе».", + "Use Custom Commercial Cert (Optional) ▸": "Настроить коммерческий сертификат (Опционально) ▸", + "Hide Custom Cert Settings ▾": "Скрыть настройки сертификата ▾", + "Commercial PFX File:": "Коммерческий файл PFX:", + "Cert Password:": "Пароль сертификата:", + "[INFO] Applying smart digital signature...": "[INFO] Применение цифровой подписи...", + "[SUCCESS] Digital signature applied successfully!": "[SUCCESS] Цифровая подпись успешно применена!", + "[WARN] Smart signing failed, but build output is retained.": "[WARN] Подпись не удалась, но исполняемый файл сохранен.", + "Create": "Создать", + "Create Self-Signed Cert": "Создать самоподписанный сертификат", + "Certificate Subject (e.g. My Company):": "Издатель сертификата (напр. Моя Компания):", + "Generate": "Сгенерировать", + "Self-Signed Certificate (*.pfx)": "Самоподписанный сертификат (*.pfx)", + "Passwords do not match!": "Пароли не совпадают!", + "Failed to generate certificate.": "Не удалось сгенерировать сертификат.", + "Certificate generated successfully!": "Сертификат успешно сгенерирован!", + "Only supported on Windows.": "Поддерживается только в Windows.", + "Save Certificate": "Сохранить сертификат", + "Error": "Ошибка", + "Select .pfx / .p12 certificate file": "Выберите файл сертификата .pfx / .p12", + "Certificate password": "Пароль сертификата", + "Undo": "Отменить", + "Cut": "Вырезать", + "Paste": "Вставить", + "QPyPack Developer": "Разработчик QPyPack", + "Password cannot be empty!": "Пароль не может быть пустым!", + "Recommendation: 6+ chars, alphanumeric, '-' and '_' only. Avoid spaces or Chinese to prevent signing errors.": "Рекомендация: от 6 символов, только латиница, цифры, '-' и '_'. Без пробелов.", + "OS Support Matrix:": "Матрица поддержки ОС:", + "Platform Support Matrix:": "Матрица поддержки платформ:", + "No Windows 7 Support": "Без поддержки Windows 7", + "Full backward compatibility": "Полная обратная совместимость", + "Legacy macOS Compatible": "Совместимо со старыми macOS", + "Apple Silicon (M1/M2) & Intel": "Поддержка Apple Silicon (M1/M2) и Intel", + "Apple Silicon (M-Series) & Intel": "Поддержка Apple Silicon (Серия M) и Intel", + "Compatibility depends on build environment glibc version.": "Совместимость зависит от версии glibc среды сборки.", + "* Nuitka Auto-manages C Compiler": "* Nuitka автоматически управляет компилятором C", + "
Interpreter
Auto-detecting system environment and OS support matrix...": "
Интерпретатор
Автоопределение среды и матрицы поддержки ОС...", + "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] Превышено время ожидания сервера штампа времени, выполняется локальная быстрая подпись...", + "[INFO] Applied digital signature with timestamp ({tsa})...": "[INFO] Цифровая подпись со штампом времени ({tsa}) успешно применена..." } \ No newline at end of file diff --git a/qpypack/locales/zh_TW.json b/qpypack/locales/zh_TW.json index ff57c98..a63065e 100644 --- a/qpypack/locales/zh_TW.json +++ b/qpypack/locales/zh_TW.json @@ -18,7 +18,6 @@ "Engine": "建置引擎", "Dependencies": "依賴管理", "Resources": "附加資源", - "Optimization": "效能優化", "Package Map": "套件名稱對映", "Execution Log": "執行日誌", "Loaded: {filename}": "已載入: {filename}", @@ -79,7 +78,6 @@ "Output Location": "輸出位置", "Preferences & System Behavior": "偏好與系統行為", "Build Engine:": "建置引擎:", - "Python Interpreter:": "Python 解譯器:", "Output Name:": "輸出名稱:", "App Icon:": "應用程式圖示:", "Primary PIP Index:": "主 PIP 源:", @@ -139,7 +137,6 @@ "
Python {ver} Platform Matrix:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
Legacy OS Full backward compatibility": "
Python {ver} 平台支援:
✔ Windows 7    ✔ Windows 8/8.1    ✔ Windows 10/11    ✔ macOS 10.9+    ✔ Linux
相容舊系統 支援 Windows 7 及舊版作業系統", "
Python {ver} Platform Matrix:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux": "
Python {ver} 平台支援:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10/11    ✔ macOS 10.9+    ✔ Linux", "
Python {ver} Platform Matrix:
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Auto-detecting and managing C backend compiler": "
Python {ver} 平台支援:
✖ Windows 7    ✖ Windows 8/8.1    ✔ Windows 10/11    ✔ macOS 10.13+    ✔ Linux
Nuitka 自動偵測並管理 C 後端編譯器", - "
Python Interpreter
Auto-detecting system environment for Windows, macOS & Linux...": "
Python 解譯器
自動偵測系統環境 (Win/macOS/Linux)...", "[INFO] Build Cancelled.": "[INFO] 建置已取消。", "[INFO] Performing pre-flight environment checks...": "[INFO] 執行環境安全檢查...", "[INFO] Analyzing source code and project dependencies...": "[INFO] 分析原始碼與依賴...", @@ -275,8 +272,6 @@ "One-Click Install": "一鍵安裝", "[ERROR] Python installation failed or was cancelled.": "[ERROR] Python 安裝失敗或已被主動取消。", "System Default ({sys_native})": "系統預設 ({sys_native})", - "My Studio": "我的工作室", - "Python Executable": "Python 執行檔", "Invalid syntax": "無效語法", "[INFO] Downloading Playwright browsers via mirror: {url}": "[INFO] 透過鏡像下載 Playwright 瀏覽器: {url}", "[INFO] Retrying Playwright browser download via official CDN...": "[INFO] 透過官方 CDN 重試下載 Playwright 瀏覽器...", @@ -292,5 +287,50 @@ "Smaller output size. Recommended for 95% of standard apps.": "產物體積最小。推薦 95% 的常規應用程式使用。", "Tip: Build failed in Lite Mode. You can try switching to [Compatibility Mode] in Build Settings and rebuild.": "提示: 精簡模式建置失敗。您可以嘗試在【建置設定】中勾選 [相容模式] 重新打包。", "Keep Virtual Environment (Faster Rebuilds)": "保留虛擬環境 (加速重編)", - "[INFO] Reusing existing virtual environment...": "[INFO] 複用本地已存在的虛擬環境..." + "[INFO] Reusing existing virtual environment...": "[INFO] 複用本地已存在的虛擬環境...", + "Interpreter:": "解譯器:", + "Optimization & Security": "效能優化與安全", + "Independent Developer": "獨立開發者", + "Desktop Application": "桌面應用程式", + "Code Signing": "程式碼簽章", + "Enable Smart Code Signing": "開啟數位簽章", + "Auto-applies digital signature to built app, eliminating 'Unknown Publisher' warning": "自動為產生的應用程式新增數位簽章,提升系統信任度", + "Use Custom Commercial Cert (Optional) ▸": "設定商業數位憑證 (選填) ▸", + "Hide Custom Cert Settings ▾": "折疊憑證進階設定 ▾", + "Commercial PFX File:": "商業憑證檔案 (.pfx):", + "Cert Password:": "憑證金鑰密碼:", + "[INFO] Applying smart digital signature...": "[INFO] 正在為應用程式新增數位簽章...", + "[SUCCESS] Digital signature applied successfully!": "[SUCCESS] 數位簽章新增成功!", + "[WARN] Smart signing failed, but build output is retained.": "[WARN] 數位簽章未成功,但應用產物已正常保留。", + "Create": "建立", + "Create Self-Signed Cert": "建立自簽憑證", + "Certificate Subject (e.g. My Company):": "憑證頒發者 (如 My Company):", + "Generate": "產生", + "Self-Signed Certificate (*.pfx)": "自簽名憑證 (*.pfx)", + "Passwords do not match!": "兩次輸入的密碼不一致!", + "Failed to generate certificate.": "產生憑證失敗。", + "Certificate generated successfully!": "憑證產生成功!", + "Only supported on Windows.": "僅支援在 Windows 系統下產生 .pfx 憑證。", + "Save Certificate": "儲存憑證", + "Error": "錯誤", + "Select .pfx / .p12 certificate file": "請選擇 .pfx / .p12 格式憑證", + "Certificate password": "憑證金鑰密碼", + "Undo": "復原", + "Cut": "剪切", + "Paste": "貼上", + "QPyPack Developer": "QPyPack 開發者", + "Password cannot be empty!": "密碼不能為空!", + "Recommendation: 6+ chars, alphanumeric, '-' and '_' only. Avoid spaces or Chinese to prevent signing errors.": "建議:6位以上,僅使用英文字母、數字、減號及底線。避免使用中文或空格以防簽章失敗。", + "OS Support Matrix:": "支援作業系統情況:", + "Platform Support Matrix:": "平台支援:", + "No Windows 7 Support": "不支援 Windows 7", + "Full backward compatibility": "相容舊版作業系統", + "Legacy macOS Compatible": "相容舊版 macOS", + "Apple Silicon (M1/M2) & Intel": "支援 Apple Silicon (M1/M2) 與 Intel", + "Apple Silicon (M-Series) & Intel": "支援 Apple Silicon (M系列) 與 Intel", + "Compatibility depends on build environment glibc version.": "相容性取決於當前系統的 glibc 版本", + "* Nuitka Auto-manages C Compiler": "* Nuitka 自動接管 C 編譯器", + "
Interpreter
Auto-detecting system environment and OS support matrix...": "
解譯器
正在自動偵測系統環境與支援作業系統情況...", + "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] 時間戳記伺服器連線逾時,進行本地快速簽章...", + "[INFO] Applied digital signature with timestamp ({tsa})...": "[INFO] 已透過時間戳記伺服器 ({tsa}) 完成數位簽章與蓋章..." } \ No newline at end of file diff --git a/qpypack/main.py b/qpypack/main.py index 8ba6f80..56f2aba 100644 --- a/qpypack/main.py +++ b/qpypack/main.py @@ -71,6 +71,7 @@ ZH_CN_DICT = { "Huawei Cloud (China)": "华为云镜像", "USTC (China)": "中科大镜像", + "Modern Cross-Platform Python Application Packager": "现代化的跨平台 Python 应用打包工具", "Modern Cross-Platform Python Packaging GUI Powered by PyInstaller & Nuitka": "基于 PyInstaller 与 Nuitka 的现代化跨平台 Python 打包工具", "Python Packaging, Reimagined.": "重新定义 Python 应用打包体验", "Drop Python source code to start": "拖拽 Python 源码至此开始", @@ -82,7 +83,7 @@ ZH_CN_DICT = { "Engine": "构建引擎", "Dependencies": "依赖管理", "Resources": "附加资源", - "Optimization": "性能优化", + "Optimization & Security": "优化与安全", "Package Map": "包名映射", "Execution Log": "执行日志", @@ -134,6 +135,13 @@ ZH_CN_DICT = { "Clear Log": "清空日志", "Export Log...": "导出日志...", "Reset": "重置", + "Undo": "撤销", + "Cut": "剪切", + "Paste": "粘贴", + "Create": "创建", + "Generate": "生成", + "Save Certificate": "保存证书", + "Error": "错误", "Are you sure you want to reset all preferences?
All settings will be restored to default state.": "确定重置所有偏好设置?
所有设置将恢复为默认状态。", @@ -142,14 +150,17 @@ ZH_CN_DICT = { "Mirrors & Scanner": "镜像与扫描", "Additional Resources (Drag & Drop Supported)": "附加资源 (支持拖拽)", "Performance Optimization": "性能优化", + "Code Signing": "代码签名", "Lock Core Dependencies": "锁定核心依赖", "Package Name Mappings": "包名映射", "UI Language:": "界面语言:", "App Metadata & Presets": "元数据与预设", "Output Location": "输出位置", "Preferences & System Behavior": "偏好与行为", + "Build Engine:": "构建引擎:", - "Python Interpreter:": "Python 解释器:", + "Packaging Mode:": "打包模式:", + "Interpreter:": "解释器:", "Output Name:": "输出名称:", "App Icon:": "应用图标:", "Primary PIP Index:": "主 PIP 源:", @@ -179,8 +190,16 @@ ZH_CN_DICT = { "Target relative path:": "目标相对路径:", "Import name (e.g. cv2):": "导入名 (如 cv2):", "PyPI package name for [{imp_name}]:": "[{imp_name}] 对应 PyPI 包名:", - "Script and settings retained. Ready to rebuild.": "已保留当前配置,就绪等待重新构建。", + "Commercial PFX File:": "商业证书文件 (.pfx):", + "Cert Password:": "证书密钥密码:", + "Certificate Subject (e.g. My Company):": "证书颁发者 (如 My Company):", + "Confirm Password:": "确认密码:", + "Compatibility Mode (Default)": "兼容模式 (默认)", + "Lite Mode (Smaller size)": "精简模式 (体积小)", + "Maximum compatibility. Recommended for apps with complex dynamic imports.": "最大兼容性。适合使用了复杂动态导入的项目。", + "Smaller output size. Recommended for 95% of standard apps.": "产物体积最小。推荐 95% 的常规应用使用。", + "Tip: Build failed in Lite Mode. You can try switching to [Compatibility Mode] in Build Settings and rebuild.": "提示: 精简模式构建失败。您可以尝试在【构建设置】中勾选 [兼容模式] 重新打包。", "One-File Mode (--onefile)": "单文件模式 (--onefile)", "Folder Mode (--onedir)": "文件夹模式 (--onedir)", "Contents Directory (--contents-directory):": "内部资源目录:", @@ -188,38 +207,50 @@ ZH_CN_DICT = { "Hide Console (--noconsole)": "隐藏控制台 (--noconsole)", "Use Virtual Environment (Recommended)": "使用虚拟环境 (推荐)", "Keep Virtual Environment (Faster Rebuilds)": "保留虚拟环境 (适合频繁重编)", - "[INFO] Reusing existing virtual environment...": "[INFO] 复用本地已存在的虚拟环境...", "Install requirements.txt": "安装 requirements.txt", "Analyze Dependencies (AST)": "分析依赖 (原生 AST)", "Scan Entire Folder": "扫描整个文件夹", "Enable UPX Compression": "启用 UPX 压缩", + "Enable Smart Code Signing": "开启数字签名", + "Auto-applies digital signature to built app, eliminating 'Unknown Publisher' warning": "自动为生成的应用程序添加数字签名,提升系统信任度", + "Use Custom Commercial Cert (Optional) ▸": "配置商业数字证书 (可选) ▸", + "Hide Custom Cert Settings ▾": "折叠证书高级设置 ▾", + "Create Self-Signed Cert": "创建自签证书", + "Self-Signed Certificate (*.pfx)": "自签名证书 (*.pfx)", "Concise Log Output": "精简日志", "Auto-save Build Log": "自动保存日志", "Auto Extract Icon": "自动提取图标", "Clean Temporary Cache After Build": "构建后清理缓存", "Sound Notification": "完成提示音", + "Leave blank to auto-detect system default Python": "留空则自动检测系统 Python", "Leave blank to auto-match script name": "留空则自动匹配脚本名", "Leave blank to auto-search requirements.txt in current directory": "留空则自动检索当前目录 requirements.txt", "Comma separated (e.g. pandas, PyQt5)": "逗号分隔 (如 pandas, PyQt5)", "Comma separated (e.g. tkinter, matplotlib)": "逗号分隔 (如 tkinter, matplotlib)", "Leave blank to auto-detect from environment variables": "留空则从环境变量自动检测", + "Select .pfx / .p12 certificate file": "请选择 .pfx / .p12 格式证书", + "Certificate password": "证书密钥密码", "Double-click to edit target path; Drag & drop supported": "双击编辑目标路径;支持拖拽", "Double-click to edit target path; Drag & drop supported. Use 'Export Preset' to save for reuse.": "双击编辑目标路径;支持拖拽。建议使用「导出预设」进行保存。", + "Project-specific. Not saved to global preferences. Use 'Export Preset' to save config.": "提示:此处资源配置仅对当前项目生效。如需长期复用,请使用「导出预设」。", + "Recommendation: 6+ chars, alphanumeric, '-' and '_' only. Avoid spaces or Chinese to prevent signing errors.": "建议:6位以上,仅使用英文字母、数字、减号及下划线。避免使用中文或空格以防签名失败。", "PyInstaller — Bundles Python interpreter and bytecode. Fast build speed, zero configuration (no C compiler needed), and excellent compatibility.": "PyInstaller — 打包解释器与字节码。构建迅速,零配置 (无需 C 编译器),兼容性优异。", "Nuitka — Compiles source code into native C/C++ binary. Produces smaller package size, faster execution, and deep anti-decompilation protection (requires C compiler).": "Nuitka — 编译为原生 C/C++ 二进制。体积更小,执行更快,具备强抗反编译能力 (需 C 编译器)。", - - '
Python {ver} Platform Matrix:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
Legacy OS Full backward compatibility': - '
Python {ver} 平台支持:
✔ Windows 7    ✔ Windows 8/8.1    ✔ Windows 10/11    ✔ macOS 10.9+    ✔ Linux
兼容旧系统 支持 Windows 7 及旧版操作系统', - '
Python {ver} Platform Matrix:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux': - '
Python {ver} 平台支持:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10/11    ✔ macOS 10.9+    ✔ Linux', - '
Python {ver} Platform Matrix:
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Auto-detecting and managing C backend compiler': - '
Python {ver} 平台支持:
✖ Windows 7    ✖ Windows 8/8.1    ✔ Windows 10/11    ✔ macOS 10.13+    ✔ Linux
Nuitka 自动检测并管理 C 后端编译器', - '
Python Interpreter
Auto-detecting system environment for Windows, macOS & Linux...': - '
Python 解释器
自动检测系统环境 (Win/macOS/Linux)...', + "OS Support Matrix:": "支持操作系统情况:", + "Platform Support Matrix:": "平台支持:", + "No Windows 7 Support": "不支持 Windows 7", + "Full backward compatibility": "兼容旧版操作系统", + "Legacy macOS Compatible": "兼容旧版 macOS", + "Apple Silicon (M1/M2) & Intel": "支持 Apple Silicon (M1/M2) 与 Intel", + "Apple Silicon (M-Series) & Intel": "支持 Apple Silicon (M系列) 与 Intel", + "Compatibility depends on build environment glibc version.": "兼容性取决于当前系统的 glibc 版本", + "* Nuitka Auto-manages C Compiler": "* Nuitka 自动接管 C 编译器", + '
Interpreter
Auto-detecting system environment and OS support matrix...': + '
解释器
正在自动检测系统环境与支持操作系统情况...', "[INFO] Build Cancelled.": "[INFO] 构建已取消。", "[INFO] Performing pre-flight environment checks...": "[INFO] 执行预构建环境检查...", @@ -228,6 +259,7 @@ ZH_CN_DICT = { "[INFO] Playwright detected. Installing built-in browsers (PLAYWRIGHT_BROWSERS_PATH=0)...": "[INFO] 检测到 Playwright。正在安装内置浏览器驱动...", "[INFO] Python interpreter path: {path}": "[INFO] Python 路径: {path}", "[INFO] Creating virtual environment...": "[INFO] 创建虚拟环境...", + "[INFO] Reusing existing virtual environment...": "[INFO] 复用本地已存在的虚拟环境...", "[INFO] Synchronizing and upgrading pip package manager...": "[INFO] 更新 pip...", "[INFO] Scanning project source code via AST engine...": "[INFO] 使用原生 AST 引擎扫描依赖...", "[INFO] Nuitka Tip: If prompted to download GCC/MinGW compiler on first build, please ensure stable network connection.": "[INFO] Nuitka 提示: 首次构建如需下载 GCC/MinGW,请确保网络畅通。", @@ -258,6 +290,9 @@ ZH_CN_DICT = { "[INFO] Freeing up space, cleaning temporary build environment...": "[INFO] 清理临时构建环境...", "[INFO] Downloading Playwright browsers via mirror: {url}": "[INFO] 通过镜像下载 Playwright 浏览器: {url}", "[INFO] Retrying Playwright browser download via official CDN...": "[INFO] 通过官方 CDN 重试下载 Playwright 浏览器...", + "[INFO] Applying smart digital signature...": "[INFO] 正在为应用程序添加数字签名...", + "[SUCCESS] Digital signature applied successfully!": "[SUCCESS] 数字签名添加成功!", + "[WARN] Smart signing failed, but build output is retained.": "[WARN] 数字签名未成功,但应用产物已正常保留。", "[SUCCESS] Compilation completed, output path: {path}": "[SUCCESS] 构建成功,输出路径: {path}", "[WARN] Target project is in a Cloud Sync directory (e.g. OneDrive/Dropbox). Cloud sync may temporarily lock build files.": "[WARN] 项目位于云同步目录,可能锁定构建文件。", "[WARN] Specified versions failed to install. Stripping version constraints for automatic compatibility match...": "[WARN] 指定版本安装失败,尝试自动匹配兼容版本...", @@ -278,6 +313,7 @@ ZH_CN_DICT = { "[WARN] Playwright browser installation failed across all sources, build will proceed with risk...": "[WARN] 所有 Playwright 浏览器下载源均失败,继续构建 (有风险)...", "[WARN] Icon conversion to .icns failed, building without icon.": "[WARN] 图标转换为 .icns 失败,将不使用图标构建。", "[INFO] Tip: Packaged executables might be falsely flagged by Windows Defender/Antivirus. Adding exclusions or code-signing is recommended.": "[INFO] 提示: 独立可执行程序可能被安全软件误报。建议加入白名单或添加代码签名。", + "[ERROR] Build aborted: Insufficient disk space (NoSpaceLeft / Errno 28). Please clean up drive space (at least 5 GB free space recommended) and try again.": "[ERROR] 构建中止: 磁盘空间不足 (NoSpaceLeft / Errno 28)。建议预留至少 5GB 可用空间。", "[ERROR] Output directory is missing write permissions: {error}": "[ERROR] 目标输出目录无写入权限: {error}", "[ERROR] Requirements file not found: {path}": "[ERROR] 指定的依赖清单文件不存在: {path}", @@ -299,56 +335,33 @@ ZH_CN_DICT = { "[ERROR] System execution exception: {error}": "[ERROR] 系统执行异常: {error}", "[ERROR] I/O Exception: {err_msg}": "[ERROR] I/O 异常: {err_msg}", "[ERROR] Python installation failed or was cancelled.": "[ERROR] Python 安装失败或已被主动取消。", - "[ERROR] Build completed, but the following dependencies failed to install:\n\n - {pkgs}\n\nNote: The application might raise ModuleNotFoundError at runtime.": + "Passwords do not match!": "两次输入的密码不一致!", + "Failed to generate certificate.": "生成证书失败。", + "Certificate generated successfully!": "证书生成成功!", + "Only supported on Windows.": "仅支持在 Windows 系统下生成 .pfx 证书。", + "Password cannot be empty!": "密码不能为空!", + + "[ERROR] Build completed, but the following dependencies failed to install:\n\n - {pkgs}\n\nNote: The application might raise ModuleNotFoundError at runtime.": "[ERROR] 构建完成,但以下依赖安装失败:\n\n - {pkgs}\n\n注意: 运行时程序可能会抛出 ModuleNotFoundError。", - "[Syntax Error] Source code syntax parsing failed, build aborted:\n" - " - File: {file}\n" - " - Line: Line {line}\n" - " - Detail: {desc}\n\n" - "Tip: This is usually NOT a fault of the packaging tool.\n" - "Please ensure the [Build Python Version] you selected matches the version you used to [Write/Test the Code].\n" - "Using newer syntax (e.g., walrus operator :=, type unions |, match-case) in an older Python environment will trigger this error.\n" - "We recommend going to [Build Settings] -> [Engine] to switch to the correct Python version.": - "[Syntax Error] 源码语法解析失败,构建中止:\n" - " - 文件: {file}\n" - " - 行号: {line}\n" - " - 详情: {desc}\n\n" - "提示:这通常不是打包工具的故障。\n" - "请确认您当前选择的【打包 Python 版本】与您【编写代码时的版本】是否一致。\n" - "高版本语法(如海象运算符 :=、类型联合 |、match-case 等)在低版本 Python 中会导致此错误。\n" - "建议前往【构建设置】->【构建引擎】切换至对应版本的 Python。", + "[Syntax Error] Source code syntax parsing failed, build aborted:\n - File: {file}\n - Line: Line {line}\n - Detail: {desc}\n\nTip: This is usually NOT a fault of the packaging tool.\nPlease ensure the [Build Python Version] you selected matches the version you used to [Write/Test the Code].\nUsing newer syntax (e.g., walrus operator :=, type unions |, match-case) in an older Python environment will trigger this error.\nWe recommend going to [Build Settings] -> [Engine] to switch to the correct Python version.": + "[Syntax Error] 源码语法解析失败,构建中止:\n - 文件: {file}\n - 行号: {line}\n - 详情: {desc}\n\n提示:这通常不是打包工具的故障。\n请确认您当前选择的【打包 Python 版本】与您【编写代码时的版本】是否一致。\n高版本语法(如海象运算符 :=、类型联合 |、match-case 等)在低版本 Python 中会导致此错误。\n建议前往【构建设置】->【构建引擎】切换至对应版本的 Python。", - "[Syntax Error] Source code contains syntax errors, compilation aborted:\n - File: {file}\n - Type: {type}\n - Line: Line {line}\n - Detail: {desc}\n\nTip: Please ensure the source code runs locally before packaging.": + "[Syntax Error] Source code contains syntax errors, compilation aborted:\n - File: {file}\n - Type: {type}\n - Line: Line {line}\n - Detail: {desc}\n\nTip: Please ensure the source code runs locally before packaging.": "[ERROR] 源码语法错误,构建中止:\n - 文件: {file}\n - 类型: {type}\n - 行号: {line}\n - 详情: {desc}\n\n提示: 请确保源码可在本地运行。", - - "[FAILED] Build interrupted exceptionally!\n\n" - "Common Troubleshooting:\n" - "1. Environment Mismatch (Most Common): The selected Python version is incompatible with your source code. Please go to [Build Settings] to switch to the Python version you normally use for this code.\n" - "2. Missing Dependencies: Click 'Detailed Mode' above to check for ModuleNotFoundError.\n" - "3. Antivirus Block: Ensure your security software is not blocking the build process.\n\n" - "(Note: This is usually caused by environment/code discrepancies rather than the packaging engine itself. Please check the detailed log for exact reasons.)": - "[FAILED] 构建异常中断!\n\n" - "常见原因排查:\n" - "1. 环境不匹配 (最常见):您选择的打包 Python 版本与您的源码不兼容。请前往【构建设置】切换为您平时开发运行该代码的 Python 版本。\n" - "2. 依赖缺失:请点击上方切换至「详细日志」,查看是否有模块未找到 (ModuleNotFoundError)。\n" - "3. 杀毒软件拦截:请检查是否有安全软件阻止了打包过程。\n\n" - "(注意:这通常是环境配置与代码差异导致,并非打包引擎本身故障,请查阅详细日志获取确切原因。)", - "[FAILED] Compilation interrupted with exceptions, please click 'Detailed Mode' above the log window for troubleshooting.": + + "[FAILED] Build interrupted exceptionally!\n\nCommon Troubleshooting:\n1. Environment Mismatch (Most Common): The selected Python version is incompatible with your source code. Please go to [Build Settings] to switch to the Python version you normally use for this code.\n2. Missing Dependencies: Click 'Detailed Mode' above to check for ModuleNotFoundError.\n3. Antivirus Block: Ensure your security software is not blocking the build process.\n\n(Note: This is usually caused by environment/code discrepancies rather than the packaging engine itself. Please check the detailed log for exact reasons.)": + "[FAILED] 构建异常中断!\n\n常见原因排查:\n1. 环境不匹配 (最常见):您选择的打包 Python 版本与您的源码不兼容。请前往【构建设置】切换为您平时开发运行该代码的 Python 版本。\n2. 依赖缺失:请点击上方切换至「详细日志」,查看是否有模块未找到 (ModuleNotFoundError)。\n3. 杀毒软件拦截:请检查是否有安全软件阻止了打包过程。\n\n(注意:这通常是环境配置与代码差异导致,并非打包引擎本身故障,请查阅详细日志获取确切原因。)", + + "[FAILED] Compilation interrupted with exceptions, please click 'Detailed Mode' above the log window for troubleshooting.": "[FAILED] 构建异常中断,请切换至「详细日志」排查原因。", - "No log content.": "无日志内容。", - "Log saved to: {path}": "日志已保存: {path}", - "\\nProgram execution completed, press Enter to exit...": "\\n程序执行完成,按回车键退出...", - "Project-specific. Not saved to global preferences. Use 'Export Preset' to save config.": - "提示:此处资源配置仅对当前项目生效。如需长期复用,请使用「导出预设」。", "GitHub Repository": "GitHub 仓库", "Issues & Feedback": "问题与反馈", "PyPI Home": "PyPI 主页", "Sponsor": "赞助支持", "QPyPack is a free and open-source tool. If it has improved your efficiency or solved packaging problems, consider buying the author a coffee!": "QPyPack 是一款免费开源工具。如果它提升了您的效率或解决了打包难题,欢迎赞助支持本开源项目。", "* Sponsorship is completely voluntary, serves as an unconditional encouragement to the open-source community, and involves no commercial commitments. Thank you for your support!": "* 赞助完全出于自愿,属于对开源社区的无偿鼓励,不涉及任何商业承诺。感谢您的支持!", - "Python Environment Required": "需要 Python 环境", "Python is not detected on your system!

QPyPack requires a Python environment to compile your code.
If you haven't installed Python, please download and install it (remember to check 'Add Python.exe to PATH' during installation).": "未在系统中检测到有效的 Python 环境

QPyPack 需要依赖 Python 才能编译代码。
如果您尚未安装,请前往官网下载安装 (提示:安装界面底部请务必勾选 'Add Python.exe to PATH')。", "Download Python": "前往下载 Python", @@ -397,19 +410,19 @@ ZH_CN_DICT = { "Config preset exported to: {path}": "配置预设已成功导出至: {path}", "Config preset imported successfully.": "配置预设已成功导入。", "AST scan completed, found {count} dependencies.": "AST 扫描完成,发现 {count} 个隐式依赖。", + "No log content.": "无日志内容。", + "Log saved to: {path}": "日志已保存: {path}", "Attention: Please check the log for details.": "提示: 请检查下方日志排查详细原因。", - "System Default ({sys_native})": "系统默认 ({sys_native})", - "My Studio": "我的工作室", - "Python Executable": "Python 可执行程序", + "Independent Developer": "独立开发者", + "Desktop Application": "桌面应用程序", "Invalid syntax": "无效语法", "OK": "确定", - "Packaging Mode:": "打包模式:", - "Compatibility Mode (Default)": "兼容模式 (默认)", - "Lite Mode (Smaller size)": "精简模式 (体积小)", - "Maximum compatibility. Recommended for apps with complex dynamic imports.": "最大兼容性。适合使用了复杂动态导入的项目。", - "Smaller output size. Recommended for 95% of standard apps.": "产物体积最小。推荐 95% 的常规应用使用。", - "Tip: Build failed in Lite Mode. You can try switching to [Compatibility Mode] in Build Settings and rebuild.": "提示: 精简模式构建失败。您可以尝试在【构建设置】中勾选 [兼容模式] 重新打包。", + "QPyPack Developer": "QPyPack 开发者", + "\\nProgram execution completed, press Enter to exit...": "\\n程序执行完成,按回车键退出...", + "Script and settings retained. Ready to rebuild.": "已保留当前配置,就绪等待重新构建。", + "[WARN] Timestamp server connection timed out, performing local fast signing...": "[WARN] 时间戳服务器连通超时,进行本地快速签名...", + "[INFO] Applied digital signature with timestamp ({tsa})...": "[INFO] 已通过时间戳服务器 ({tsa}) 完成数字签名与盖章...", "Unknown": "未知" } @@ -689,6 +702,9 @@ def load_config(retry=True): default_updates = { 'language': 'auto', 'keep_venv': 'False', + 'enable_sign': 'True' if sys.platform == 'darwin' else 'False', + 'cert_path': '', + 'cert_pass': '', 'pip_index': default_mirror, 'pip_index_backup': default_backup, 'concise_log': 'True', @@ -1093,6 +1109,82 @@ class CustomInputDialog(QDialog): def get_text(self): return self.edit.text() +class GenCertDialog(QDialog): + def __init__(self, parent=None): + super().__init__(parent) + self.setWindowTitle(_("Create Self-Signed Cert")) + self.setMinimumWidth(380) + self.setStyleSheet(""" + QDialog { background-color: #ffffff; } + QLabel { font-size: 12px; color: #111827; } + QLineEdit { padding: 6px 10px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 12px; } + QLineEdit:focus { border: 1px solid #2563eb; } + QPushButton { background-color: #f1f5f9; color: #475569; border: 1px solid #cbd5e1; border-radius: 6px; font-size: 12px; font-weight: bold; padding: 6px 16px; min-width: 70px; } + QPushButton:hover { background-color: #e2e8f0; } + QPushButton#btnOk { background-color: #2563eb; color: #ffffff; border: none; } + QPushButton#btnOk:hover { background-color: #1d4ed8; } + """) + + lay = QVBoxLayout(self) + lay.setSpacing(10) + lay.setContentsMargins(20, 20, 20, 20) + + form_lay = QFormLayout() + + self.subject_edit = QLineEdit(_("QPyPack Developer")) + self.pass_edit = QLineEdit() + self.pass_edit.setEchoMode(QLineEdit.EchoMode.Password) + self.confirm_edit = QLineEdit() + self.confirm_edit.setEchoMode(QLineEdit.EchoMode.Password) + + form_lay.addRow(QLabel(_("Certificate Subject (e.g. My Company):")), self.subject_edit) + form_lay.addRow(QLabel(_("Password:")), self.pass_edit) + form_lay.addRow(QLabel(_("Confirm Password:")), self.confirm_edit) + + lay.addLayout(form_lay) + + self.hint_label = QLabel(_("Recommendation: 6+ chars, alphanumeric, '-' and '_' only. Avoid spaces or Chinese to prevent signing errors.")) + self.hint_label.setWordWrap(True) + self.hint_label.setStyleSheet("color: #64748b; font-size: 11px; margin-top: 2px;") + lay.addWidget(self.hint_label) + + lay.addSpacing(10) + + btn_lay = QHBoxLayout() + btn_lay.addStretch() + + self.btn_ok = QPushButton(_("Generate")) + self.btn_ok.setObjectName("btnOk") + self.btn_ok.clicked.connect(self.on_generate) + + self.btn_cancel = QPushButton(_("Cancel")) + self.btn_cancel.clicked.connect(self.reject) + + btn_lay.addWidget(self.btn_ok) + btn_lay.addWidget(self.btn_cancel) + lay.addLayout(btn_lay) + + self.cert_info = None + + def on_generate(self): + subject = self.subject_edit.text().strip() + pwd = self.pass_edit.text() + confirm = self.confirm_edit.text() + + if not subject: + return + + if not pwd: + QMessageBox.warning(self, _("Error"), _("Password cannot be empty!")) + return + + if pwd != confirm: + QMessageBox.warning(self, _("Error"), _("Passwords do not match!")) + return + + self.cert_info = (subject, pwd) + self.accept() + class ComboItemDelegate(QStyledItemDelegate): def sizeHint(self, option, index): s = super().sizeHint(option, index) @@ -1653,7 +1745,8 @@ class DropArea(QFrame): self, _("Drag & Drop Python script (.py/.pyw) here\nor Click to Browse"), "", - "Python Scripts (*.py *.pyw);;All Files (*)" + "Python Scripts (*.py *.pyw);;All Files (*)", + options=QFileDialog.Option.DontUseNativeDialog ) if fp: self.fileDropped.emit(fp) @@ -2041,13 +2134,13 @@ class SettingsPanel(QWidget): sub_scroll3, _cnt3, lay_sub3 = self._create_scroll_tab() sub_scroll4, _cnt4, lay_sub4 = self._create_scroll_tab() sub_scroll5, _cnt5, lay_sub5 = self._create_scroll_tab() - + self.sub_tabs.addTab(sub_scroll1, get_svg_icon('engine', "#5F6368", 16), _("Engine")) self.sub_tabs.addTab(sub_scroll2, get_svg_icon('package', "#5F6368", 16), _("Dependencies")) self.sub_tabs.addTab(sub_scroll3, get_svg_icon('folder', "#5F6368", 16), _("Resources")) - self.sub_tabs.addTab(sub_scroll4, get_svg_icon('bolt', "#5F6368", 16), _("Optimization")) + self.sub_tabs.addTab(sub_scroll4, get_svg_icon('bolt', "#5F6368", 16), _("Optimization & Security")) self.sub_tabs.addTab(sub_scroll5, get_svg_icon('link', "#5F6368", 16), _("Package Map")) - + self.card_engine, c_lay_engine = self._create_card(_("Engine & Environment")) self.form_engine = QFormLayout() self.form_engine.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow) @@ -2158,7 +2251,7 @@ class SettingsPanel(QWidget): self.lbl_eng_title = QLabel(_("Build Engine:")) self.lbl_pack_mode_title = QLabel(_("Packaging Mode:")) - self.lbl_py_title = QLabel(_("Python Interpreter:")) + self.lbl_py_title = QLabel(_("Interpreter:")) self.lbl_app_title = QLabel(_("Output Name:")) self.lbl_icon_title = QLabel(_("App Icon:")) @@ -2366,9 +2459,54 @@ class SettingsPanel(QWidget): self.lbl_upx_path = QLabel(_("UPX Path:")) self.form_opt.addRow(self.lbl_upx_path, h_upx_row) - c_lay_opt.addLayout(self.form_opt) + self.card_sign, c_lay_sign = self._create_card(_("Code Signing")) + self.enable_sign_check = QCheckBox(_("Enable Smart Code Signing")) + self.enable_sign_check.setToolTip(_("Auto-applies digital signature to built app, eliminating 'Unknown Publisher' warning")) + c_lay_sign.addWidget(self.enable_sign_check) + + self.adv_sign_container = QWidget() + form_adv_sign = QFormLayout(self.adv_sign_container) + form_adv_sign.setContentsMargins(0, 5, 0, 0) + form_adv_sign.setSpacing(10) + + self.cert_path_edit = QLineEdit() + self.cert_path_edit.setPlaceholderText(_("Select .pfx / .p12 certificate file")) + + self.btn_cert = QPushButton(_("Browse")) + self.btn_cert.setProperty("class", "ToolBtn") + self.btn_cert.clicked.connect(self.select_cert_file) + + self.btn_gen_cert = QPushButton(_("Create")) + self.btn_gen_cert.setProperty("class", "ToolBtn") + self.btn_gen_cert.setToolTip(_("Create Self-Signed Cert")) + self.btn_gen_cert.clicked.connect(self.create_self_signed_cert) + + cert_cont = QWidget() + h_cert = QHBoxLayout(cert_cont) + h_cert.setContentsMargins(0, 0, 0, 0) + h_cert.setSpacing(6) + h_cert.addWidget(self.cert_path_edit, 1) + h_cert.addWidget(self.btn_cert) + h_cert.addWidget(self.btn_gen_cert) + + self.cert_pass_edit = QLineEdit() + self.cert_pass_edit.setEchoMode(QLineEdit.EchoMode.Password) + self.cert_pass_edit.setPlaceholderText(_("Certificate password")) + + form_adv_sign.addRow(QLabel(_("Commercial PFX File:")), cert_cont) + form_adv_sign.addRow(QLabel(_("Cert Password:")), self.cert_pass_edit) + self.adv_sign_container.setVisible(False) + + self.btn_toggle_adv_sign = QPushButton(_("Use Custom Commercial Cert (Optional) ▸")) + self.btn_toggle_adv_sign.setFlat(True) + self.btn_toggle_adv_sign.setStyleSheet("QPushButton { color: #2563eb; font-size: 12px; text-align: left; background: transparent; border: none; font-weight: bold; } QPushButton:hover { text-decoration: underline; }") + self.btn_toggle_adv_sign.clicked.connect(self.toggle_adv_sign_ui) + + c_lay_sign.addWidget(self.btn_toggle_adv_sign) + c_lay_sign.addWidget(self.adv_sign_container) + self.card_ver, c_lay_ver = self._create_card(_("Lock Core Dependencies")) self.form_ver = QFormLayout() self.form_ver.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow) @@ -2385,6 +2523,7 @@ class SettingsPanel(QWidget): c_lay_ver.addLayout(self.form_ver) lay_sub4.addWidget(self.card_opt) + lay_sub4.addWidget(self.card_sign) lay_sub4.addWidget(self.card_ver) lay_sub4.addStretch() @@ -2420,7 +2559,7 @@ class SettingsPanel(QWidget): lay_sub5.addWidget(self.card_map) lay_sub5.addStretch() - + main_lay.addWidget(self.sub_tabs) self.on_engine_changed() @@ -2444,8 +2583,8 @@ class SettingsPanel(QWidget): self.form_meta.setSpacing(15) self.ver_ver = QLineEdit("1.0.0") - self.ver_comp = QLineEdit(_("My Studio")) - self.ver_desc = QLineEdit(_("Python Executable")) + self.ver_comp = QLineEdit(_("Independent Developer")) + self.ver_desc = QLineEdit(_("Desktop Application")) self.lbl_ver_title = QLabel(_("Version:")) self.lbl_company_title = QLabel(_("Author/Company:")) @@ -2655,7 +2794,7 @@ class SettingsPanel(QWidget): self.sub_tabs.setTabText(0, _("Engine")) self.sub_tabs.setTabText(1, _("Dependencies")) self.sub_tabs.setTabText(2, _("Resources")) - self.sub_tabs.setTabText(3, _("Optimization")) + self.sub_tabs.setTabText(3, _("Optimization & Security")) self.sub_tabs.setTabText(4, _("Package Map")) self.card_engine.findChild(QLabel, "CardTitle").setText(_("Engine & Environment")) @@ -2677,7 +2816,7 @@ class SettingsPanel(QWidget): self.rb_compat_mode.setToolTip(_("Maximum compatibility. Recommended for apps with complex dynamic imports.")) self.rb_lite_mode.setToolTip(_("Smaller output size. Recommended for 95% of standard apps.")) - self.lbl_py_title.setText(_("Python Interpreter:")) + self.lbl_py_title.setText(_("Interpreter:")) self.lbl_app_title.setText(_("Output Name:")) self.lbl_icon_title.setText(_("App Icon:")) self.lbl_pip_main.setText(_("Primary PIP Index:")) @@ -2700,10 +2839,10 @@ class SettingsPanel(QWidget): self.sandbox_mode_combo.setItemText(1, _("System Temp Directory")) if not self.ver_comp.isModified(): - self.ver_comp.setText(_("My Studio")) + self.ver_comp.setText(_("Independent Developer")) if not self.ver_desc.isModified(): - self.ver_desc.setText(_("Python Executable")) + self.ver_desc.setText(_("Desktop Application")) if hasattr(self, 'pip_source_combo') and hasattr(self, 'pip_backup_combo'): cur_main = self._get_url_from_combo(self.pip_source_combo) @@ -2730,6 +2869,11 @@ class SettingsPanel(QWidget): self.btn_python_path.setText(_("Browse")) self.btn_download_py.setText(_("View Python")) self.btn_icon.setText(_("Browse")) + self.btn_cert.setText(_("Browse")) + self.btn_gen_cert.setText(_("Create")) + self.btn_gen_cert.setToolTip(_("Create Self-Signed Cert")) + self.cert_path_edit.setPlaceholderText(_("Select .pfx / .p12 certificate file")) + self.cert_pass_edit.setPlaceholderText(_("Certificate password")) self.btn_reqs.setText(_("Browse")) self.btn_scan.setText(_("AST Scan")) self.btn_upx.setText(_("Browse")) @@ -2853,8 +2997,63 @@ class SettingsPanel(QWidget): if hasattr(self.parent_win, "show_notification"): self.parent_win.show_notification(_("Package mappings have been reset to defaults.")) + def toggle_adv_sign_ui(self): + is_visible = not self.adv_sign_container.isVisible() + self.adv_sign_container.setVisible(is_visible) + if is_visible: + self.btn_toggle_adv_sign.setText(_("Hide Custom Cert Settings ▾")) + else: + self.btn_toggle_adv_sign.setText(_("Use Custom Commercial Cert (Optional) ▸")) + + def select_cert_file(self): + f, _filter = QFileDialog.getOpenFileName(self, _("Commercial PFX File:"), "", "PKCS#12 Certificate (*.pfx *.p12);;All Files (*)", options=QFileDialog.Option.DontUseNativeDialog) + if f: self.cert_path_edit.setText(Path(f).resolve().as_posix()) + + def create_self_signed_cert(self): + if os.name != 'nt': + if hasattr(self.parent_win, "show_notification"): + self.parent_win.show_notification(_("Only supported on Windows.")) + return + + dlg = GenCertDialog(self) + if dlg.exec() == QDialog.DialogCode.Accepted: + subject, pwd = dlg.cert_info + + fp, _filter = QFileDialog.getSaveFileName( + self, + _("Save Certificate"), + "my_cert.pfx", + _("Self-Signed Certificate (*.pfx)"), + options=QFileDialog.Option.DontUseNativeDialog + ) + + if fp: + try: + fp_posix = Path(fp).resolve().as_posix() + safe_subject = subject.replace("'", "''") + safe_pwd = pwd.replace("'", "''") + ps_cmd = ( + f'$subject = "CN={safe_subject}"; ' + f'$cert = New-SelfSignedCertificate -Type CodeSigningCert -Subject $subject -CertStoreLocation "Cert:\\CurrentUser\\My"; ' + f'$pwd = ConvertTo-SecureString -String \'{safe_pwd}\' -Force -AsPlainText; ' + f'Export-PfxCertificate -Cert $cert -FilePath "{fp_posix}" -Password $pwd; ' + f'Remove-Item -Path "Cert:\\CurrentUser\\My\\$($cert.Thumbprint)"' + ) + res = subprocess.run(["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", ps_cmd], capture_output=True, text=True, creationflags=subprocess.CREATE_NO_WINDOW) + if res.returncode == 0 and Path(fp).exists(): + self.cert_path_edit.setText(fp_posix) + self.cert_pass_edit.setText(pwd) + if hasattr(self.parent_win, "show_notification"): + self.parent_win.show_notification(_("Certificate generated successfully!")) + else: + if hasattr(self.parent_win, "show_error_log"): + self.parent_win.show_error_log(_("Failed to generate certificate.") + f" {res.stderr}") + except Exception as e: + if hasattr(self.parent_win, "show_error_log"): + self.parent_win.show_error_log(_("Failed to generate certificate.") + f" {str(e)}") + def export_preset(self): - fp, _filter = QFileDialog.getSaveFileName(self, _("Export Preset..."), "project_config.qpypack", "QPyPack Presets (*.qpypack *.json)") + fp, _filter = QFileDialog.getSaveFileName(self, _("Export Preset..."), "project_config.qpypack", "QPyPack Presets (*.qpypack *.json)", options=QFileDialog.Option.DontUseNativeDialog) if fp: try: data = { @@ -2887,7 +3086,7 @@ class SettingsPanel(QWidget): self.parent_win.show_error_log(_("[ERROR] Failed to export preset file: {error}", error=str(e))) def import_preset(self): - fp, _filter = QFileDialog.getOpenFileName(self, _("Import Preset..."), "", "QPyPack Presets (*.qpypack *.json);;All Files (*)") + fp, _filter = QFileDialog.getOpenFileName(self, _("Import Preset..."), "", "QPyPack Presets (*.qpypack *.json);;All Files (*)", options=QFileDialog.Option.DontUseNativeDialog) if fp: try: data = json.loads(Path(fp).read_text(encoding='utf-8')) @@ -2990,7 +3189,16 @@ class SettingsPanel(QWidget): self.pyi_ver_edit.setText(s.get('pyi_version', '6.21.0')) self.nuitka_ver_edit.setText(s.get('nuitka_version', '4.1.3')) - + + default_sign_on_os = True if sys.platform == 'darwin' else False + self.enable_sign_check.setChecked(s.getboolean('enable_sign', default_sign_on_os)) + + self.cert_path_edit.setText(s.get('cert_path', '')) + self.cert_pass_edit.setText(s.get('cert_pass', '')) + if self.cert_path_edit.text(): + self.adv_sign_container.setVisible(True) + self.btn_toggle_adv_sign.setText(_("Hide Custom Cert Settings ▾")) + self.add_data_list.clear() if 'Mappings' in config: @@ -3041,7 +3249,11 @@ class SettingsPanel(QWidget): s['pyi_version'] = self.pyi_ver_edit.text().strip() s['nuitka_version'] = self.nuitka_ver_edit.text().strip() - + + s['enable_sign'] = str(self.enable_sign_check.isChecked()) + s['cert_path'] = self.cert_path_edit.text().strip() + s['cert_pass'] = self.cert_pass_edit.text().strip() + s['add_data_list'] = '' config['Mappings'] = {} @@ -3090,24 +3302,53 @@ class SettingsPanel(QWidget): m_path = re.search(r'python(\d)(\d+)', raw_text, re.I) if m_path: ver_str = f"{m_path.group(1)}.{m_path.group(2)}" - self.python_desc_lbl.setStyleSheet("QLabel { background-color: #f8fafc; color: #334155; border: 1px solid #e2e8f0; border-radius: 6px; padding: 8px 12px; font-size: 12px; line-height: 1.5; }") + self.python_desc_lbl.setStyleSheet("QLabel { background-color: #f8fafc; color: #334155; border: 1px solid #e2e8f0; border-radius: 6px; padding: 10px 14px; font-size: 12px; line-height: 1.6; }") if ver_str: try: parts = [int(x) for x in ver_str.split('.')] major, minor = parts[0], parts[1] - if (major, minor) <= (3, 8): - self.python_desc_lbl.setText(_('
Python {ver} Platform Matrix:
✔ Windows 7    ✔ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux
Legacy OS Full backward compatibility', ver=ver_str)) - elif (major, minor) <= (3, 10): - self.python_desc_lbl.setText(_('
Python {ver} Platform Matrix:
✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ macOS 10.9+    ✔ Linux', ver=ver_str)) + html = f'
Python {ver_str} { _("OS Support Matrix:") }
' + + tag_style = "background-color:#f1f5f9; color:#475569; padding:2px 8px; border-radius:4px; font-weight:bold; font-size:10px; margin-right: 8px;" + + if sys.platform == "win32": + if (major, minor) <= (3, 8): + html += '✔ Windows 7 / 8 / 8.1    ✔ Windows 10 / 11    ✔ Windows Server 2008+
' + html += f'
x86 / AMD64{_("Full backward compatibility")}
' + elif (major, minor) <= (3, 10): + html += '✖ Windows 7    ✔ Windows 8.1    ✔ Windows 10 / 11    ✔ Windows Server 2012+
' + html += f'
AMD64 / ARM64{_("No Windows 7 Support")}
' + else: + html += '✖ Windows 7 / 8 / 8.1    ✔ Windows 10 / 11    ✔ Windows Server 2016+
' + html += f'
{_("* Nuitka Auto-manages C Compiler")}
' + + elif sys.platform == "darwin": + if (major, minor) <= (3, 8): + html += '✔ OS X 10.9 (Mavericks) +    ✔ macOS 10.15 (Catalina)
' + html += f'
x86_64 Intel Only{_("Legacy macOS Compatible")}
' + elif (major, minor) <= (3, 10): + html += '✔ macOS 10.9 (Mavericks) +    ✔ macOS 11 (Big Sur) +
' + html += f'
Universal2 Binary{_("Apple Silicon (M1/M2) & Intel")}
' + else: + html += '✔ macOS 10.13 (High Sierra) +    ✔ macOS 13 / 14 / 15+
' + html += f'
Universal2 Binary{_("Apple Silicon (M-Series) & Intel")}
' + else: - self.python_desc_lbl.setText(_('
Python {ver} Platform Matrix:
✖ Windows 7    ✖ Windows 8 / 8.1    ✔ Windows 10 / 11    ✔ macOS 10.13+    ✔ Linux
Nuitka Auto-detecting and managing C backend compiler', ver=ver_str)) + if (major, minor) <= (3, 9): + html += '✔ Ubuntu 16.04+    ✔ CentOS / RHEL 7+    ✔ Debian 9+
' + html += f'
x86_64 / aarch64glibc >= 2.17
' + else: + html += '✔ Ubuntu 20.04+    ✔ Fedora 32+    ✔ Debian 11+    ✔ RHEL 8+
' + html += f'
x86_64 / aarch64glibc >= 2.28
' + + self.python_desc_lbl.setText(html) return except Exception: pass - self.python_desc_lbl.setText(_('
Python Interpreter
Auto-detecting system environment for Windows, macOS & Linux...')) + self.python_desc_lbl.setText(_('
Interpreter
Auto-detecting system environment and OS support matrix...')) def on_upx_toggled(self, checked): if getattr(self, 'upx_path_container', None) is not None: @@ -3119,20 +3360,20 @@ class SettingsPanel(QWidget): self.out_dir_container.setVisible(show_custom) def select_out_dir(self): - d = QFileDialog.getExistingDirectory(self, _("Target Directory:")) + d = QFileDialog.getExistingDirectory(self, _("Target Directory:"), options=QFileDialog.Option.DontUseNativeDialog) if d: self.out_dir_edit.setText(Path(d).resolve().as_posix()) def select_upx_path(self): - d = QFileDialog.getExistingDirectory(self, _("UPX Path:")) + d = QFileDialog.getExistingDirectory(self, _("UPX Path:"), options=QFileDialog.Option.DontUseNativeDialog) if d: self.upx_path_edit.setText(Path(d).resolve().as_posix()) def select_reqs_file(self): - f, _filter = QFileDialog.getOpenFileName(self, _("Requirements File:"), "", "Requirements Files (*.txt);;All Files (*)") + f, _filter = QFileDialog.getOpenFileName(self, _("Requirements File:"), "", "Requirements Files (*.txt);;All Files (*)", options=QFileDialog.Option.DontUseNativeDialog) if f: self.reqs_file_edit.setText(Path(f).resolve().as_posix()) def select_python_path(self): exe_filter = "Executable (*.exe);;All Files (*)" if os.name == 'nt' else "All Files (*)" - f, _filter = QFileDialog.getOpenFileName(self, _("Python Interpreter:"), "", exe_filter) + f, _filter = QFileDialog.getOpenFileName(self, _("Interpreter:"), "", exe_filter, options=QFileDialog.Option.DontUseNativeDialog) if f: self.python_path_combo.setCurrentText(Path(f).resolve().as_posix()) def on_download_python_clicked(self): @@ -3148,7 +3389,7 @@ class SettingsPanel(QWidget): self.icon_preview.clear() def select_icon(self): - p, _filter = QFileDialog.getOpenFileName(self, _("App Icon:"), "", "Icon Files (*.ico *.svg *.png *.icns)") + p, _filter = QFileDialog.getOpenFileName(self, _("App Icon:"), "", "Icon Files (*.ico *.svg *.png *.icns)", options=QFileDialog.Option.DontUseNativeDialog) if p: self.icon_edit.setText(Path(p).resolve().as_posix()) def auto_scan_hidden(self): @@ -3177,13 +3418,13 @@ class SettingsPanel(QWidget): self._add_resource_item('dir', p.as_posix(), p.name) def add_resource_files(self): - files, _filter = QFileDialog.getOpenFileNames(self, _("Add File"), "", "All Files (*)") + files, _filter = QFileDialog.getOpenFileNames(self, _("Add File"), "", "All Files (*)", options=QFileDialog.Option.DontUseNativeDialog) for f in files: src = Path(f).resolve().as_posix() self._add_resource_item('file', src, ".") def add_resource_dir(self): - folder = QFileDialog.getExistingDirectory(self, _("Add Dir")) + folder = QFileDialog.getExistingDirectory(self, _("Add Dir"), options=QFileDialog.Option.DontUseNativeDialog) if folder: src = Path(folder).resolve().as_posix() dst = Path(folder).name @@ -3199,27 +3440,27 @@ class SettingsPanel(QWidget): def _show_lineedit_menu(self, line_edit, pos): menu = QMenu(line_edit) - act_undo = menu.addAction(_("Undo") if False else "Undo") + act_undo = menu.addAction(_("Undo")) act_undo.triggered.connect(line_edit.undo) act_undo.setEnabled(line_edit.isUndoAvailable()) menu.addSeparator() - act_cut = menu.addAction("Cut") + act_cut = menu.addAction(_("Cut")) act_cut.triggered.connect(line_edit.cut) act_cut.setEnabled(line_edit.hasSelectedText() and not line_edit.isReadOnly()) - act_copy = menu.addAction("Copy") + act_copy = menu.addAction(_("Copy")) act_copy.triggered.connect(line_edit.copy) act_copy.setEnabled(line_edit.hasSelectedText()) - act_paste = menu.addAction("Paste") + act_paste = menu.addAction(_("Paste")) act_paste.triggered.connect(line_edit.paste) act_paste.setEnabled(not line_edit.isReadOnly()) menu.addSeparator() - act_select_all = menu.addAction("Select All") + act_select_all = menu.addAction(_("Select All")) act_select_all.triggered.connect(line_edit.selectAll) menu.exec(line_edit.mapToGlobal(pos)) @@ -3305,8 +3546,8 @@ class ScriptAnalysisThread(QThread): app_name = Path(self.path).stem version = "" - author = "My Studio" - desc = "Python Executable" + author = "Independent Developer" + desc = "Desktop Application" script_imports = set() try: @@ -3422,6 +3663,9 @@ class PackingThread(QThread): stripped = line.rstrip('\r\n') self.all_raw_logs.append(stripped) + + if silent_error: + continue buffer.append(stripped) if len(buffer) >= 15 or (time.time() - last_emit) > 0.1: @@ -3429,7 +3673,8 @@ class PackingThread(QThread): buffer.clear() last_emit = time.time() - if buffer: self.progress.emit('\n'.join(buffer)) + if buffer and not silent_error: + self.progress.emit('\n'.join(buffer)) self.process.wait() if is_timeout[0]: @@ -3445,9 +3690,14 @@ class PackingThread(QThread): return False finally: if timer: timer.cancel() - if self.process and self.process.stdout: + if self.process: + if self.process.stdout: + try: + self.process.stdout.close() + except Exception: + pass try: - self.process.stdout.close() + self.process.wait(timeout=5) except Exception: pass @@ -3551,6 +3801,199 @@ class PackingThread(QThread): } return {"is_code_error": False} + def auto_sign_executable(self, target_path: Path) -> bool: + is_macos = (sys.platform == 'darwin') + enable_sign_setting = self.params.get('enable_sign', False) + + if not is_macos and not enable_sign_setting: + return True + + self.progress.emit(_("[INFO] Applying smart digital signature...")) + + if os.name == 'nt': + if target_path.is_file(): + for _wait in range(6): + try: + with open(target_path, 'r+b'): + break + except (IOError, OSError): + time.sleep(0.5) + + cert_path = self.params.get('cert_path', '').strip() + cert_pass = self.params.get('cert_pass', '').strip() + + targets = [] + if target_path.is_dir(): + targets.extend(list(target_path.rglob("*.exe"))) + targets.extend(list(target_path.rglob("*.dll"))) + targets.extend(list(target_path.rglob("*.pyd"))) + else: + targets.append(target_path) + + if not targets: + return True + + tsa_servers = [ + "http://timestamp.digicert.com", + "http://ts.ssl.com", + "http://timestamp.sectigo.com", + "http://timestamp.acs.microsoft.com", + "http://timestamp.comodoca.com", + ] + + signtool_exe = self._find_signtool() + success_all = True + + for target_file in targets: + target_str = target_file.resolve().as_posix() + signed_with_ts = False + + if signtool_exe: + signed_with_ts = self._sign_with_signtool( + signtool_exe, target_str, cert_path, cert_pass, tsa_servers + ) + if signed_with_ts and target_file == targets[0]: + self.progress.emit(_("[INFO] Applied digital signature with timestamp ({tsa})...", tsa="RFC3161/signtool")) + + if not signed_with_ts: + signed_with_ts = self._sign_with_powershell( + target_str, cert_path, cert_pass, tsa_servers, is_first=(target_file == targets[0]) + ) + + if not signed_with_ts: + success_all = False + + if success_all: + self.progress.emit(_("[SUCCESS] Digital signature applied successfully!")) + return True + else: + self.progress.emit(_("[WARN] Smart signing failed, but build output is retained.")) + return False + + elif is_macos: + target_posix = target_path.resolve().as_posix() + cmd = ["codesign", "--force", "--deep", "--options", "runtime", "--sign", "-", target_posix] + + ok = self.run_cmd(cmd, silent_error=True) + if not ok: + fallback_cmd = ["codesign", "--force", "--deep", "--sign", "-", target_posix] + ok = self.run_cmd(fallback_cmd, silent_error=True) + + if ok: + self.progress.emit(_("[SUCCESS] Digital signature applied successfully!")) + return True + else: + self.progress.emit(_("[WARN] Smart signing failed, but build output is retained.")) + return False + + return True + + def _find_signtool(self) -> str: + signtool = shutil.which("signtool") or shutil.which("signtool.exe") + if signtool: + return signtool + + sdk_base = Path(os.environ.get("ProgramFiles(x86)", "C:\\Program Files (x86)")) / "Windows Kits" / "10" / "bin" + if sdk_base.exists(): + candidates = sorted(sdk_base.glob("10.*/x64/signtool.exe"), reverse=True) + if candidates: + return candidates[0].as_posix() + + return "" + + def _sign_with_signtool(self, signtool_exe, target_path, cert_path, cert_pass, tsa_servers) -> bool: + thumbprint = None + + if not (cert_path and Path(cert_path).exists()): + company_name = self.params.get('ver_comp', '').strip() or 'QPyPack App' + safe_company = company_name.replace("'", "''").replace('"', '""') + ps_create = ( + f'$subject = "CN={safe_company}"; ' + '$cert = Get-ChildItem Cert:\\CurrentUser\\My -CodeSigningCert | Where-Object { $_.Subject -eq $subject } | Select-Object -First 1; ' + 'if (-not $cert) { $cert = New-SelfSignedCertificate -Type CodeSigningCert -Subject $subject -CertStoreLocation Cert:\\CurrentUser\\My }; ' + 'Write-Output $cert.Thumbprint' + ) + try: + kw = {"capture_output": True, "text": True, "timeout": 10, "errors": "ignore"} + if os.name == 'nt': + kw["creationflags"] = subprocess.CREATE_NO_WINDOW + res = subprocess.run( + ["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", ps_create], + **kw + ) + thumbprint = res.stdout.strip().split('\n')[-1].strip() if res.returncode == 0 else "" + if not thumbprint: + return False + except Exception: + return False + + for tsa in tsa_servers: + if self._is_cancelled: + return False + + if cert_path and Path(cert_path).exists(): + cmd = [signtool_exe, "sign", "/f", cert_path, "/fd", "sha256", + "/tr", tsa, "/td", "sha256"] + if cert_pass: + cmd.extend(["/p", cert_pass]) + cmd.append(target_path) + else: + cmd = [signtool_exe, "sign", "/sha1", thumbprint, "/fd", "sha256", + "/tr", tsa, "/td", "sha256", target_path] + + if self.run_cmd(cmd, silent_error=True, timeout=30): + return True + + return False + + def _sign_with_powershell(self, target_path, cert_path, cert_pass, tsa_servers, is_first=False) -> bool: + company_name = self.params.get('ver_comp', '').strip() + if not company_name: + app_title = self.params.get('app_name', 'App').strip() or 'App' + company_name = f"{app_title} Developer" + + safe_company = company_name.replace("'", "''").replace('"', '""') + + if cert_path and Path(cert_path).exists(): + safe_pwd = (cert_pass or '').replace("'", "''") + pass_part = f' -Password (ConvertTo-SecureString -String \'{safe_pwd}\' -Force -AsPlainText)' if cert_pass else '' + base_cert_script = f'$cert = Get-PfxCertificate -FilePath "{cert_path}"{pass_part}; ' + else: + base_cert_script = ( + f'$subject = "CN={safe_company}"; ' + '$cert = Get-ChildItem Cert:\\CurrentUser\\My -CodeSigningCert | Where-Object { $_.Subject -eq $subject } | Select-Object -First 1; ' + 'if (-not $cert) { ' + '$cert = New-SelfSignedCertificate -Type CodeSigningCert -Subject $subject -CertStoreLocation Cert:\\CurrentUser\\My ' + '}; ' + ) + + for tsa in tsa_servers: + if self._is_cancelled: + return False + + ps_cmd = ( + f'{base_cert_script}' + f'$sig = Set-AuthenticodeSignature -FilePath "{target_path}" -Certificate $cert ' + f'-TimestampServer "{tsa}" -HashAlgorithm SHA256; ' + f'if ($sig.Status -ne "Valid" -and $sig.Status -ne "UnknownError") {{ exit 1 }}; ' + f'if ($null -eq $sig.TimeStamperCertificate) {{ exit 1 }}' + ) + if self.run_cmd(["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", ps_cmd], + silent_error=True, timeout=30): + if is_first: + self.progress.emit(_("[INFO] Applied digital signature with timestamp ({tsa})...", tsa=tsa)) + return True + + self.progress.emit(_("[WARN] Timestamp server connection timed out, performing local fast signing...")) + + ps_cmd_no_ts = ( + f'{base_cert_script}' + f'$sig = Set-AuthenticodeSignature -FilePath "{target_path}" -Certificate $cert -HashAlgorithm SHA256; ' + f'if ($sig.Status -ne "Valid" -and $sig.Status -ne "UnknownError") {{ exit 1 }}' + ) + return self.run_cmd(["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", ps_cmd_no_ts], + silent_error=True, timeout=15) + def run(self): os.environ["NUITKA_ACCEPT_DOWNLOADS"] = "yes" engine = self.params['engine'] @@ -4310,6 +4753,9 @@ class PackingThread(QThread): self.progress.emit(_("[ERROR] Could not locate valid executable product in temporary build directory: {path}", path=str(src_out))) if success and final_out.exists(): + if self.params.get('enable_sign'): + self.auto_sign_executable(final_out) + self.progress.emit(_("[INFO] Validating output files and generating final product...")) if self.params.get('auto_save_log') and self.all_raw_logs: try: @@ -5143,8 +5589,8 @@ class MainWindow(QMainWindow): if version: self.settings_panel.ver_ver.setText(version) else: self.settings_panel.ver_ver.setText("1.0.0") - self.settings_panel.ver_comp.setText(_(author) if author == "My Studio" else author) - self.settings_panel.ver_desc.setText(_(desc) if desc == "Python Executable" else desc) + self.settings_panel.ver_comp.setText(_(author) if author == "Independent Developer" else author) + self.settings_panel.ver_desc.setText(_(desc) if desc == "Desktop Application" else desc) gui_libs = { 'pyqt5', 'pyqt6', 'pyside2', 'pyside6', 'tkinter', 'wx', 'kivy', 'libavg', @@ -5333,6 +5779,9 @@ class MainWindow(QMainWindow): 'engine': engine, 'python_exe': raw_py, 'script_path': self.script_path, + 'enable_sign': sp.enable_sign_check.isChecked(), + 'cert_path': sp.cert_path_edit.text().strip(), + 'cert_pass': sp.cert_pass_edit.text().strip(), 'app_name': app_name, 'onefile': sp.rb_onefile.isChecked(), 'contents_dir': sp.contents_dir_edit.text().strip() or '_internal', @@ -5366,6 +5815,7 @@ class MainWindow(QMainWindow): 'lite_mode': sp.rb_lite_mode.isChecked(), 'pyi_version': sp.pyi_ver_edit.text().strip(), 'nuitka_version': sp.nuitka_ver_edit.text().strip(), + 'mappings': mappings, } self.log_concise.clear() @@ -5445,8 +5895,8 @@ class MainWindow(QMainWindow): self.settings_panel.reqs_file_edit.clear() self.settings_panel.out_dir_edit.clear() self.settings_panel.ver_ver.setText("1.0.0") - self.settings_panel.ver_comp.setText(_("My Studio")) - self.settings_panel.ver_desc.setText(_("Python Executable")) + self.settings_panel.ver_comp.setText(_("Independent Developer")) + self.settings_panel.ver_desc.setText(_("Desktop Application")) self.log_concise.clear() self.log_detailed.clear() @@ -5591,7 +6041,7 @@ class MainWindow(QMainWindow): if self.script_path: default_name = f"qpypack_{Path(self.script_path).stem}.log" - fp, _filter = QFileDialog.getSaveFileName(self, _("Export Log..."), default_name, "Log Files (*.log);;Text Files (*.txt);;All Files (*)") + fp, _filter = QFileDialog.getSaveFileName(self, _("Export Log..."), default_name, "Log Files (*.log);;Text Files (*.txt);;All Files (*)", options=QFileDialog.Option.DontUseNativeDialog) if fp: try: Path(fp).write_text(content, encoding='utf-8')