forked from Boria138/PortProtonQt
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f9e6ea958 | |||
|
|
19aecd75c4 | ||
|
|
905ebe1d61 | ||
|
ae0b3a0f1a
|
|||
|
678f28ed30
|
|||
|
e7d2860c0e
|
|||
|
55a7f77a33
|
|||
|
8e6c0aafd1
|
|||
|
dd65021976
|
|||
|
5f3a451c50
|
|||
|
c33813dae5
|
|||
|
88a436c29f
|
@@ -2,8 +2,14 @@ name: Nightly Build - AppImage, Arch, Fedora
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch:
|
||||
description: 'Branch to build'
|
||||
required: false
|
||||
default: 'main'
|
||||
|
||||
env:
|
||||
BUILD_BRANCH: ${{ inputs.branch || 'main' }}
|
||||
PKGDEST: "/tmp/portprotonqt"
|
||||
PACKAGE: "portprotonqt"
|
||||
|
||||
@@ -12,7 +18,7 @@ jobs:
|
||||
name: Build AppImage
|
||||
runs-on: ubuntu-22.04
|
||||
container:
|
||||
image: archlinux:base-devel@sha256:ebcaeca69c4d416f848aedcd27fe224384fd506f86046526a5d49ec6d9e29db1
|
||||
image: archlinux:base-devel@sha256:84c36fa73fc692775e6b99de0d6a10967005b459ef170fc4faea426673b5e7b6
|
||||
options: --privileged --device /dev/fuse
|
||||
steps:
|
||||
- name: Prepare container
|
||||
@@ -22,12 +28,14 @@ jobs:
|
||||
pacman -Syu --noconfirm --disable-download-timeout --needed git wget gnupg nodejs npm xorg-server-xvfb zsync
|
||||
|
||||
- uses: https://gitea.com/actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
with:
|
||||
ref: ${{ env.BUILD_BRANCH }}
|
||||
|
||||
- name: Install appimage dependencies
|
||||
run: |
|
||||
cd build-aux/AppImage
|
||||
chmod +x get-dependencies.sh portprotonqt-appimage.sh
|
||||
./get-dependencies.sh --git
|
||||
./get-dependencies.sh --local --branch "${{ env.BUILD_BRANCH }}"
|
||||
|
||||
- name: Build AppImage
|
||||
run: |
|
||||
@@ -55,9 +63,8 @@ jobs:
|
||||
steps:
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
dnf install -y git rpmdevtools python3-devel python3-wheel python3-pip \
|
||||
python3-build pyproject-rpm-macros systemd-rpm-macros python3-setuptools \
|
||||
redhat-rpm-config nodejs npm
|
||||
dnf install -y git rpmdevtools meson ninja-build python3-devel \
|
||||
systemd-rpm-macros redhat-rpm-config nodejs npm
|
||||
|
||||
- name: Setup rpmbuild environment
|
||||
run: |
|
||||
@@ -68,10 +75,13 @@ jobs:
|
||||
|
||||
- name: Checkout repo
|
||||
uses: https://gitea.com/actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
with:
|
||||
ref: ${{ env.BUILD_BRANCH }}
|
||||
|
||||
- name: Copy fedora.spec
|
||||
run: |
|
||||
cp build-aux/fedora-git.spec /home/rpmbuild/SPECS/${{ env.PACKAGE }}.spec
|
||||
sed "s|git clone https://git.linux-gaming.ru/Boria138/PortProtonQt.git|git clone -b ${{ env.BUILD_BRANCH }} https://git.linux-gaming.ru/Boria138/PortProtonQt.git|" \
|
||||
build-aux/fedora-git.spec > /home/rpmbuild/SPECS/${{ env.PACKAGE }}.spec
|
||||
chown -R rpmbuild:users /home/rpmbuild
|
||||
|
||||
- name: Build RPM
|
||||
@@ -88,7 +98,7 @@ jobs:
|
||||
name: Build Arch Package
|
||||
runs-on: ubuntu-22.04
|
||||
container:
|
||||
image: archlinux:base-devel@sha256:ebcaeca69c4d416f848aedcd27fe224384fd506f86046526a5d49ec6d9e29db1
|
||||
image: archlinux:base-devel@sha256:84c36fa73fc692775e6b99de0d6a10967005b459ef170fc4faea426673b5e7b6
|
||||
|
||||
steps:
|
||||
- name: Prepare container
|
||||
@@ -115,17 +125,20 @@ jobs:
|
||||
chown user -R /tmp
|
||||
chown user -R ..
|
||||
|
||||
- name: Checkout
|
||||
uses: https://gitea.com/actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
with:
|
||||
ref: ${{ env.BUILD_BRANCH }}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd /__w/portproton-repo
|
||||
git clone https://git.linux-gaming.ru/Boria138/PortProtonQt.git
|
||||
cp -r "$GITHUB_WORKSPACE" PortProtonQt
|
||||
cd /__w/portproton-repo/PortProtonQt/build-aux
|
||||
sed -i "s|source=(\"git+https://git.linux-gaming.ru/Boria138/PortProtonQt.git\")|source=(\"git+https://git.linux-gaming.ru/Boria138/PortProtonQt.git#branch=${{ env.BUILD_BRANCH }}\")|" PKGBUILD-git
|
||||
chown user -R ..
|
||||
su user -c "yes '' | makepkg --noconfirm -s -p PKGBUILD-git"
|
||||
|
||||
- name: Checkout
|
||||
uses: https://gitea.com/actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
|
||||
- name: Upload Arch package
|
||||
uses: https://gitea.com/actions/gitea-upload-artifact@v4
|
||||
with:
|
||||
|
||||
@@ -8,7 +8,7 @@ on:
|
||||
|
||||
env:
|
||||
# Common version, will be used for tagging the release
|
||||
VERSION: 0.1.9
|
||||
VERSION: 0.1.10
|
||||
PKGDEST: "/tmp/portprotonqt"
|
||||
PACKAGE: "portprotonqt"
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
@@ -77,17 +77,17 @@ jobs:
|
||||
chown user -R /tmp
|
||||
chown user -R ..
|
||||
|
||||
- name: Checkout
|
||||
uses: https://gitea.com/actions/checkout@v4
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd /__w/portproton-repo
|
||||
git clone https://git.linux-gaming.ru/Boria138/PortProtonQt.git
|
||||
cp -r "$GITHUB_WORKSPACE" PortProtonQt
|
||||
cd /__w/portproton-repo/PortProtonQt/build-aux
|
||||
chown user -R ..
|
||||
su user -c "yes '' | makepkg --noconfirm -s"
|
||||
|
||||
- name: Checkout
|
||||
uses: https://gitea.com/actions/checkout@v4
|
||||
|
||||
- name: Upload Arch package
|
||||
uses: https://gitea.com/actions/gitea-upload-artifact@v4
|
||||
with:
|
||||
@@ -109,9 +109,8 @@ jobs:
|
||||
steps:
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
dnf install -y git rpmdevtools python3-devel python3-wheel python3-pip \
|
||||
python3-build pyproject-rpm-macros systemd-rpm-macros python3-setuptools \
|
||||
redhat-rpm-config nodejs npm
|
||||
dnf install -y git rpmdevtools meson ninja-build python3-devel \
|
||||
systemd-rpm-macros redhat-rpm-config nodejs npm
|
||||
|
||||
- name: Setup rpmbuild environment
|
||||
run: |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Check Translations (disabled until yaspeller is fixed)
|
||||
name: Check Translations
|
||||
run-name: Check spelling in translation files
|
||||
on:
|
||||
push:
|
||||
|
||||
@@ -9,6 +9,8 @@ on:
|
||||
env:
|
||||
PKGDEST: "/tmp/portprotonqt"
|
||||
PACKAGE: "portprotonqt"
|
||||
PR_REPO_URL: ${{ github.event.pull_request.head.repo.clone_url }}
|
||||
PR_BRANCH: ${{ github.head_ref }}
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
@@ -63,7 +65,7 @@ jobs:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.appimage == 'true' || github.event_name == 'workflow_dispatch'
|
||||
container:
|
||||
image: archlinux:base-devel@sha256:ebcaeca69c4d416f848aedcd27fe224384fd506f86046526a5d49ec6d9e29db1
|
||||
image: archlinux:base-devel@sha256:84c36fa73fc692775e6b99de0d6a10967005b459ef170fc4faea426673b5e7b6
|
||||
options: --privileged --device /dev/fuse
|
||||
steps:
|
||||
- name: Prepare container
|
||||
@@ -78,7 +80,7 @@ jobs:
|
||||
run: |
|
||||
cd build-aux/AppImage
|
||||
chmod +x get-dependencies.sh portprotonqt-appimage.sh
|
||||
./get-dependencies.sh
|
||||
./get-dependencies.sh --local --branch "${{ env.PR_BRANCH }}" --repo "${{ env.PR_REPO_URL }}"
|
||||
|
||||
- name: Build AppImage
|
||||
run: |
|
||||
@@ -108,9 +110,8 @@ jobs:
|
||||
steps:
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
dnf install -y git rpmdevtools python3-devel python3-wheel python3-pip \
|
||||
python3-build pyproject-rpm-macros python3-setuptools \
|
||||
redhat-rpm-config nodejs npm
|
||||
dnf install -y git rpmdevtools meson ninja-build python3-devel \
|
||||
systemd-rpm-macros redhat-rpm-config nodejs npm
|
||||
|
||||
- name: Setup rpmbuild environment
|
||||
run: |
|
||||
@@ -124,7 +125,8 @@ jobs:
|
||||
|
||||
- name: Copy fedora-git.spec
|
||||
run: |
|
||||
cp build-aux/fedora-git.spec /home/rpmbuild/SPECS/${{ env.PACKAGE }}.spec
|
||||
sed "s|git clone https://git.linux-gaming.ru/Boria138/PortProtonQt.git|git clone -b ${{ env.PR_BRANCH }} ${{ env.PR_REPO_URL }}|" \
|
||||
build-aux/fedora-git.spec > /home/rpmbuild/SPECS/${{ env.PACKAGE }}.spec
|
||||
chown -R rpmbuild:users /home/rpmbuild
|
||||
|
||||
- name: Build RPM
|
||||
@@ -143,7 +145,7 @@ jobs:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.arch == 'true' || github.event_name == 'workflow_dispatch'
|
||||
container:
|
||||
image: archlinux:base-devel@sha256:ebcaeca69c4d416f848aedcd27fe224384fd506f86046526a5d49ec6d9e29db1
|
||||
image: archlinux:base-devel@sha256:84c36fa73fc692775e6b99de0d6a10967005b459ef170fc4faea426673b5e7b6
|
||||
|
||||
steps:
|
||||
- name: Prepare container
|
||||
@@ -170,17 +172,18 @@ jobs:
|
||||
chown user -R /tmp
|
||||
chown user -R ..
|
||||
|
||||
- name: Checkout
|
||||
uses: https://gitea.com/actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd /__w/portproton-repo
|
||||
git clone https://git.linux-gaming.ru/Boria138/PortProtonQt.git
|
||||
git clone -b ${{ env.PR_BRANCH }} ${{ env.PR_REPO_URL }} PortProtonQt
|
||||
cd /__w/portproton-repo/PortProtonQt/build-aux
|
||||
sed -i "s|source=(\"git+https://git.linux-gaming.ru/Boria138/PortProtonQt.git\")|source=(\"git+${{ env.PR_REPO_URL }}#branch=${{ env.PR_BRANCH }}\")|" PKGBUILD-git
|
||||
chown user -R ..
|
||||
su user -c "yes '' | makepkg --noconfirm -s -p PKGBUILD-git"
|
||||
|
||||
- name: Checkout
|
||||
uses: https://gitea.com/actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
|
||||
- name: Upload Arch package
|
||||
uses: https://gitea.com/actions/gitea-upload-artifact@v4
|
||||
with:
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
- uses: https://gitea.com/actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: https://gitea.com/actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
|
||||
uses: https://gitea.com/actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
- uses: https://gitea.com/actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: https://gitea.com/actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
|
||||
uses: https://gitea.com/actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
|
||||
29
CHANGELOG.md
29
CHANGELOG.md
@@ -3,6 +3,35 @@
|
||||
Все заметные изменения в этом проекте фиксируются в этом файле.
|
||||
Формат основан на [Keep a Changelog](https://keepachangelog.com/) и придерживается принципов [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [0.1.10] - 2026-01-14
|
||||
|
||||
### Added
|
||||
- Детальная страница для автоустановок с описанием игры и возможности переуствновки
|
||||
- Менеджер версий Wine для скачивания и удаления различных версий Wine и Proton
|
||||
- Возможность перевода описание, названия тем на другие языки
|
||||
- Возможность перевода подписи к скриншотам тем на другие языки
|
||||
|
||||
### Changed
|
||||
- Проведена чистка мёртвого кода
|
||||
- Улучшена проверка сторонних тем
|
||||
- В документации по созданию тем добавлены примеры dropin тем
|
||||
- Провеедена редактура перевода
|
||||
- Переработана сортировка вайнов и префиксов во всех комбобоксах
|
||||
- Список Wine и префиксов теперь обновляется на лету, а не при запуске приложения
|
||||
- AppImage теперь работает на дистрибутивах использующий альтернативный libc, а так же на тех что не следуют FHS
|
||||
|
||||
### Fixed
|
||||
- Изменение размера карточек автоустановок через геймпад
|
||||
- Проведены исправления для утечек памяти
|
||||
- Время игры теперь парсится даже если файл статистики повреждён
|
||||
- При наличии битых обложек они теперь перекачиваются, а не провоцируют ошибки libpng
|
||||
- Управление QmessageBox через стрелки клавиатуры
|
||||
|
||||
### Contributors
|
||||
- @Vector_null
|
||||
- @Dervart
|
||||
- @Simple16
|
||||
|
||||
## [0.1.9] - 2025-12-08
|
||||
|
||||
### Added
|
||||
|
||||
@@ -2,22 +2,52 @@
|
||||
|
||||
set -eu
|
||||
|
||||
# Determine if git mode is enabled based on the first argument
|
||||
if [ "${1:-}" = "--git" ] || [ "${1:-}" = "-g" ]; then
|
||||
GIT_MODE=true
|
||||
else
|
||||
GIT_MODE=false
|
||||
fi
|
||||
# Initialize variables
|
||||
LOCAL_MODE=false
|
||||
BRANCH="main"
|
||||
REPO_URL="https://git.linux-gaming.ru/Boria138/PortProtonQt.git"
|
||||
|
||||
# Parse arguments
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--local|-l)
|
||||
LOCAL_MODE=true
|
||||
;;
|
||||
--branch)
|
||||
if [ -n "${2:-}" ] && [ "${2#-}" = "$2" ]; then
|
||||
BRANCH="$2"
|
||||
shift
|
||||
else
|
||||
echo "Error: --branch requires an argument"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--repo)
|
||||
if [ -n "${2:-}" ] && [ "${2#-}" = "$2" ]; then
|
||||
REPO_URL="$2"
|
||||
shift
|
||||
else
|
||||
echo "Error: --repo requires an argument"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
ARCH="$(uname -m)"
|
||||
PACKAGE_BUILDER="https://raw.githubusercontent.com/pkgforge-dev/Anylinux-AppImages/refs/heads/main/useful-tools/make-aur-package.sh"
|
||||
EXTRA_PACKAGES="https://raw.githubusercontent.com/pkgforge-dev/Anylinux-AppImages/refs/heads/main/useful-tools/get-debloated-pkgs.sh"
|
||||
|
||||
if [ "$GIT_MODE" = true ]; then
|
||||
echo "Using git version of PortProtonQt..."
|
||||
PPQT_PKGBUILD="https://git.linux-gaming.ru/Boria138/PortProtonQt/raw/branch/main/build-aux/PKGBUILD-git"
|
||||
if [ "$LOCAL_MODE" = true ]; then
|
||||
echo "Using local PKGBUILD-git from repository..."
|
||||
PPQT_PKGBUILD=""
|
||||
else
|
||||
echo "Using stable version of PortProtonQt..."
|
||||
echo "Using stable version of PortProtonQt from main branch..."
|
||||
PPQT_PKGBUILD="https://git.linux-gaming.ru/Boria138/PortProtonQt/raw/branch/main/build-aux/PKGBUILD"
|
||||
fi
|
||||
|
||||
@@ -37,7 +67,12 @@ chmod +x ./make-aur-package.sh
|
||||
|
||||
echo "Building PortProtonQt from PKGBUILD..."
|
||||
echo "---------------------------------------------------------------"
|
||||
wget --retry-connrefused --tries=30 "$PPQT_PKGBUILD" -O ./PKGBUILD
|
||||
if [ "$LOCAL_MODE" = true ]; then
|
||||
cp ../PKGBUILD-git ./PKGBUILD
|
||||
else
|
||||
wget --retry-connrefused --tries=30 "$PPQT_PKGBUILD" -O ./PKGBUILD
|
||||
fi
|
||||
sed -i "s|source=(\"git+https://git.linux-gaming.ru/Boria138/PortProtonQt.git\")|source=(\"git+${REPO_URL}#branch=$BRANCH\")|" PKGBUILD
|
||||
makepkg -si --noconfirm
|
||||
|
||||
echo "Installing debloated packages..."
|
||||
@@ -46,7 +81,7 @@ wget --retry-connrefused --tries=30 "$EXTRA_PACKAGES" -O ./get-debloated-pkgs.sh
|
||||
chmod +x ./get-debloated-pkgs.sh
|
||||
./get-debloated-pkgs.sh --add-common --prefer-nano
|
||||
|
||||
if [ "$GIT_MODE" = true ]; then
|
||||
if [ "$LOCAL_MODE" = true ]; then
|
||||
# For git version, we use portprotonqt-git
|
||||
pacman -Q portprotonqt-git | awk '{print $2}' | cut -d- -f1 > ~/version
|
||||
else
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
pkgname=portprotonqt
|
||||
pkgver=0.1.9
|
||||
pkgver=0.1.10
|
||||
pkgrel=1
|
||||
pkgdesc="Modern GUI for managing and launching games from PortProton, Steam, and Epic Games Store"
|
||||
arch=('any')
|
||||
url="https://git.linux-gaming.ru/Boria138/PortProtonQt"
|
||||
license=('GPL-3.0')
|
||||
depends=('python-requests' 'python-babel' 'python-evdev' 'python-pyudev' 'python-orjson'
|
||||
'python-psutil' 'python-tqdm' 'python-vdf' 'python-libarchive-c' 'pyside6' 'python-rapidfuzz' 'icoextract' 'python-pillow' 'perl-image-exiftool' 'xdg-utils' 'python-beautifulsoup4' 'python-websocket-client' 'cabextract' 'unzip' 'curl' 'unrar')
|
||||
makedepends=('python-'{'build','installer','setuptools','wheel'})
|
||||
'python-psutil' 'python-tqdm' 'python-vdf' 'python-libarchive-c' 'pyside6' 'python-rapidfuzz' 'icoextract' 'python-pillow' 'perl-image-exiftool' 'xdg-utils' 'python-beautifulsoup4' 'python-websocket-client' 'cabextract' 'unzip' 'curl' 'unrar' 'qt6-svg')
|
||||
makedepends=('meson' 'ninja')
|
||||
source=("git+https://git.linux-gaming.ru/Boria138/PortProtonQt#tag=v$pkgver")
|
||||
sha256sums=('SKIP')
|
||||
|
||||
build() {
|
||||
cd "$srcdir/PortProtonQt"
|
||||
python -m build --wheel --no-isolation
|
||||
arch-meson PortProtonQt build
|
||||
meson compile -C build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/PortProtonQt"
|
||||
python -m installer --destdir="$pkgdir" dist/*.whl
|
||||
cp -r build-aux/share "$pkgdir/usr/"
|
||||
cp -r build-aux/lib "$pkgdir/usr/"
|
||||
meson install -C build --destdir "$pkgdir"
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ arch=('any')
|
||||
url="https://git.linux-gaming.ru/Boria138/PortProtonQt"
|
||||
license=('GPL-3.0')
|
||||
depends=('python-requests' 'python-babel' 'python-evdev' 'python-pyudev' 'python-orjson'
|
||||
'python-psutil' 'python-tqdm' 'python-vdf' 'python-libarchive-c' 'pyside6' 'icoextract' 'python-pillow' 'python-rapidfuzz' 'perl-image-exiftool' 'xdg-utils' 'python-beautifulsoup4' 'python-websocket-client' 'cabextract' 'unzip' 'curl' 'unrar')
|
||||
makedepends=('python-'{'build','installer','setuptools','wheel'})
|
||||
'python-psutil' 'python-tqdm' 'python-vdf' 'python-libarchive-c' 'pyside6' 'icoextract' 'python-pillow' 'python-rapidfuzz' 'perl-image-exiftool' 'xdg-utils' 'python-beautifulsoup4' 'python-websocket-client' 'cabextract' 'unzip' 'curl' 'unrar' 'qt6-svg')
|
||||
makedepends=('meson' 'ninja')
|
||||
source=("git+https://git.linux-gaming.ru/Boria138/PortProtonQt.git")
|
||||
sha256sums=('SKIP')
|
||||
|
||||
@@ -17,13 +17,10 @@ pkgver() {
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/PortProtonQt"
|
||||
python -m build --wheel --no-isolation
|
||||
arch-meson PortProtonQt build
|
||||
meson compile -C build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/PortProtonQt"
|
||||
python -m installer --destdir="$pkgdir" dist/*.whl
|
||||
cp -r build-aux/share "$pkgdir/usr/"
|
||||
cp -r build-aux/lib "$pkgdir/usr/"
|
||||
meson install -C build --destdir "$pkgdir"
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
%global pypi_name portprotonqt
|
||||
%global pypi_version 0.1.1
|
||||
%global pypi_version 0.1.10
|
||||
%global oname PortProtonQt
|
||||
%global build_timestamp %(date +"%Y%m%d")
|
||||
%global _python_no_extras_requires 1
|
||||
|
||||
%global rel_build 1.git.%{build_timestamp}%{?dist}
|
||||
|
||||
Name: python-%{pypi_name}-git
|
||||
Name: %{pypi_name}-git
|
||||
Version: %{pypi_version}
|
||||
Release: %{rel_build}
|
||||
Summary: Modern GUI for managing and launching games from PortProton, Steam, and Epic Games Store (development build)
|
||||
@@ -15,21 +15,15 @@ License: GPL-3.0
|
||||
URL: https://git.linux-gaming.ru/Boria138/PortProtonQt
|
||||
BuildArch: noarch
|
||||
|
||||
BuildRequires: meson >= 0.61.2
|
||||
BuildRequires: ninja-build
|
||||
BuildRequires: python3-devel
|
||||
BuildRequires: python3-wheel
|
||||
BuildRequires: python3-pip
|
||||
BuildRequires: python3-build
|
||||
BuildRequires: pyproject-rpm-macros
|
||||
BuildRequires: python3dist(setuptools)
|
||||
BuildRequires: git
|
||||
BuildRequires: systemd-rpm-macros
|
||||
|
||||
%description
|
||||
%{summary}
|
||||
Obsoletes: python3-%{pypi_name}-git < %{version}-%{release}
|
||||
Provides: python3-%{pypi_name}-git = %{version}-%{release}
|
||||
|
||||
%package -n python3-%{pypi_name}-git
|
||||
Summary: %{summary}
|
||||
%{?python_provide:%python_provide python3-%{pypi_name}}
|
||||
Requires: python3-babel
|
||||
Requires: python3-evdev
|
||||
Requires: python3-icoextract
|
||||
@@ -48,13 +42,14 @@ Requires: python3-rapidfuzz
|
||||
Requires: python3-libarchive-c
|
||||
Requires: perl-Image-ExifTool
|
||||
Requires: xdg-utils
|
||||
Requires: qt6-qtsvg
|
||||
Requires: cabextract
|
||||
Requires: gzip
|
||||
Requires: unzip
|
||||
Requires: curl
|
||||
Requires: unrar
|
||||
|
||||
%description -n python3-%{pypi_name}-git
|
||||
%description
|
||||
This application provides a sleek, intuitive graphical interface for managing and launching games from PortProton, Steam, and Epic Games Store. It consolidates your game libraries into a single, user-friendly hub for seamless navigation and organization. Its lightweight structure and cross-platform support deliver a cohesive gaming experience, eliminating the need for multiple launchers. Unique PortProton integration enhances Linux gaming, enabling effortless play of Windows-based titles with minimal setup.
|
||||
|
||||
%{?python_disable_dependency_generator}
|
||||
@@ -64,17 +59,17 @@ git clone https://git.linux-gaming.ru/Boria138/PortProtonQt.git
|
||||
|
||||
%build
|
||||
cd %{oname}
|
||||
%pyproject_wheel
|
||||
%meson -Dpython_libdir=%{python3_sitelib} -Dudevdir=%{_udevrulesdir}
|
||||
%meson_build
|
||||
|
||||
%install
|
||||
cd %{oname}
|
||||
%pyproject_install
|
||||
%pyproject_save_files %{pypi_name}
|
||||
cp -r build-aux/share %{buildroot}/usr/
|
||||
cp -r build-aux/lib %{buildroot}/usr/
|
||||
%meson_install
|
||||
%find_lang %{pypi_name}
|
||||
|
||||
%files -n python3-%{pypi_name}-git -f %{pyproject_files}
|
||||
%files -f %{oname}/%{pypi_name}.lang
|
||||
%{_bindir}/%{pypi_name}
|
||||
%{python3_sitelib}/%{pypi_name}/
|
||||
%{_datadir}/icons/hicolor/scalable/apps/ru.linux_gaming.PortProtonQt.svg
|
||||
%{_metainfodir}/ru.linux_gaming.PortProtonQt.metainfo.xml
|
||||
%{_udevrulesdir}/60-portprotonqt.rules
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
%global pypi_name portprotonqt
|
||||
%global pypi_version 0.1.9
|
||||
%global pypi_version 0.1.10
|
||||
%global oname PortProtonQt
|
||||
%global _python_no_extras_requires 1
|
||||
|
||||
Name: python-%{pypi_name}
|
||||
Name: %{pypi_name}
|
||||
Version: %{pypi_version}
|
||||
Release: 1%{?dist}
|
||||
Summary: Modern GUI for managing and launching games from PortProton, Steam, and Epic Games Store
|
||||
@@ -12,21 +12,15 @@ License: GPL-3.0
|
||||
URL: https://git.linux-gaming.ru/Boria138/PortProtonQt
|
||||
BuildArch: noarch
|
||||
|
||||
BuildRequires: meson >= 0.61.2
|
||||
BuildRequires: ninja-build
|
||||
BuildRequires: python3-devel
|
||||
BuildRequires: python3-wheel
|
||||
BuildRequires: python3-pip
|
||||
BuildRequires: python3-build
|
||||
BuildRequires: pyproject-rpm-macros
|
||||
BuildRequires: python3dist(setuptools)
|
||||
BuildRequires: git
|
||||
BuildRequires: systemd-rpm-macros
|
||||
|
||||
%description
|
||||
%{summary}
|
||||
Obsoletes: python3-%{pypi_name} < %{version}-%{release}
|
||||
Provides: python3-%{pypi_name} = %{version}-%{release}
|
||||
|
||||
%package -n python3-%{pypi_name}
|
||||
Summary: %{summary}
|
||||
%{?python_provide:%python_provide python3-%{pypi_name}}
|
||||
Requires: python3-babel
|
||||
Requires: python3-evdev
|
||||
Requires: python3-icoextract
|
||||
@@ -45,13 +39,14 @@ Requires: python3-rapidfuzz
|
||||
Requires: python3-libarchive-c
|
||||
Requires: perl-Image-ExifTool
|
||||
Requires: xdg-utils
|
||||
Requires: qt6-qtsvg
|
||||
Requires: cabextract
|
||||
Requires: gzip
|
||||
Requires: unzip
|
||||
Requires: curl
|
||||
Requires: unrar
|
||||
|
||||
%description -n python3-%{pypi_name}
|
||||
%description
|
||||
This application provides a sleek, intuitive graphical interface for managing and launching games from PortProton, Steam, and Epic Games Store. It consolidates your game libraries into a single, user-friendly hub for seamless navigation and organization. Its lightweight structure and cross-platform support deliver a cohesive gaming experience, eliminating the need for multiple launchers. Unique PortProton integration enhances Linux gaming, enabling effortless play of Windows-based titles with minimal setup.
|
||||
|
||||
%{?python_disable_dependency_generator}
|
||||
@@ -63,17 +58,17 @@ git checkout v%{pypi_version}
|
||||
|
||||
%build
|
||||
cd %{oname}
|
||||
%pyproject_wheel
|
||||
%meson -Dpython_libdir=%{python3_sitelib} -Dudevdir=%{_udevrulesdir}
|
||||
%meson_build
|
||||
|
||||
%install
|
||||
cd %{oname}
|
||||
%pyproject_install
|
||||
%pyproject_save_files %{pypi_name}
|
||||
cp -r build-aux/share %{buildroot}/usr/
|
||||
cp -r build-aux/lib %{buildroot}/usr/
|
||||
%meson_install
|
||||
%find_lang %{pypi_name}
|
||||
|
||||
%files -n python3-%{pypi_name} -f %{pyproject_files}
|
||||
%files -f %{oname}/%{pypi_name}.lang
|
||||
%{_bindir}/%{pypi_name}
|
||||
%{python3_sitelib}/%{pypi_name}/
|
||||
%{_datadir}/icons/hicolor/scalable/apps/ru.linux_gaming.PortProtonQt.svg
|
||||
%{_metainfodir}/ru.linux_gaming.PortProtonQt.metainfo.xml
|
||||
%{_udevrulesdir}/60-portprotonqt.rules
|
||||
|
||||
9
build-aux/portprotonqt
Normal file
9
build-aux/portprotonqt
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
|
||||
from portprotonqt.app import main
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -12,7 +12,9 @@ BASE_DIR = Path(__file__).parent.parent
|
||||
APPIMAGE_RECIPE = BASE_DIR / "build-aux" / "AppImageBuilder.yml"
|
||||
ARCH_PKGBUILD = BASE_DIR / "build-aux" / "PKGBUILD"
|
||||
FEDORA_SPEC = BASE_DIR / "build-aux" / "fedora.spec"
|
||||
FEDORA_GIT_SPEC = BASE_DIR / "build-aux" / "fedora-git.spec"
|
||||
PYPROJECT = BASE_DIR / "pyproject.toml"
|
||||
MESON_BUILD = BASE_DIR / "meson.build"
|
||||
APP_PY = BASE_DIR / "portprotonqt" / "app.py"
|
||||
GITEA_WORKFLOW = BASE_DIR / ".gitea" / "workflows" / "build.yml"
|
||||
CHANGELOG = BASE_DIR / "CHANGELOG.md"
|
||||
@@ -56,6 +58,7 @@ def bump_fedora(path: Path, old: str, new: str) -> bool:
|
||||
path.write_text(new_text, encoding='utf-8')
|
||||
return bool(count)
|
||||
|
||||
|
||||
def bump_pyproject(path: Path, old: str, new: str) -> bool:
|
||||
"""
|
||||
Update version in pyproject.toml under [project]
|
||||
@@ -69,6 +72,19 @@ def bump_pyproject(path: Path, old: str, new: str) -> bool:
|
||||
path.write_text(new_text, encoding='utf-8')
|
||||
return bool(count)
|
||||
|
||||
def bump_meson(path: Path, old: str, new: str) -> bool:
|
||||
"""
|
||||
Update version in meson.build
|
||||
"""
|
||||
if not path.exists():
|
||||
return False
|
||||
text = path.read_text(encoding='utf-8')
|
||||
pattern = re.compile(r"(version:\s*)'" + re.escape(old) + r"'")
|
||||
new_text, count = pattern.subn(lambda m: m.group(1) + f"'{new}'", text)
|
||||
if count:
|
||||
path.write_text(new_text, encoding='utf-8')
|
||||
return bool(count)
|
||||
|
||||
def bump_app_py(path: Path, old: str, new: str) -> bool:
|
||||
"""
|
||||
Update __app_version__ in app.py
|
||||
@@ -120,7 +136,9 @@ def main():
|
||||
(APPIMAGE_RECIPE, bump_appimage),
|
||||
(ARCH_PKGBUILD, bump_arch),
|
||||
(FEDORA_SPEC, bump_fedora),
|
||||
(FEDORA_GIT_SPEC, bump_fedora),
|
||||
(PYPROJECT, bump_pyproject),
|
||||
(MESON_BUILD, bump_meson),
|
||||
(APP_PY, bump_app_py),
|
||||
(GITEA_WORKFLOW, bump_workflow),
|
||||
(CHANGELOG, bump_changelog)
|
||||
|
||||
@@ -17,8 +17,9 @@ README_EN = GUIDE_DIR / "README.md"
|
||||
README_RU = GUIDE_DIR / "README.ru.md"
|
||||
LOCALES_PATH = Path(__file__).parent.parent / "portprotonqt" / "locales"
|
||||
THEMES_PATH = Path(__file__).parent.parent / "portprotonqt" / "themes"
|
||||
MESON_BUILD = Path(__file__).parent.parent / "portprotonqt" / "meson.build"
|
||||
README_FILES = [README_EN, README_RU]
|
||||
POT_FILE = LOCALES_PATH / "messages.pot"
|
||||
POT_FILE = LOCALES_PATH / "portprotonqt.pot"
|
||||
|
||||
# ---------- Версия проекта ----------
|
||||
def _get_version() -> str:
|
||||
@@ -27,16 +28,16 @@ def _get_version() -> str:
|
||||
# ---------- Обновление README ----------
|
||||
def _update_coverage(lines: list[str]) -> None:
|
||||
# Парсим статистику из вывода pybabel --statistics
|
||||
locales_stats = [line for line in lines if line.endswith(".po")]
|
||||
locales_stats = [line for line in lines if "portprotonqt.po" in line]
|
||||
# Извлекаем (count, pct, locale) и сортируем
|
||||
rows = sorted(
|
||||
(m := re.search(
|
||||
row for stat in locales_stats
|
||||
if (m := re.search(
|
||||
r"""(\d+\ of\ \d+).* # message counts
|
||||
\((\d+\%)\).* # message percentage
|
||||
locales\/(.*)\/LC_MESSAGES # locale name""",
|
||||
locales\/([^/]+)\/LC_MESSAGES # locale name""",
|
||||
stat, re.VERBOSE
|
||||
)) and m.groups()
|
||||
for stat in locales_stats
|
||||
)) and (row := m.groups())
|
||||
)
|
||||
|
||||
for md_file in README_FILES:
|
||||
@@ -59,14 +60,14 @@ def _update_coverage(lines: list[str]) -> None:
|
||||
"| Локаль | Прогресс | Переведено |\n"
|
||||
"| :----- | -------: | ---------: |\n"
|
||||
)
|
||||
fmt = lambda count, pct, loc: f"| [{loc}](./{loc}/LC_MESSAGES/messages.po) | {pct} | {count.replace(' of ', ' из ')} |"
|
||||
fmt = lambda count, pct, loc: f"| [{loc}](./{loc}/LC_MESSAGES/portprotonqt.po) | {pct} | {count.replace(' of ', ' из ')} |"
|
||||
else:
|
||||
table_header = (
|
||||
"<!-- Auto-generated coverage table -->\n\n"
|
||||
"| Locale | Progress | Translated |\n"
|
||||
"| :----- | -------: | ---------: |\n"
|
||||
)
|
||||
fmt = lambda count, pct, loc: f"| [{loc}](./{loc}/LC_MESSAGES/messages.po) | {pct} | {count} |"
|
||||
fmt = lambda count, pct, loc: f"| [{loc}](./{loc}/LC_MESSAGES/portprotonqt.po) | {pct} | {count} |"
|
||||
|
||||
# Собираем строки и добавляем '---' в конце
|
||||
coverage_table = (
|
||||
@@ -100,7 +101,7 @@ def _update_coverage(lines: list[str]) -> None:
|
||||
def compile_locales() -> None:
|
||||
CommandLineInterface().run([
|
||||
"pybabel", "compile", "--use-fuzzy", "--directory",
|
||||
f"{LOCALES_PATH.resolve()}", "--statistics"
|
||||
f"{LOCALES_PATH.resolve()}", "--domain=portprotonqt", "--statistics"
|
||||
])
|
||||
|
||||
def extract_strings() -> None:
|
||||
@@ -121,10 +122,39 @@ def update_locales() -> None:
|
||||
"pybabel", "update",
|
||||
f"--input-file={POT_FILE.resolve()}",
|
||||
f"--output-dir={LOCALES_PATH.resolve()}",
|
||||
"--domain=portprotonqt",
|
||||
"--ignore-obsolete",
|
||||
"--update-header-comment",
|
||||
])
|
||||
|
||||
def _update_meson_locales(new_locales: list[str]) -> None:
|
||||
"""Обновляет список языков в meson.build."""
|
||||
if not MESON_BUILD.exists():
|
||||
return
|
||||
|
||||
text = MESON_BUILD.read_text(encoding="utf-8")
|
||||
|
||||
# Ищем foreach lang : ['de', 'es', 'pt', 'ru']
|
||||
pattern = r"(foreach\s+lang\s*:\s*\[)([^\]]+)(\])"
|
||||
match = re.search(pattern, text)
|
||||
if not match:
|
||||
return
|
||||
|
||||
# Парсим текущий список языков
|
||||
current_langs_str = match.group(2)
|
||||
current_langs = re.findall(r"'([^']+)'", current_langs_str)
|
||||
|
||||
# Добавляем новые языки и сортируем
|
||||
all_langs = sorted(set(current_langs) | set(new_locales))
|
||||
|
||||
# Формируем новый список
|
||||
new_langs_str = ", ".join(f"'{lang}'" for lang in all_langs)
|
||||
new_text = text[:match.start()] + match.group(1) + new_langs_str + match.group(3) + text[match.end():]
|
||||
|
||||
if new_text != text:
|
||||
MESON_BUILD.write_text(new_text, encoding="utf-8")
|
||||
print(f"Updated meson.build with locales: {all_langs}")
|
||||
|
||||
def create_new(locales: list[str]) -> None:
|
||||
if not POT_FILE.exists():
|
||||
extract_strings()
|
||||
@@ -133,8 +163,11 @@ def create_new(locales: list[str]) -> None:
|
||||
"pybabel", "init",
|
||||
f"--input-file={POT_FILE.resolve()}",
|
||||
f"--output-dir={LOCALES_PATH.resolve()}",
|
||||
"--domain=portprotonqt",
|
||||
f"--locale={locale}"
|
||||
])
|
||||
# Обновляем meson.build с новыми локалями
|
||||
_update_meson_locales(locales)
|
||||
|
||||
# ---------- Игнорируемые префиксы для spellcheck ----------
|
||||
IGNORED_PREFIXES = ()
|
||||
@@ -148,6 +181,41 @@ def load_ignored_prefixes(ignore_file=".spellignore"):
|
||||
|
||||
IGNORED_PREFIXES = load_ignored_prefixes() + ("PortProton", "flatpak")
|
||||
|
||||
# ---------- Проверка fuzzy строк ----------
|
||||
def find_fuzzy_entries(filepath: Path) -> list[tuple[int, str, str]]:
|
||||
"""Находит fuzzy записи в .po файле. Возвращает список (номер_строки, msgid, флаги)."""
|
||||
fuzzy_entries = []
|
||||
lines = filepath.read_text(encoding='utf-8').splitlines()
|
||||
i = 0
|
||||
while i < len(lines):
|
||||
line = lines[i].strip()
|
||||
# Ищем комментарий с флагами, содержащий fuzzy
|
||||
if line.startswith('#,') and 'fuzzy' in line:
|
||||
flags = line[2:].strip()
|
||||
line_num = i + 1
|
||||
# Ищем следующий msgid
|
||||
msgid = ""
|
||||
i += 1
|
||||
while i < len(lines):
|
||||
next_line = lines[i].strip()
|
||||
if next_line.startswith('msgid '):
|
||||
match = re.match(r'^msgid\s+"(.*)"', next_line)
|
||||
if match:
|
||||
msgid = match.group(1)
|
||||
i += 1
|
||||
# Собираем многострочный msgid
|
||||
while i < len(lines) and lines[i].strip().startswith('"'):
|
||||
msgid += lines[i].strip()[1:-1]
|
||||
i += 1
|
||||
break
|
||||
i += 1
|
||||
# Пропускаем пустой msgid (заголовок PO файла)
|
||||
if msgid:
|
||||
fuzzy_entries.append((line_num, msgid, flags))
|
||||
else:
|
||||
i += 1
|
||||
return fuzzy_entries
|
||||
|
||||
# ---------- Проверка орфографии с параллелизмом ----------
|
||||
speller = YandexSpeller()
|
||||
MSGID_RE = re.compile(r'^msgid\s+"(.*)"')
|
||||
@@ -208,17 +276,36 @@ def main(args) -> int:
|
||||
if args.create_new:
|
||||
create_new(args.create_new)
|
||||
if args.spellcheck:
|
||||
files = list(LOCALES_PATH.glob("**/*.po")) + [POT_FILE]
|
||||
files = list(LOCALES_PATH.glob("**/portprotonqt.po")) + [POT_FILE]
|
||||
seen = set(); has_err = False
|
||||
issues_summary = defaultdict(list)
|
||||
fuzzy_summary = defaultdict(list)
|
||||
for f in files:
|
||||
if not f.exists() or f in seen: continue
|
||||
seen.add(f)
|
||||
# Проверка fuzzy строк (только для .po файлов)
|
||||
if f.suffix == '.po':
|
||||
fuzzy_entries = find_fuzzy_entries(f)
|
||||
if fuzzy_entries:
|
||||
fuzzy_summary[f] = fuzzy_entries
|
||||
has_err = True
|
||||
if check_file(f, issues_summary):
|
||||
has_err = True
|
||||
else:
|
||||
print(f"✅ {f} — no errors found.")
|
||||
if has_err:
|
||||
if f not in fuzzy_summary:
|
||||
print(f"✅ {f} — no errors found.")
|
||||
# Вывод fuzzy строк
|
||||
if fuzzy_summary:
|
||||
print("\n⚠️ Fuzzy Entries (require review before release):")
|
||||
for file, entries in fuzzy_summary.items():
|
||||
print(f"\n⚠ {file}")
|
||||
print("-----")
|
||||
for idx, (line_num, msgid, flags) in enumerate(entries, 1):
|
||||
print(f"{idx}. Line {line_num}: [{flags}]")
|
||||
print(f" msgid: \"{msgid[:80]}{'...' if len(msgid) > 80 else ''}\"")
|
||||
print("-----")
|
||||
# Вывод орфографических ошибок
|
||||
if issues_summary:
|
||||
print("\n📋 Summary of Spelling Errors:")
|
||||
for file, errs in issues_summary.items():
|
||||
print(f"\n✗ {file}")
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
## 📖 Overview
|
||||
|
||||
Localization in `PortProtonQT` is powered by `Babel` using `.po/.mo` files stored under `LC_MESSAGES/messages.po` for each language.
|
||||
Localization in `PortProtonQT` is powered by `Babel` using `.po/.mo` files stored under `LC_MESSAGES/portprotonqt.po` for each language.
|
||||
|
||||
Current translation status:
|
||||
|
||||
@@ -21,9 +21,10 @@ Current translation status:
|
||||
|
||||
| Locale | Progress | Translated |
|
||||
| :----- | -------: | ---------: |
|
||||
| [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 of 374 |
|
||||
| [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 of 374 |
|
||||
| [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 374 of 374 |
|
||||
| [de](./de/LC_MESSAGES/portprotonqt.po) | 0% | 0 of 376 |
|
||||
| [es](./es/LC_MESSAGES/portprotonqt.po) | 0% | 0 of 376 |
|
||||
| [pt](./pt/LC_MESSAGES/portprotonqt.po) | 0% | 0 of 376 |
|
||||
| [ru](./ru/LC_MESSAGES/portprotonqt.po) | 100% | 376 of 376 |
|
||||
|
||||
---
|
||||
|
||||
@@ -39,7 +40,7 @@ source .venv/bin/activate
|
||||
python dev-scripts/l10n.py --create-new <locale_code>
|
||||
```
|
||||
|
||||
2. Edit the file `portprotonqt/locales/<locale>/LC_MESSAGES/messages.po` in Poedit or any text editor.
|
||||
2. Edit the file `portprotonqt/locales/<locale>/LC_MESSAGES/portprotonqt.po` in Poedit or any text editor.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
## 📖 Обзор
|
||||
|
||||
Локализация в `PortProtonQT` осуществляется через систему `.po/.mo` файлов и управляется утилитой `Babel`. Все переводы находятся в подкаталогах вида `LC_MESSAGES/messages.po` для каждой поддерживаемой локали.
|
||||
Локализация в `PortProtonQT` осуществляется через систему `.po/.mo` файлов и управляется утилитой `Babel`. Все переводы находятся в подкаталогах вида `LC_MESSAGES/portprotonqt.po` для каждой поддерживаемой локали.
|
||||
|
||||
Текущий статус перевода:
|
||||
|
||||
@@ -21,9 +21,10 @@
|
||||
|
||||
| Локаль | Прогресс | Переведено |
|
||||
| :----- | -------: | ---------: |
|
||||
| [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 из 374 |
|
||||
| [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 из 374 |
|
||||
| [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 374 из 374 |
|
||||
| [de](./de/LC_MESSAGES/portprotonqt.po) | 0% | 0 из 376 |
|
||||
| [es](./es/LC_MESSAGES/portprotonqt.po) | 0% | 0 из 376 |
|
||||
| [pt](./pt/LC_MESSAGES/portprotonqt.po) | 0% | 0 из 376 |
|
||||
| [ru](./ru/LC_MESSAGES/portprotonqt.po) | 100% | 376 из 376 |
|
||||
|
||||
---
|
||||
|
||||
@@ -39,7 +40,7 @@ source .venv/bin/activate
|
||||
python dev-scripts/l10n.py --create-new <код_локали>
|
||||
```
|
||||
|
||||
2. Отредактируйте файл `portprotonqt/locales/<локаль>/LC_MESSAGES/messages.po` в Poedit или любом текстовом редакторе.
|
||||
2. Отредактируйте файл `portprotonqt/locales/<локаль>/LC_MESSAGES/portprotonqt.po` в Poedit или любом текстовом редакторе.
|
||||
|
||||
---
|
||||
|
||||
|
||||
83
meson.build
Normal file
83
meson.build
Normal file
@@ -0,0 +1,83 @@
|
||||
project('portprotonqt',
|
||||
version: '0.1.10',
|
||||
meson_version: '>= 0.61.2',
|
||||
license: 'GPL-3.0',
|
||||
)
|
||||
|
||||
# Project directories
|
||||
prefix = get_option('prefix')
|
||||
datadir = prefix / get_option('datadir')
|
||||
bindir = prefix / get_option('bindir')
|
||||
|
||||
# Python module for site-packages path
|
||||
python = import('python')
|
||||
python3 = python.find_installation('python3')
|
||||
pythondir = join_paths(prefix, python3.get_path('purelib'))
|
||||
|
||||
python_libdir = get_option('python_libdir')
|
||||
if python_libdir == ''
|
||||
python_installdir = pythondir
|
||||
else
|
||||
python_installdir = python_libdir
|
||||
endif
|
||||
|
||||
pkgdatadir = python_installdir / meson.project_name()
|
||||
|
||||
conf = configuration_data()
|
||||
conf.set('PYTHON', python.find_installation('python3').full_path())
|
||||
|
||||
# Install Python package
|
||||
subdir('portprotonqt')
|
||||
|
||||
# Install entry point script with proper name to avoid conflict in build directory
|
||||
configured_portprotonqt = configure_file(
|
||||
input: 'build-aux/portprotonqt',
|
||||
output: 'portprotonqt-script',
|
||||
configuration: conf,
|
||||
)
|
||||
|
||||
# Install the configured script with the correct name
|
||||
install_data(configured_portprotonqt,
|
||||
install_dir: bindir,
|
||||
install_mode: 'rwxr-xr-x',
|
||||
rename: 'portprotonqt')
|
||||
|
||||
# Install desktop file
|
||||
install_data(
|
||||
'build-aux/share/applications/ru.linux_gaming.PortProtonQt.desktop',
|
||||
install_dir: datadir / 'applications',
|
||||
)
|
||||
|
||||
# Install icon
|
||||
install_data(
|
||||
'build-aux/share/icons/hicolor/scalable/apps/ru.linux_gaming.PortProtonQt.svg',
|
||||
install_dir: datadir / 'icons/hicolor/scalable/apps',
|
||||
)
|
||||
|
||||
# Install metainfo
|
||||
install_data(
|
||||
'build-aux/share/metainfo/ru.linux_gaming.PortProtonQt.metainfo.xml',
|
||||
install_dir: datadir / 'metainfo',
|
||||
)
|
||||
|
||||
# Install bash completion
|
||||
install_data(
|
||||
'build-aux/share/bash-completion/completions/portprotonqt',
|
||||
install_dir: datadir / 'bash-completion/completions',
|
||||
)
|
||||
|
||||
# Install udev rules
|
||||
udevdir = get_option('udevdir')
|
||||
if udevdir == ''
|
||||
udev = dependency('udev', required: false)
|
||||
if udev.found()
|
||||
udevdir = udev.get_variable(pkgconfig: 'udevdir') / 'rules.d'
|
||||
else
|
||||
udevdir = prefix / get_option('libdir') / 'udev/rules.d'
|
||||
endif
|
||||
endif
|
||||
|
||||
install_data(
|
||||
'build-aux/lib/udev/rules.d/60-portprotonqt.rules',
|
||||
install_dir: udevdir,
|
||||
)
|
||||
11
meson_options.txt
Normal file
11
meson_options.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
option('udevdir',
|
||||
type: 'string',
|
||||
value: '',
|
||||
description: 'Directory for udev rules (auto-detected if empty)',
|
||||
)
|
||||
|
||||
option('python_libdir',
|
||||
type: 'string',
|
||||
value: '',
|
||||
description: 'Python site-packages directory (auto-detected if empty)',
|
||||
)
|
||||
@@ -556,8 +556,11 @@ class DetailPageAnimations:
|
||||
if detail_page and not detail_page.isHidden():
|
||||
detail_page.setGraphicsEffect(cast(Any, original_effect))
|
||||
except RuntimeError:
|
||||
logger.debug("Original effect already deleted")
|
||||
cleanup_callback()
|
||||
logger.debug("Detail page or effect already deleted")
|
||||
try:
|
||||
cleanup_callback()
|
||||
except RuntimeError:
|
||||
logger.debug("Error during cleanup callback")
|
||||
|
||||
# Check if animation is still valid before starting
|
||||
if animation and not detail_page.isHidden():
|
||||
@@ -594,10 +597,10 @@ class DetailPageAnimations:
|
||||
animation.setEasingCurve(easing_curve)
|
||||
|
||||
def slide_cleanup():
|
||||
# Check if page is still valid before cleanup
|
||||
if not detail_page or detail_page.isHidden():
|
||||
logger.debug("Detail page already cleaned up")
|
||||
cleanup_callback()
|
||||
try:
|
||||
cleanup_callback()
|
||||
except RuntimeError:
|
||||
logger.debug("Error during slide cleanup callback")
|
||||
|
||||
# Check if animation is still valid before starting
|
||||
if animation and not detail_page.isHidden():
|
||||
@@ -647,20 +650,28 @@ class DetailPageAnimations:
|
||||
return
|
||||
|
||||
def bounce_cleanup():
|
||||
# Check if page is still valid before cleanup
|
||||
if not detail_page or detail_page.isHidden():
|
||||
logger.debug("Detail page already cleaned up")
|
||||
cleanup_callback()
|
||||
try:
|
||||
cleanup_callback()
|
||||
except RuntimeError:
|
||||
logger.debug("Error during bounce cleanup callback")
|
||||
|
||||
group_anim.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
|
||||
self.animations[detail_page] = group_anim
|
||||
group_anim.finished.connect(bounce_cleanup)
|
||||
except RuntimeError:
|
||||
# Widget was already deleted, which is expected after deleteLater()
|
||||
logger.debug("Detail page already deleted during animation setup")
|
||||
cleanup_callback()
|
||||
try:
|
||||
cleanup_callback()
|
||||
except RuntimeError:
|
||||
pass
|
||||
except Exception as e:
|
||||
logger.error(f"Error in animate_detail_page_exit: {e}", exc_info=True)
|
||||
if detail_page in self.animations:
|
||||
self.animations.pop(detail_page, None)
|
||||
cleanup_callback()
|
||||
try:
|
||||
if detail_page in self.animations:
|
||||
self.animations.pop(detail_page, None)
|
||||
except RuntimeError:
|
||||
pass
|
||||
try:
|
||||
cleanup_callback()
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
@@ -17,7 +17,7 @@ from portprotonqt.cli import parse_args
|
||||
|
||||
__app_id__ = "ru.linux_gaming.PortProtonQt"
|
||||
__app_name__ = "PortProtonQt"
|
||||
__app_version__ = "0.1.9"
|
||||
__app_version__ = "0.1.10"
|
||||
|
||||
def get_version():
|
||||
try:
|
||||
|
||||
@@ -863,10 +863,12 @@ class DetailPageManager:
|
||||
logger.warning("Detail page not valid, bypassing animation and cleaning up directly")
|
||||
self._exit_animation_in_progress = False
|
||||
cleanup()
|
||||
except RuntimeError:
|
||||
logger.debug("Page deleted before animation could start")
|
||||
self._exit_animation_in_progress = False
|
||||
except Exception as e:
|
||||
logger.error(f"Error starting exit animation: {e}", exc_info=True)
|
||||
self._exit_animation_in_progress = False
|
||||
cleanup() # Fallback to cleanup if animation fails
|
||||
|
||||
def open_portproton_forum_topic(self, name):
|
||||
result = self.portproton_api.get_forum_topic_slug(name)
|
||||
|
||||
@@ -971,15 +971,69 @@ class ProtonManager(QDialog):
|
||||
if os.path.exists(filepath):
|
||||
total_size += os.path.getsize(filepath)
|
||||
|
||||
# Convert to human readable format
|
||||
for unit in ['B', 'KB', 'MB', 'GB']:
|
||||
if total_size < 1024.0:
|
||||
return f"{total_size:.1f} {unit}"
|
||||
total_size /= 1024.0
|
||||
return f"{total_size:.1f} TB"
|
||||
# Convert to human readable format (binary units)
|
||||
if total_size == 0:
|
||||
return "0 B"
|
||||
elif total_size < 1024:
|
||||
return f"{total_size}.0 B"
|
||||
elif total_size < 1024 * 1024:
|
||||
return f"{int(total_size / 1024)}.{int((total_size / 1024 * 10) % 10)} KiB"
|
||||
elif total_size < 1024 * 1024 * 1024:
|
||||
return f"{int(total_size / (1024 * 1024))}.{int((total_size / (1024 * 1024) * 10) % 10)} MiB"
|
||||
elif total_size < 1024 * 1024 * 1024 * 1024:
|
||||
return f"{int(total_size / (1024 * 1024 * 1024))}.{int((total_size / (1024 * 1024 * 1024) * 10) % 10)} GiB"
|
||||
else:
|
||||
return f"{int(total_size / (1024 * 1024 * 1024 * 1024))}.{int((total_size / (1024 * 1024 * 1024 * 1024) * 10) % 10)} TiB"
|
||||
except Exception:
|
||||
return _("Unknown")
|
||||
|
||||
def convert_size_to_bytes(self, size_str):
|
||||
"""Convert human-readable size string to bytes"""
|
||||
if not size_str or size_str == _("Unknown"):
|
||||
return 0
|
||||
|
||||
# Remove any extra text and extract the number and unit
|
||||
size_str = size_str.strip()
|
||||
|
||||
# Handle different units
|
||||
if size_str.endswith("TiB"):
|
||||
num = float(size_str[:-3].strip())
|
||||
return int(num * 1024 * 1024 * 1024 * 1024)
|
||||
elif size_str.endswith("GiB"):
|
||||
num = float(size_str[:-3].strip())
|
||||
return int(num * 1024 * 1024 * 1024)
|
||||
elif size_str.endswith("MiB"):
|
||||
num = float(size_str[:-3].strip())
|
||||
return int(num * 1024 * 1024)
|
||||
elif size_str.endswith("KiB"):
|
||||
num = float(size_str[:-3].strip())
|
||||
return int(num * 1024)
|
||||
elif size_str.endswith("B"):
|
||||
num = float(size_str[:-1].strip())
|
||||
return int(num)
|
||||
else:
|
||||
# If format is unknown, return 0
|
||||
return 0
|
||||
|
||||
def format_bytes(self, bytes_value):
|
||||
"""Format bytes to human-readable string"""
|
||||
if bytes_value == 0:
|
||||
return "0 B"
|
||||
elif bytes_value < 1024:
|
||||
return f"{bytes_value} B"
|
||||
elif bytes_value < 1024 * 1024:
|
||||
kb_value = bytes_value / 1024
|
||||
return f"{kb_value:.1f} KiB"
|
||||
elif bytes_value < 1024 * 1024 * 1024:
|
||||
mb_value = bytes_value / (1024 * 1024)
|
||||
return f"{mb_value:.1f} MiB"
|
||||
elif bytes_value < 1024 * 1024 * 1024 * 1024:
|
||||
gb_value = bytes_value / (1024 * 1024 * 1024)
|
||||
return f"{gb_value:.1f} GiB"
|
||||
else:
|
||||
tb_value = bytes_value / (1024 * 1024 * 1024 * 1024)
|
||||
return f"{tb_value:.1f} TiB"
|
||||
|
||||
def on_cell_clicked(self, row):
|
||||
"""Обработка клика по ячейке - переключение флажка при клике по любой ячейке в строке"""
|
||||
tab = self.tab_widget.currentWidget()
|
||||
@@ -1033,6 +1087,7 @@ class ProtonManager(QDialog):
|
||||
table = current_tab.findChild(QTableWidget)
|
||||
if table:
|
||||
selected_count = 0
|
||||
total_size = 0
|
||||
|
||||
for row in range(table.rowCount()):
|
||||
checkbox_widget = table.cellWidget(row, 0)
|
||||
@@ -1041,6 +1096,14 @@ class ProtonManager(QDialog):
|
||||
if checkbox and checkbox.isChecked():
|
||||
selected_count += 1
|
||||
|
||||
# Get the size for the selected item
|
||||
size_item = table.item(row, 2) # Size column
|
||||
if size_item:
|
||||
size_text = size_item.text()
|
||||
size_bytes = self.convert_size_to_bytes(size_text)
|
||||
if size_bytes:
|
||||
total_size += size_bytes
|
||||
|
||||
if selected_count > 0:
|
||||
selection_text = _('Selected {} assets:\n').format(selected_count)
|
||||
|
||||
@@ -1061,6 +1124,10 @@ class ProtonManager(QDialog):
|
||||
selection_text += f"{item_number}. {version_name}\n"
|
||||
item_number += 1
|
||||
|
||||
# Add total size to the selection text
|
||||
total_size_text = self.format_bytes(total_size)
|
||||
selection_text += _("\nTotal size to delete: {}\n").format(total_size_text)
|
||||
|
||||
self.download_btn.setText(_('Delete Selected'))
|
||||
self.download_btn.setEnabled(True)
|
||||
else:
|
||||
@@ -1078,9 +1145,49 @@ class ProtonManager(QDialog):
|
||||
if self.selected_assets:
|
||||
selection_text = _('Selected {} assets:\n').format(len(self.selected_assets))
|
||||
|
||||
total_size = 0
|
||||
|
||||
for i, asset_data in enumerate(self.selected_assets.values(), 1):
|
||||
selection_text += f"{i}. {asset_data['asset_name']}\n"
|
||||
|
||||
# Get size from JSON entry if available
|
||||
# We need to search through all tabs to find the matching entry
|
||||
for tab_index in range(self.tab_widget.count()):
|
||||
tab = self.tab_widget.widget(tab_index)
|
||||
table = tab.findChild(QTableWidget)
|
||||
if table and self.tab_widget.tabText(tab_index) != _("Installed"):
|
||||
# Search for the item in the table to get its size
|
||||
for row in range(table.rowCount()):
|
||||
table_item = table.item(row, 1) # Name column
|
||||
if table_item:
|
||||
# Extract just the name without extensions for comparison
|
||||
table_item_name = table_item.text()
|
||||
# Remove common extensions for comparison
|
||||
for ext in ['.tar.xz', '.tar.gz', '.zip']:
|
||||
if table_item_name.lower().endswith(ext):
|
||||
table_item_name = table_item_name[:-len(ext)]
|
||||
break
|
||||
|
||||
asset_name_for_comparison = asset_data['asset_name']
|
||||
for ext in ['.tar.xz', '.tar.gz', '.zip']:
|
||||
if asset_name_for_comparison.lower().endswith(ext):
|
||||
asset_name_for_comparison = asset_name_for_comparison[:-len(ext)]
|
||||
break
|
||||
|
||||
if table_item_name == asset_name_for_comparison:
|
||||
user_data = table_item.data(Qt.ItemDataRole.UserRole)
|
||||
if user_data and 'json_entry' in user_data:
|
||||
json_entry = user_data['json_entry']
|
||||
size_text = json_entry.get('size_human', 'Unknown')
|
||||
size_bytes = self.convert_size_to_bytes(size_text)
|
||||
if size_bytes:
|
||||
total_size += size_bytes
|
||||
break
|
||||
|
||||
# Add total size to the selection text
|
||||
total_size_text = self.format_bytes(total_size)
|
||||
selection_text += _("\nTotal size to download: {}\n").format(total_size_text)
|
||||
|
||||
self.selection_text.setPlainText(selection_text)
|
||||
self.download_btn.setText(_('Download Selected'))
|
||||
self.download_btn.setEnabled(True)
|
||||
|
||||
@@ -71,9 +71,11 @@ def load_pixmap_async(cover: str, width: int, height: int, callback: Callable[[Q
|
||||
pixmap = QPixmap(local_path)
|
||||
# Check if the pixmap loaded successfully
|
||||
if pixmap.isNull():
|
||||
logger.warning(f"Failed to load image from {local_path}")
|
||||
finish_with(pixmap)
|
||||
return
|
||||
logger.warning(f"Failed to load image from {local_path}, removing corrupted file")
|
||||
os.remove(local_path)
|
||||
else:
|
||||
finish_with(pixmap)
|
||||
return
|
||||
|
||||
def on_downloaded(result: str | None):
|
||||
pixmap = QPixmap()
|
||||
@@ -111,9 +113,11 @@ def load_pixmap_async(cover: str, width: int, height: int, callback: Callable[[Q
|
||||
pixmap = QPixmap(local_path)
|
||||
# Check if the pixmap loaded successfully
|
||||
if pixmap.isNull():
|
||||
logger.warning(f"Failed to load image from {local_path}")
|
||||
finish_with(pixmap)
|
||||
return
|
||||
logger.warning(f"Failed to load image from {local_path}, removing corrupted file")
|
||||
os.remove(local_path)
|
||||
else:
|
||||
finish_with(pixmap)
|
||||
return
|
||||
|
||||
def on_downloaded(result: str | None):
|
||||
pixmap = QPixmap()
|
||||
@@ -148,9 +152,11 @@ def load_pixmap_async(cover: str, width: int, height: int, callback: Callable[[Q
|
||||
pixmap = QPixmap(local_path)
|
||||
# Check if the pixmap loaded successfully
|
||||
if pixmap.isNull():
|
||||
logger.warning(f"Failed to load image from {local_path}")
|
||||
finish_with(pixmap)
|
||||
return
|
||||
logger.warning(f"Failed to load image from {local_path}, removing corrupted file")
|
||||
os.remove(local_path)
|
||||
else:
|
||||
finish_with(pixmap)
|
||||
return
|
||||
|
||||
def on_downloaded(result: str | None):
|
||||
pixmap = QPixmap()
|
||||
@@ -181,8 +187,13 @@ def load_pixmap_async(cover: str, width: int, height: int, callback: Callable[[Q
|
||||
# Check if the pixmap loaded successfully
|
||||
if pixmap.isNull():
|
||||
logger.warning(f"Failed to load image from {cover}")
|
||||
finish_with(pixmap)
|
||||
return
|
||||
# Remove corrupted file only if it's in the cache directory
|
||||
if cover.startswith(image_folder):
|
||||
logger.warning(f"Removing corrupted cached file {cover}")
|
||||
os.remove(cover)
|
||||
else:
|
||||
finish_with(pixmap)
|
||||
return
|
||||
|
||||
placeholder_path = theme_manager.get_theme_image("placeholder", current_theme_name)
|
||||
pixmap = QPixmap()
|
||||
|
||||
Binary file not shown.
@@ -9,7 +9,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-01-12 19:50+0500\n"
|
||||
"POT-Creation-Date: 2026-01-12 20:59+0500\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: de_DE\n"
|
||||
@@ -544,9 +544,21 @@ msgstr ""
|
||||
msgid "Selected {} assets:\n"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"Total size to delete: {}\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete Selected"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"Total size to download: {}\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "Downloading in Progress"
|
||||
msgstr ""
|
||||
|
||||
Binary file not shown.
@@ -9,7 +9,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-01-12 19:50+0500\n"
|
||||
"POT-Creation-Date: 2026-01-12 20:59+0500\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: es_ES\n"
|
||||
@@ -544,9 +544,21 @@ msgstr ""
|
||||
msgid "Selected {} assets:\n"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"Total size to delete: {}\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete Selected"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"Total size to download: {}\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "Downloading in Progress"
|
||||
msgstr ""
|
||||
|
||||
@@ -9,7 +9,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PortProtonQt 0.1.1\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-01-12 19:50+0500\n"
|
||||
"POT-Creation-Date: 2026-01-18 11:43+0500\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -542,9 +542,21 @@ msgstr ""
|
||||
msgid "Selected {} assets:\n"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"Total size to delete: {}\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete Selected"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"Total size to download: {}\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "Downloading in Progress"
|
||||
msgstr ""
|
||||
|
||||
BIN
portprotonqt/locales/pt/LC_MESSAGES/portprotonqt.mo
Normal file
BIN
portprotonqt/locales/pt/LC_MESSAGES/portprotonqt.mo
Normal file
Binary file not shown.
1286
portprotonqt/locales/pt/LC_MESSAGES/portprotonqt.po
Normal file
1286
portprotonqt/locales/pt/LC_MESSAGES/portprotonqt.po
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -9,8 +9,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-01-12 19:50+0500\n"
|
||||
"PO-Revision-Date: 2026-01-03 20:32+0500\n"
|
||||
"POT-Creation-Date: 2026-01-12 20:59+0500\n"
|
||||
"PO-Revision-Date: 2026-01-12 20:59+0500\n"
|
||||
"Last-Translator: \n"
|
||||
"Language: ru_RU\n"
|
||||
"Language-Team: ru_RU <LL@li.org>\n"
|
||||
@@ -506,7 +506,6 @@ msgstr "Бронза"
|
||||
msgid "Pending"
|
||||
msgstr "В ожидании"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Manage Wine versions"
|
||||
msgstr "Управление версиями WINE"
|
||||
|
||||
@@ -522,19 +521,16 @@ msgstr "Скачивание: "
|
||||
msgid "Download Selected"
|
||||
msgstr "Скачать выбранное"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Installed"
|
||||
msgstr "Удаление WINE"
|
||||
msgstr "Установленные"
|
||||
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Error loading wine data: {error}"
|
||||
msgstr "Ошибка загрузки WINE: {error}"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Version Name"
|
||||
msgstr "Версия WINE"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Size"
|
||||
msgstr "Размер"
|
||||
|
||||
@@ -555,9 +551,25 @@ msgstr "Выберите, чтобы удалить WINE"
|
||||
msgid "Selected {} assets:\n"
|
||||
msgstr "Выбранно {} WINE:\n"
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"Total size to delete: {}\n"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"Общий размер на удаление: {}\n"
|
||||
|
||||
msgid "Delete Selected"
|
||||
msgstr "Удалить выбранное"
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"Total size to download: {}\n"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"Общий размер на загрузку: {}\n"
|
||||
|
||||
msgid "Downloading in Progress"
|
||||
msgstr "Скачивание"
|
||||
|
||||
@@ -573,27 +585,26 @@ msgstr "Пожалуйста выберите хотя бы один WINE для
|
||||
msgid "Please wait for current downloading to complete."
|
||||
msgstr "Пожалуйста подождите завершения скачивания."
|
||||
|
||||
#, fuzzy
|
||||
msgid "Please select at least one version to delete."
|
||||
msgstr "Пожалуйста выберите хотя бы один WINE для удаления."
|
||||
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"Are you sure you want to delete {} selected version(s)?\n"
|
||||
"\n"
|
||||
"This action cannot be undone."
|
||||
msgstr ""
|
||||
"Вы уверены, что хотите удалить выбранные WINE?\n"
|
||||
"Вы уверены, что хотите удалить {} выбранные WINE?\n"
|
||||
"\n"
|
||||
"Это действие нельзя отменить."
|
||||
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Failed to remove version at {}: {}"
|
||||
msgstr "Не удалось удалить WINE '{}': {}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Successfully removed {} version(s)."
|
||||
msgstr "Успешно удалено {} WINE"
|
||||
msgstr "Успешно удалено {} WINE."
|
||||
|
||||
msgid "Downloading Complete"
|
||||
msgstr "Скачивание завершено"
|
||||
@@ -738,7 +749,6 @@ msgstr "Удалить Префикс"
|
||||
msgid "Clear Prefix"
|
||||
msgstr "Очистить Префикс"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Manage WINE versions"
|
||||
msgstr "Управление версиями WINE"
|
||||
|
||||
@@ -33,11 +33,21 @@ LOCALE_MAP = {
|
||||
'el': 'greek',
|
||||
}
|
||||
|
||||
translate = gettext.translation(
|
||||
domain="messages",
|
||||
localedir = Path(__file__).parent / "locales",
|
||||
fallback=True,
|
||||
)
|
||||
# Try system locale directory first, fallback to local for development
|
||||
_system_localedir = Path("/usr/share/locale")
|
||||
_local_localedir = Path(__file__).parent / "locales"
|
||||
|
||||
try:
|
||||
translate = gettext.translation(
|
||||
domain="portprotonqt",
|
||||
localedir=_system_localedir,
|
||||
)
|
||||
except FileNotFoundError:
|
||||
translate = gettext.translation(
|
||||
domain="portprotonqt",
|
||||
localedir=_local_localedir,
|
||||
fallback=True,
|
||||
)
|
||||
_ = translate.gettext
|
||||
|
||||
def get_system_locale():
|
||||
|
||||
54
portprotonqt/meson.build
Normal file
54
portprotonqt/meson.build
Normal file
@@ -0,0 +1,54 @@
|
||||
# Install Python source files
|
||||
install_data(
|
||||
'__init__.py',
|
||||
'animations.py',
|
||||
'app.py',
|
||||
'cli.py',
|
||||
'config_utils.py',
|
||||
'context_menu_manager.py',
|
||||
'custom_widgets.py',
|
||||
'detail_pages.py',
|
||||
'dialogs.py',
|
||||
'downloader.py',
|
||||
'egs_api.py',
|
||||
'game_card.py',
|
||||
'game_library_manager.py',
|
||||
'get_wine_module.py',
|
||||
'howlongtobeat_api.py',
|
||||
'image_utils.py',
|
||||
'input_manager.py',
|
||||
'keyboard_layouts.py',
|
||||
'localization.py',
|
||||
'logger.py',
|
||||
'main_window.py',
|
||||
'portproton_api.py',
|
||||
'preloader.py',
|
||||
'search_utils.py',
|
||||
'settings_manager.py',
|
||||
'steam_api.py',
|
||||
'system_overlay.py',
|
||||
'theme_manager.py',
|
||||
'theme_security.py',
|
||||
'time_utils.py',
|
||||
'tray_manager.py',
|
||||
'version_utils.py',
|
||||
'virtual_keyboard.py',
|
||||
install_dir: pkgdatadir,
|
||||
)
|
||||
|
||||
# Install themes
|
||||
install_subdir(
|
||||
'themes',
|
||||
install_dir: pkgdatadir,
|
||||
exclude_directories: ['__pycache__'],
|
||||
exclude_files: ['*.pyc'],
|
||||
)
|
||||
|
||||
# Install locales - only .mo files (compiled translations)
|
||||
# exclude_files doesn't work recursively, so we install each language manually
|
||||
foreach lang : ['de', 'es', 'pt', 'ru']
|
||||
install_data(
|
||||
'locales' / lang / 'LC_MESSAGES' / 'portprotonqt.mo',
|
||||
install_dir: get_option('localedir') / lang / 'LC_MESSAGES',
|
||||
)
|
||||
endforeach
|
||||
@@ -94,8 +94,13 @@ def parse_playtime_file(file_path):
|
||||
if len(parts) < 3:
|
||||
continue
|
||||
exe_path = parts[0]
|
||||
seconds = int(parts[2])
|
||||
playtime_data[exe_path] = seconds
|
||||
# Find playtime: first numeric value after exe_path
|
||||
# Format: <exe_path> <hash> <playtime_seconds> <platform> ...
|
||||
# Hash is 64 hex chars, playtime is digits only
|
||||
for i in range(1, len(parts)):
|
||||
if parts[i].isdigit():
|
||||
playtime_data[exe_path] = int(parts[i])
|
||||
break
|
||||
return playtime_data
|
||||
|
||||
def format_playtime(seconds):
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "portprotonqt"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
description = "A project to rewrite PortProton (PortWINE) using PySide"
|
||||
readme = "README.md"
|
||||
license = { text = "GPL-3.0" }
|
||||
|
||||
Reference in New Issue
Block a user