Commit 2d21f551 authored by Roman Alifanov's avatar Roman Alifanov

Add i18n with Russian translation, NVIDIA-aware update dialog, meson build and ALT spec

parent d98ec7e7
spec: .gear/ximper-system-updater.spec
tar: .
tar: .gear/predownloaded-development name=@name@-development-@version@ base=
%define xdg_name ru.ximperlinux.SystemUpdater
Name: ximper-system-updater
Version: 0.1.0
Release: alt1
License: GPL-3.0
Summary: GTK4 frontend for the Ximper Linux system updater
Group: Graphical desktop/Other
Url: https://gitlab.eterfund.ru/ximperlinux/ximper-system-updater
Source: %name-%version.tar
Source1: %name-development-%version.tar
BuildRequires(pre): rpm-macros-meson
BuildRequires: meson
BuildRequires: golang
BuildRequires: blueprint-compiler
BuildRequires: gcc
BuildRequires: pkgconfig(gtk4)
BuildRequires: pkgconfig(libadwaita-1)
BuildRequires: pkgconfig(gio-2.0)
BuildRequires: pkgconfig(glib-2.0)
Requires: eepm-dbus
%description
GTK4 / libadwaita GUI client for the EEPM D-Bus service. Shows
available system, kernel and Play application updates and drives the
update process via the ru.etersoft.EPM D-Bus interface.
%prep
%setup -a1
%build
export GOFLAGS="-mod=vendor"
%meson
%meson_build
%install
%meson_install
%find_lang %name
%files -f %name.lang
%_bindir/%name
%_desktopdir/%xdg_name.desktop
%_userunitdir/%name.service
%changelog
* Fri Apr 10 2026 Roman Alifanov <ximper@altlinux.org> 0.1.0-alt1
- initial build
desktop_file = i18n.merge_file(
input: 'ru.ximperlinux.SystemUpdater.desktop.in',
output: 'ru.ximperlinux.SystemUpdater.desktop',
type: 'desktop',
po_dir: meson.project_source_root() / 'po',
install: true,
install_dir: get_option('datadir') / 'applications',
)
desktop_validate = find_program('desktop-file-validate', required: false)
if desktop_validate.found()
test('Validate desktop file', desktop_validate, args: [desktop_file])
endif
service_conf = configuration_data()
service_conf.set('bindir', get_option('prefix') / get_option('bindir'))
configure_file(
input: 'ximper-system-updater.service.in',
output: 'ximper-system-updater.service',
configuration: service_conf,
install: true,
install_dir: get_option('prefix') / 'lib' / 'systemd' / 'user',
)
[Desktop Entry]
# Translators: app name shown in the application launcher
Name=Ximper Linux Updater
Comment=Manage system, kernel and application updates
Keywords=update;upgrade;packages;system;
Exec=ximper-system-updater
Icon=software-update-available-symbolic
Terminal=false
Type=Application
Categories=GNOME;GTK;System;PackageManager;
StartupNotify=true
X-SingleMainWindow=true
X-GNOME-Gettext-Domain=ximper-system-updater
[Unit]
Description=Ximper System Updater background service
PartOf=graphical-session.target
After=graphical-session.target
[Service]
Type=simple
ExecStart=@bindir@/ximper-system-updater --background
Restart=on-failure
RestartSec=10
[Install]
WantedBy=graphical-session.target
......@@ -8,7 +8,7 @@ import (
"github.com/diamondburned/gotk4/pkg/gtk/v4"
)
var translationDomain = "somedomain"
var translationDomain = "ximper-system-updater"
func SetTranslationDomain(domain string) {
translationDomain = domain
......
package hardware
import (
"os"
"strings"
)
func HasNVIDIAModule() bool {
data, err := os.ReadFile("/proc/modules")
if err != nil {
return false
}
for _, line := range strings.Split(string(data), "\n") {
name, _, _ := strings.Cut(line, " ")
if strings.HasPrefix(name, "nvidia") {
return true
}
}
return false
}
package i18n
import (
"fmt"
gcore "github.com/diamondburned/gotk4/pkg/core/glib"
)
const Domain = "ximper-system-updater"
const defaultLocaleDir = "/usr/share/locale"
func Init() {
gcore.InitI18n(Domain, defaultLocaleDir)
}
// T returns the translation of msg from our text domain.
func T(msg string) string {
return gcore.Local(msg)
}
// Tf returns T(msg) formatted with args.
func Tf(msg string, args ...any) string {
return fmt.Sprintf(gcore.Local(msg), args...)
}
// N is a no-op marker so xgettext picks up identifier strings.
// Translate at the display point with T.
func N(msg string) string {
return msg
}
......@@ -3,6 +3,7 @@ package main
import (
"SystemUpdater/backend/eepm"
_ "SystemUpdater/lib/gtks/logging"
"SystemUpdater/lib/i18n"
"SystemUpdater/pkg/storage"
"SystemUpdater/service"
"SystemUpdater/store"
......@@ -16,6 +17,8 @@ import (
)
func main() {
i18n.Init()
st := store.NewStore()
defer st.Close()
......
project(
'ximper-system-updater',
version: '0.1.0',
meson_version: '>= 1.0.0',
)
i18n = import('i18n')
subdir('po')
subdir('data')
find_program('go')
find_program('blueprint-compiler')
custom_target(
'ximper-system-updater',
build_by_default: true,
build_always_stale: true,
console: true,
install: true,
install_dir: get_option('bindir'),
output: 'ximper-system-updater',
command: [
find_program('sh'), '-c',
'set -e; go generate -C "@0@" ./...; go build -C "@0@" -trimpath -ldflags="-s -w" -o "@1@" .'.format(
meson.current_source_dir(),
meson.current_build_dir() / 'ximper-system-updater',
),
],
)
# Please keep this list alphabetically sorted
ru
data/ru.ximperlinux.SystemUpdater.desktop.in
main.go
store/state.go
ui/window.go
ui/window.blp
ui/components/category_row.go
ui/pages/history.go
ui/pages/history.blp
ui/pages/loading.blp
ui/pages/noupdates.blp
ui/pages/package_list.go
ui/pages/process-page.blp
ui/pages/update_process.go
ui/pages/updates-list.blp
i18n.gettext('ximper-system-updater', preset: 'glib')
msgid ""
msgstr ""
"Project-Id-Version: ximper-system-updater\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-04-10 00:00+0000\n"
"PO-Revision-Date: 2026-04-10 00:00+0300\n"
"Last-Translator: Ximper <noreply@ximperlinux.ru>\n"
"Language-Team: Russian\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n"
#: ui/window.blp
msgid "System Updater"
msgstr "Обновление системы"
#: data/ru.ximperlinux.SystemUpdater.desktop.in
msgid "Ximper Linux Updater"
msgstr "Обновление Ximper Linux"
#: ui/window.blp
msgid "Update History"
msgstr "История обновлений"
#: ui/window.blp
msgid "About"
msgstr "О программе"
#: ui/pages/updates-list.blp
msgid "Update"
msgstr "Обновить"
#: ui/pages/process-page.blp
msgid "The update process is underway..."
msgstr "Идёт процесс обновления…"
#: ui/pages/process-page.blp
msgid "Show more information"
msgstr "Подробности"
#: ui/pages/process-page.blp ui/pages/update_process.go
msgid "Updating complete!"
msgstr "Обновление завершено!"
#: ui/pages/process-page.blp ui/pages/update_process.go
msgid "Click on button below to restart device"
msgstr "Нажмите на кнопку ниже, чтобы перезагрузить устройство"
#: ui/pages/process-page.blp
msgid "Reboot"
msgstr "Перезагрузить"
#: ui/pages/process-page.blp
msgid "Updating"
msgstr "Обновление"
#: ui/pages/history.blp
msgid "History"
msgstr "История"
#: ui/pages/noupdates.blp
msgid "System is up to date"
msgstr "Система обновлена"
#: ui/pages/loading.blp
msgid "Loading…"
msgstr "Загрузка…"
#: store/state.go
msgid "System"
msgstr "Система"
#: store/state.go
msgid "Kernel"
msgstr "Ядро"
#: store/state.go
msgid "Play Apps"
msgstr "Приложения epm play"
#: ui/components/category_row.go
#, c-format
msgid "%d packages"
msgstr "пакетов: %d"
#: ui/window.go
msgid "Select Components to Update"
msgstr "Выбор компонентов для обновления"
#: ui/window.go
msgid "Choose which components you want to update:"
msgstr "Выберите, что обновить:"
#: ui/window.go
#, c-format
msgid "System (%d packages)"
msgstr "Система (пакетов: %d)"
#: ui/window.go
#, c-format
msgid "Kernel (%d modules)"
msgstr "Ядро (модулей: %d)"
#: ui/window.go
msgid "Play apps"
msgstr "Приложения epm play"
#: ui/window.go
msgid "Cancel"
msgstr "Отмена"
#: ui/window.go
msgid "No Selection"
msgstr "Ничего не выбрано"
#: ui/window.go
msgid "Please select at least one component to update"
msgstr "Выберите хотя бы один компонент для обновления"
#: ui/window.go
msgid "NVIDIA driver detected: system and kernel updates must be installed together."
msgstr "Обнаружен драйвер NVIDIA: системные пакеты и ядро нужно обновлять вместе."
#: ui/window.go ui/pages/update_process.go
msgid "Update Failed"
msgstr "Сбой обновления"
#: ui/window.go
msgid "Reboot System?"
msgstr "Перезагрузить систему?"
#: ui/window.go
msgid "The system needs to be rebooted to complete the update."
msgstr "Для завершения обновления необходимо перезагрузить систему."
#: ui/window.go
msgid "OK"
msgstr "ОК"
#: ui/pages/history.go
msgid "Success"
msgstr "Успешно"
#: ui/pages/history.go
msgid "Failed"
msgstr "Сбой"
#: ui/pages/history.go
#, c-format
msgid "%s • %s • %d packages • %ds"
msgstr "%s • %s • пакетов: %d • %d с"
#: ui/pages/history.go
#, c-format
msgid "... and %d more lines"
msgstr "…и ещё строк: %d"
#: ui/pages/history.go
msgid "Error"
msgstr "Ошибка"
#: ui/pages/update_process.go
msgid "You can close this window"
msgstr "Можно закрыть это окно"
#: ui/pages/update_process.go
msgid "Update Partially Complete"
msgstr "Обновление выполнено частично"
#: ui/pages/update_process.go
msgid "Some updates failed, but system packages were updated. A reboot is recommended."
msgstr "Часть обновлений не установилась, но системные пакеты обновлены. Рекомендуется перезагрузка."
#: ui/pages/update_process.go
msgid "The update encountered an error. Please check the logs."
msgstr "При обновлении возникла ошибка. Проверьте журнал."
#!/bin/sh
# Should run from project root dir
for lang in $(grep -v '^#' po/LINGUAS); do
msgmerge -U --backup=off po/$lang.po po/ximper-system-updater.pot
done
#!/bin/sh
# Should run from project root dir
set -e
sh po/update_potfiles.sh
# Extract from Go sources (i18n.T / Tf / Tn / N)
grep '\.go$' ./po/POTFILES.in | xargs xgettext \
--language=C \
--keyword=_ \
--keyword=T \
--keyword=Tf \
--keyword=N \
--keyword=Tn:1,2 \
--from-code=UTF-8 \
--add-comments \
--package-name=ximper-system-updater \
-o po/ximper-system-updater-go.pot
# Extract from Blueprint files (_("...") syntax)
grep '\.blp$' ./po/POTFILES.in | xargs xgettext \
--language=C \
--keyword=_ \
--from-code=UTF-8 \
--add-comments \
--package-name=ximper-system-updater \
-o po/ximper-system-updater-blp.pot
msgcat po/ximper-system-updater-go.pot po/ximper-system-updater-blp.pot \
-o po/ximper-system-updater.pot
rm -f po/ximper-system-updater-go.pot po/ximper-system-updater-blp.pot
#!/bin/sh
# Should run from project root dir
tmp=./po/unsort-POTFILES
: > "$tmp"
# Go sources that use i18n.T / i18n.Tf / i18n.N
find ./ -iname "*.go" -type f \
-not -path "./_build/*" \
-exec grep -lE 'i18n\.(T|Tf|Tn|N)\(' {} + \
| while read -r file; do
echo "${file#./}" >> "$tmp"
done
# Blueprint UI sources
find ./ui -iname "*.blp" -type f | while read -r file; do
echo "${file#./}" >> "$tmp"
done
sort -u "$tmp" > ./po/POTFILES.in
rm "$tmp"
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the ximper-system-updater package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: ximper-system-updater\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-04-10 00:00+0000\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"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: ui/window.blp
msgid "System Updater"
msgstr ""
#: data/ru.ximperlinux.SystemUpdater.desktop.in
msgid "Ximper Linux Updater"
msgstr ""
#: ui/window.blp
msgid "Update History"
msgstr ""
#: ui/window.blp
msgid "About"
msgstr ""
#: ui/pages/updates-list.blp
msgid "Update"
msgstr ""
#: ui/pages/process-page.blp
msgid "The update process is underway..."
msgstr ""
#: ui/pages/process-page.blp
msgid "Show more information"
msgstr ""
#: ui/pages/process-page.blp ui/pages/update_process.go
msgid "Updating complete!"
msgstr ""
#: ui/pages/process-page.blp ui/pages/update_process.go
msgid "Click on button below to restart device"
msgstr ""
#: ui/pages/process-page.blp
msgid "Reboot"
msgstr ""
#: ui/pages/process-page.blp
msgid "Updating"
msgstr ""
#: ui/pages/history.blp
msgid "History"
msgstr ""
#: ui/pages/noupdates.blp
msgid "System is up to date"
msgstr ""
#: ui/pages/loading.blp
msgid "Loading…"
msgstr ""
#: store/state.go
msgid "System"
msgstr ""
#: store/state.go
msgid "Kernel"
msgstr ""
#: store/state.go
msgid "Play Apps"
msgstr ""
#: ui/components/category_row.go
#, c-format
msgid "%d packages"
msgstr ""
#: ui/window.go
msgid "Select Components to Update"
msgstr ""
#: ui/window.go
msgid "Choose which components you want to update:"
msgstr ""
#: ui/window.go
#, c-format
msgid "System (%d packages)"
msgstr ""
#: ui/window.go
#, c-format
msgid "Kernel (%d modules)"
msgstr ""
#: ui/window.go
msgid "Play apps"
msgstr ""
#: ui/window.go
msgid "Cancel"
msgstr ""
#: ui/window.go
msgid "No Selection"
msgstr ""
#: ui/window.go
msgid "Please select at least one component to update"
msgstr ""
#: ui/window.go
msgid "NVIDIA driver detected: system and kernel updates must be installed together."
msgstr ""
#: ui/window.go ui/pages/update_process.go
msgid "Update Failed"
msgstr ""
#: ui/window.go
msgid "Reboot System?"
msgstr ""
#: ui/window.go
msgid "The system needs to be rebooted to complete the update."
msgstr ""
#: ui/window.go
msgid "OK"
msgstr ""
#: ui/pages/history.go
msgid "Success"
msgstr ""
#: ui/pages/history.go
msgid "Failed"
msgstr ""
#: ui/pages/history.go
#, c-format
msgid "%s • %s • %d packages • %ds"
msgstr ""
#: ui/pages/history.go
#, c-format
msgid "... and %d more lines"
msgstr ""
#: ui/pages/history.go
msgid "Error"
msgstr ""
#: ui/pages/update_process.go
msgid "You can close this window"
msgstr ""
#: ui/pages/update_process.go
msgid "Update Partially Complete"
msgstr ""
#: ui/pages/update_process.go
msgid "Some updates failed, but system packages were updated. A reboot is recommended."
msgstr ""
#: ui/pages/update_process.go
msgid "The update encountered an error. Please check the logs."
msgstr ""
package store
import "SystemUpdater/model"
import (
"SystemUpdater/lib/i18n"
"SystemUpdater/model"
)
type AppPhase int
......@@ -57,15 +60,15 @@ func NewState() *State {
return &State{
Phase: PhaseLoading,
SystemUpdates: &model.UpdateCategory{
Name: "System",
Name: i18n.N("System"),
Enabled: true,
},
KernelUpdates: &model.UpdateCategory{
Name: "Kernel",
Name: i18n.N("Kernel"),
Enabled: true,
},
PlayUpdates: &model.UpdateCategory{
Name: "Play Apps",
Name: i18n.N("Play Apps"),
Enabled: true,
},
ActiveUpdate: nil,
......
......@@ -5,6 +5,7 @@ import (
"fmt"
gtksbuilder "SystemUpdater/lib/gtks/builder"
"SystemUpdater/lib/i18n"
"SystemUpdater/model"
"SystemUpdater/store"
......@@ -34,7 +35,7 @@ func NewCategoryRow(category string, st *store.Store, onNavigate func()) *Catego
panic(err)
}
cr.Row.SetTitle(category)
cr.Row.SetTitle(i18n.T(category))
cr.Row.ConnectActivated(func() {
if cr.onNavigate != nil {
......@@ -46,10 +47,10 @@ func NewCategoryRow(category string, st *store.Store, onNavigate func()) *Catego
}
func (cr *CategoryRow) Update(cat *model.UpdateCategory) {
cr.Row.SetTitle(cat.Name)
cr.Row.SetTitle(i18n.T(cat.Name))
if cat.Available {
subtitle := fmt.Sprintf("%d packages", len(cat.Packages))
subtitle := i18n.Tf("%d packages", len(cat.Packages))
if cat.DownloadSize > 0 {
subtitle += fmt.Sprintf(", %s", formatBytes(cat.DownloadSize))
}
......
......@@ -2,11 +2,11 @@ package pages
import (
_ "embed"
"fmt"
"strings"
"time"
gtksbuilder "SystemUpdater/lib/gtks/builder"
"SystemUpdater/lib/i18n"
"SystemUpdater/model"
"github.com/diamondburned/gotk4-adwaita/pkg/adw"
......@@ -50,15 +50,15 @@ func (p *HistoryPage) createHistoryRow(entry model.HistoryEntry) *adw.ExpanderRo
row.SetTitle(timestamp.Format("Jan 02, 2006 15:04"))
categoriesStr := strings.Join(entry.Categories, ", ")
status := "Success"
status := i18n.T("Success")
icon := "emblem-ok-symbolic"
if !entry.Success {
status = "Failed"
status = i18n.T("Failed")
icon = "dialog-error-symbolic"
}
row.SetSubtitle(fmt.Sprintf("%s • %s • %d packages • %ds",
row.SetSubtitle(i18n.Tf("%s • %s • %d packages • %ds",
categoriesStr, status, entry.PackagesUpdated, entry.DurationSeconds))
row.AddPrefix(gtk.NewImageFromIconName(icon))
......@@ -77,14 +77,14 @@ func (p *HistoryPage) createHistoryRow(entry model.HistoryEntry) *adw.ExpanderRo
if len(entry.Log) > 5 {
moreRow := adw.NewActionRow()
moreRow.SetTitle(fmt.Sprintf("... and %d more lines", len(entry.Log)-5))
moreRow.SetTitle(i18n.Tf("... and %d more lines", len(entry.Log)-5))
row.AddRow(moreRow)
}
}
if entry.ErrorMessage != "" {
errorRow := adw.NewActionRow()
errorRow.SetTitle("Error: " + entry.ErrorMessage)
errorRow.SetTitle(i18n.T("Error") + ": " + entry.ErrorMessage)
errorRow.AddCSSClass("error")
row.AddRow(errorRow)
}
......
......@@ -3,7 +3,7 @@ using Adw 1;
Adw.StatusPage loading_page {
title: _("Loading…");
icon-name: "emblem-synchronizing-symbolic";
icon-name: "software-update-available-symbolic";
Adw.Spinner {
halign: center;
......
......@@ -4,6 +4,7 @@ import (
_ "embed"
gtksbuilder "SystemUpdater/lib/gtks/builder"
"SystemUpdater/lib/i18n"
"SystemUpdater/model"
"SystemUpdater/ui/components"
......@@ -28,7 +29,11 @@ func NewPackageListPage(category string, packages []model.Package) *PackageListP
panic(err)
}
page.NavigationPage.SetTitle(category)
title := category
if category == "Play" {
title = i18n.N("Play Apps")
}
page.NavigationPage.SetTitle(i18n.T(title))
page.SetPackages(packages)
return page
......
......@@ -10,6 +10,7 @@ import (
"github.com/diamondburned/gotk4/pkg/gtk/v4"
gtksbuilder "SystemUpdater/lib/gtks/builder"
"SystemUpdater/lib/i18n"
)
//go:generate blueprint-compiler compile process-page.blp --output process-page.ui
......@@ -77,21 +78,21 @@ func (p *UpdateProcessPage) UpdateProgress(event model.EventData) {
func (p *UpdateProcessPage) ShowComplete(success bool, showReboot bool) {
switch {
case success && showReboot:
p.finishStatusPage.SetTitle("Updating complete!")
p.finishStatusPage.SetTitle(i18n.T("Updating complete!"))
p.finishStatusPage.SetIconName("face-smile-big-symbolic")
p.finishStatusPage.SetDescription("Click on button below to restart device")
p.finishStatusPage.SetDescription(i18n.T("Click on button below to restart device"))
case success:
p.finishStatusPage.SetTitle("Updating complete!")
p.finishStatusPage.SetTitle(i18n.T("Updating complete!"))
p.finishStatusPage.SetIconName("face-smile-big-symbolic")
p.finishStatusPage.SetDescription("You can close this window")
p.finishStatusPage.SetDescription(i18n.T("You can close this window"))
case showReboot:
p.finishStatusPage.SetTitle("Update Partially Complete")
p.finishStatusPage.SetTitle(i18n.T("Update Partially Complete"))
p.finishStatusPage.SetIconName("dialog-warning-symbolic")
p.finishStatusPage.SetDescription("Some updates failed, but system packages were updated. A reboot is recommended.")
p.finishStatusPage.SetDescription(i18n.T("Some updates failed, but system packages were updated. A reboot is recommended."))
default:
p.finishStatusPage.SetTitle("Update Failed")
p.finishStatusPage.SetTitle(i18n.T("Update Failed"))
p.finishStatusPage.SetIconName("dialog-error-symbolic")
p.finishStatusPage.SetDescription("The update encountered an error. Please check the logs.")
p.finishStatusPage.SetDescription(i18n.T("The update encountered an error. Please check the logs."))
}
p.rebootBtn.SetVisible(showReboot)
......
......@@ -3,11 +3,12 @@ package ui
import (
_ "embed"
"context"
"fmt"
"log"
"strings"
gtksbuilder "SystemUpdater/lib/gtks/builder"
"SystemUpdater/lib/hardware"
"SystemUpdater/lib/i18n"
"SystemUpdater/model"
"SystemUpdater/service"
"SystemUpdater/store"
......@@ -171,8 +172,8 @@ func (w *Window) showUpdateDialog() {
dialog := adw.NewMessageDialog(
&w.Window.Window,
"Select Components to Update",
"Choose which components you want to update:",
i18n.T("Select Components to Update"),
i18n.T("Choose which components you want to update:"),
)
box := gtk.NewBox(gtk.OrientationVertical, 12)
......@@ -185,7 +186,7 @@ func (w *Window) showUpdateDialog() {
if state.SystemUpdates.Available {
systemCheck = gtk.NewCheckButtonWithLabel(
fmt.Sprintf("System (%d packages)", len(state.SystemUpdates.Packages)),
i18n.Tf("System (%d packages)", len(state.SystemUpdates.Packages)),
)
systemCheck.SetActive(true)
box.Append(systemCheck)
......@@ -193,21 +194,49 @@ func (w *Window) showUpdateDialog() {
if state.KernelUpdates.Available {
kernelCheck = gtk.NewCheckButtonWithLabel(
fmt.Sprintf("Kernel (%d modules)", len(state.KernelUpdates.Packages)),
i18n.Tf("Kernel (%d modules)", len(state.KernelUpdates.Packages)),
)
kernelCheck.SetActive(true)
box.Append(kernelCheck)
}
if state.PlayUpdates.Available {
playCheck = gtk.NewCheckButtonWithLabel("Play apps")
playCheck = gtk.NewCheckButtonWithLabel(i18n.T("Play apps"))
playCheck.SetActive(true)
box.Append(playCheck)
}
// On systems with the proprietary nvidia kernel module loaded the
// driver package is pinned to the running kernel — system and
// kernel updates must be installed together or the GPU breaks on
// next boot. When both are available, link the two checkboxes so
// the user can't deselect one without the other.
if systemCheck != nil && kernelCheck != nil && hardware.HasNVIDIAModule() {
linking := false
link := func(src, dst *gtk.CheckButton) {
src.ConnectToggled(func() {
if linking {
return
}
linking = true
dst.SetActive(src.Active())
linking = false
})
}
link(systemCheck, kernelCheck)
link(kernelCheck, systemCheck)
note := gtk.NewLabel(i18n.T("NVIDIA driver detected: system and kernel updates must be installed together."))
note.SetWrap(true)
note.SetXAlign(0)
note.AddCSSClass("dim-label")
note.AddCSSClass("caption")
box.Append(note)
}
dialog.SetExtraChild(box)
dialog.AddResponse("cancel", "Cancel")
dialog.AddResponse("update", "Update")
dialog.AddResponse("cancel", i18n.T("Cancel"))
dialog.AddResponse("update", i18n.T("Update"))
dialog.SetResponseAppearance("update", adw.ResponseSuggested)
dialog.SetDefaultResponse("update")
......@@ -225,7 +254,7 @@ func (w *Window) showUpdateDialog() {
}
if len(categories) == 0 {
w.showError("No Selection", "Please select at least one component to update")
w.showError(i18n.T("No Selection"), i18n.T("Please select at least one component to update"))
return
}
......@@ -267,7 +296,7 @@ func (w *Window) runUpdate(categories []string) {
if err := w.updateSvc.RunUpdates(w.ctx); err != nil {
log.Printf("Update failed: %v", err)
glib.IdleAdd(func() {
w.showError("Update Failed", err.Error())
w.showError(i18n.T("Update Failed"), err.Error())
})
}
}()
......@@ -276,11 +305,11 @@ func (w *Window) runUpdate(categories []string) {
func (w *Window) onRebootClicked() {
dialog := adw.NewMessageDialog(
&w.Window.Window,
"Reboot System?",
"The system needs to be rebooted to complete the update.",
i18n.T("Reboot System?"),
i18n.T("The system needs to be rebooted to complete the update."),
)
dialog.AddResponse("cancel", "Cancel")
dialog.AddResponse("reboot", "Reboot")
dialog.AddResponse("cancel", i18n.T("Cancel"))
dialog.AddResponse("reboot", i18n.T("Reboot"))
dialog.SetResponseAppearance("reboot", adw.ResponseDestructive)
dialog.SetDefaultResponse("cancel")
......@@ -338,7 +367,7 @@ func (w *Window) showError(title, message string) {
scrolled.SetChild(textView)
dialog.SetExtraChild(scrolled)
dialog.AddResponse("ok", "OK")
dialog.AddResponse("ok", i18n.T("OK"))
dialog.SetDefaultResponse("ok")
dialog.Present()
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment