From 2851d5c30fa91e381127a05fbc3455ad4e037042 Mon Sep 17 00:00:00 2001 From: MorphyKutay Date: Mon, 13 Apr 2026 23:32:44 +0300 Subject: [PATCH 1/6] fix(i18n): localize CachyOS app shortcuts and sync TR Fluent - Add Fluent keys for Package Installer and Kernel Manager buttons - Use create_gtk_button + runtime locale updates for Applications row - Complete missing TR strings for DNS/custom apps (previous sync) --- i18n/en/cachyos_hello.ftl | 4 ++++ i18n/tr/cachyos_hello.ftl | 26 +++++++++++++++++++-- src/pages/i18n.rs | 8 +++++++ src/pages/mod.rs | 48 ++++++++++++++------------------------- 4 files changed, 53 insertions(+), 33 deletions(-) diff --git a/i18n/en/cachyos_hello.ftl b/i18n/en/cachyos_hello.ftl index 40b98c97..fc770d05 100644 --- a/i18n/en/cachyos_hello.ftl +++ b/i18n/en/cachyos_hello.ftl @@ -14,6 +14,10 @@ gaming-package-installed = Gaming packages already installed! winboat-package-installed = Winboat packages already installed! gpu-boosters-package-installed = GPU booster packages already installed! +# Tweaks page — quick launch (CachyOS apps) +app-cachyos-pi-label = CachyOS Package Installer +app-cachyos-kernel-manager-label = CachyOS Kernel Manager + # Application Browser page advanced-btn = advanced reset-btn = reset diff --git a/i18n/tr/cachyos_hello.ftl b/i18n/tr/cachyos_hello.ftl index d1612174..5db93e34 100644 --- a/i18n/tr/cachyos_hello.ftl +++ b/i18n/tr/cachyos_hello.ftl @@ -11,6 +11,12 @@ lock-doesnt-exist = Pacman veritabanı kilidi bulunmamaktadır! orphans-not-found = Hiçbir artık (orphan) paket bulunamadı! package-not-installed = '{$package_name}' paketi kurulmamıştır! gaming-package-installed = Oyun paketleri halihazırda kurulu! +winboat-package-installed = Winboat paketleri zaten kurulu! +gpu-boosters-package-installed = GPU güçlendirici paketleri zaten kurulu! + +# Tweaks page — quick launch (CachyOS apps) +app-cachyos-pi-label = CachyOS Paket Kurucu +app-cachyos-kernel-manager-label = CachyOS Çekirdek Yöneticisi # Application Browser page advanced-btn = gelişmiş @@ -31,6 +37,9 @@ apply = Uygula reset = Sıfırla enable-dot = DNS over TLS (DoT) etkinleştir dot-tooltip = Daha iyi gizlilik için DNS sorgularını TLS ile şifrele (sunucu desteği gerektirir) +enable-doh = HTTPS üzerinden DNS (DoH) etkinleştir +doh-tooltip = Daha iyi gizlilik için DNS sorgularını yerel blocky vekil sunucusu üzerinden HTTPS ile şifrele (sunucu desteği gerektirir; blocky kurar) +doh-blocky-install-failed = DoH desteği için blocky kurulamadı! test-latency = Seçili Sunucunun Gecikmesini Test Et test-latency-tooltip = Seçili DNS sunucusuna ağ gecikmesini ölç best-server = Gecikmeye Göre En İyi Sunucuyu Seç @@ -40,11 +49,21 @@ server-info = {""} latency-testing = test ediliyor... latency-timeout = zaman aşımı latency-no-result = hiçbir sunucu yanıt vermedi -dns-check-hint = Uyguladıktan sonra DNS sağlayıcınızı doğrulayın +custom-dns = Özel +dhcp-automatic = DHCP (otomatik) +custom-dns-ipv4 = IPv4 adresleri (virgülle ayrılmış): +custom-dns-ipv6 = IPv6 adresleri (virgülle ayrılmış): +custom-dns-dot-hostname = DoT ana bilgisayar adı (isteğe bağlı): +custom-dns-invalid = Lütfen en az bir IPv4 veya IPv6 adresi girin +custom-dns-invalid-hostname = Geçersiz DoT ana bilgisayar adı +custom-dns-doh-url = DoH URL’si (HTTPS üzerinden DNS için): +custom-dns-doh-url-required = Lütfen https:// ile başlayan geçerli bir DoH URL’si girin +dns-check-hint = Uyguladıktan sonra DNS sağlayıcınızı şu adreste doğrulayın: dns-server-changed = DNS sunucusu başarıyla değiştirildi! dns-server-failed = DNS sunucusu değiştirme işlemi başarısız oldu! dns-server-reset = DNS sunucusu eski haline getirildi! dns-server-reset-failed = DNS sunucusu sıfırlama işlemi başarısız oldu! +winboat-install-failed = Winboat kurulamadı! # Tweaks page (tweaks) tweak-enabled-title = {$tweak} etkinleştirildi. @@ -58,7 +77,7 @@ tweak-cachyupdate-tooltip = Güncelleme bildirim servisi # Tweaks page (fixes) remove-lock-title = Pacman veritabanı kilidini kaldır reinstall-title = Tüm paketleri yeniden kur -reset-keyrings-title = Reset keyrings +reset-keyrings-title = Anahtar halkalarını sıfırla update-system-title = Sistem güncellemesi remove-orphans-title = Artık (orphan) paketleri kaldır clear-pkgcache-title = Önbellekteki paketleri temizle @@ -66,6 +85,9 @@ rankmirrors-title = Yansıları hıza göre sırala dnsserver-title = DNS sunucusunu değiştir show-kwinw-debug-title = KWin (Wayland) hata ayıklama penceresini göster install-gaming-title = Oyun paketlerini kur +install-winboat-title = Winboat kur +install-gpu-boosters-title = GPU güçlendiricilerini kur +install-gpu-boosters-tooltip = AMD veya Intel GPU’larda dmemcg-booster ve plasma-foreground-booster paketlerini kur # Main Page (buttons) button-about-tooltip = Hakkında diff --git a/src/pages/i18n.rs b/src/pages/i18n.rs index a7888d09..782d80ce 100644 --- a/src/pages/i18n.rs +++ b/src/pages/i18n.rs @@ -8,6 +8,14 @@ fn update_translation_apps_section(section_box: >k::Box) { for section_box_element in section_box.children() { if let Ok(section_label) = section_box_element.clone().downcast::() { section_label.set_text(&fl!("applications")); + } else if let Ok(hbox) = section_box_element.downcast::() { + for child in hbox.children() { + if let Ok(btn) = child.downcast::() { + let id = btn.widget_name(); + let translated = crate::localization::get_locale_text(&id); + btn.set_label(&translated); + } + } } } } diff --git a/src/pages/mod.rs b/src/pages/mod.rs index d8c3298e..4e15c59c 100644 --- a/src/pages/mod.rs +++ b/src/pages/mod.rs @@ -189,6 +189,19 @@ fn create_fixes_section(builder: &Builder) -> gtk::Box { topbox } +fn spawn_cachyos_app(bin: &'static str) { + std::thread::spawn(move || { + let Ok(exec_path) = which(bin) else { + return; + }; + let Some(exec_path) = exec_path.to_str() else { + return; + }; + let exit_status = utils::spawn_detached(exec_path).expect("Failed to spawn process"); + debug!("Exit status successfully? = {:?}", exit_status.success()); + }); +} + fn create_apps_section() -> Option { let topbox = gtk::Box::new(gtk::Orientation::Vertical, 2); let box_collection = gtk::Box::new(gtk::Orientation::Horizontal, 10); @@ -199,14 +212,14 @@ fn create_apps_section() -> Option { // Check first btn. if Path::new("/sbin/cachyos-pi").exists() { - let cachyos_pi = gtk::Button::with_label("CachyOS PackageInstaller"); - cachyos_pi.connect_clicked(on_appbtn_clicked); + let cachyos_pi = create_gtk_button!("app-cachyos-pi-label"); + cachyos_pi.connect_clicked(|_| spawn_cachyos_app("cachyos-pi")); box_collection.pack_start(&cachyos_pi, true, true, 2); } // Check second btn. if Path::new("/sbin/cachyos-kernel-manager").exists() { - let cachyos_km = gtk::Button::with_label("CachyOS Kernel Manager"); - cachyos_km.connect_clicked(on_appbtn_clicked); + let cachyos_km = create_gtk_button!("app-cachyos-kernel-manager-label"); + cachyos_km.connect_clicked(|_| spawn_cachyos_app("cachyos-kernel-manager")); box_collection.pack_start(&cachyos_km, true, true, 2); } @@ -319,30 +332,3 @@ fn on_clear_pkgcache_btn_clicked(_: >k::Button) { actions::clear_pkgcache(crate::gui::run_command); }); } - -fn on_appbtn_clicked(button: >k::Button) { - // Get button label. - let name = button.label().unwrap(); - let binname = if name == "CachyOS PackageInstaller" { - "cachyos-pi" - } else if name == "CachyOS Kernel Manager" { - "cachyos-kernel-manager" - } else { - "" - }; - - // Get executable path, overwise return if it doesn't exist. - let exec_path = which(binname); - if exec_path.is_err() { - return; - } - - // Spawn child process in separate thread. - std::thread::spawn(move || { - // Get executable path. - let exec_path = exec_path.unwrap().to_str().unwrap().to_owned(); - let exit_status = utils::spawn_detached(&exec_path).expect("Failed to spawn process"); - - debug!("Exit status successfully? = {:?}", exit_status.success()); - }); -} From b8d42e6e1c841399ca510068a2dabb599be14085 Mon Sep 17 00:00:00 2001 From: MorphyKutay Date: Tue, 14 Apr 2026 22:05:21 +0300 Subject: [PATCH 2/6] fix(tweaks): avoid panic on spawn failure; align app buttons with PATH --- src/pages/mod.rs | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/pages/mod.rs b/src/pages/mod.rs index 4e15c59c..2ddc9e03 100644 --- a/src/pages/mod.rs +++ b/src/pages/mod.rs @@ -12,7 +12,7 @@ use gtk::prelude::*; use gtk::{glib, Builder}; use subprocess::Exec; -use tracing::debug; +use tracing::{debug, warn}; use which::which; #[macro_export] @@ -189,16 +189,16 @@ fn create_fixes_section(builder: &Builder) -> gtk::Box { topbox } -fn spawn_cachyos_app(bin: &'static str) { +fn spawn_cachyos_app(exec_path: String) { std::thread::spawn(move || { - let Ok(exec_path) = which(bin) else { - return; - }; - let Some(exec_path) = exec_path.to_str() else { - return; - }; - let exit_status = utils::spawn_detached(exec_path).expect("Failed to spawn process"); - debug!("Exit status successfully? = {:?}", exit_status.success()); + match utils::spawn_detached(&exec_path) { + Ok(exit_status) => { + debug!("Exit status successfully? = {:?}", exit_status.success()); + } + Err(e) => { + warn!(?e, path = %exec_path, "Failed to spawn CachyOS app"); + } + } }); } @@ -210,17 +210,22 @@ fn create_apps_section() -> Option { label.set_justify(gtk::Justification::Center); label.set_text(&fl!("applications")); - // Check first btn. - if Path::new("/sbin/cachyos-pi").exists() { - let cachyos_pi = create_gtk_button!("app-cachyos-pi-label"); - cachyos_pi.connect_clicked(|_| spawn_cachyos_app("cachyos-pi")); - box_collection.pack_start(&cachyos_pi, true, true, 2); + // Show buttons only when the executable is on PATH (same resolution as spawn). + if let Ok(path) = which("cachyos-pi") { + if let Some(path_str) = path.to_str() { + let exec_path = path_str.to_owned(); + let cachyos_pi = create_gtk_button!("app-cachyos-pi-label"); + cachyos_pi.connect_clicked(move |_| spawn_cachyos_app(exec_path.clone())); + box_collection.pack_start(&cachyos_pi, true, true, 2); + } } - // Check second btn. - if Path::new("/sbin/cachyos-kernel-manager").exists() { - let cachyos_km = create_gtk_button!("app-cachyos-kernel-manager-label"); - cachyos_km.connect_clicked(|_| spawn_cachyos_app("cachyos-kernel-manager")); - box_collection.pack_start(&cachyos_km, true, true, 2); + if let Ok(path) = which("cachyos-kernel-manager") { + if let Some(path_str) = path.to_str() { + let exec_path = path_str.to_owned(); + let cachyos_km = create_gtk_button!("app-cachyos-kernel-manager-label"); + cachyos_km.connect_clicked(move |_| spawn_cachyos_app(exec_path.clone())); + box_collection.pack_start(&cachyos_km, true, true, 2); + } } topbox.pack_start(&label, true, true, 5); From af6cadc61dc5cdcf0456727670bcf9db1a3505a3 Mon Sep 17 00:00:00 2001 From: MorphyKutay Date: Wed, 15 Apr 2026 12:14:00 +0300 Subject: [PATCH 3/6] fix(pages): eliminate panic paths and improve robustness in i18n update - Replace unwrap() with if let Ok() in update_translation_fixes_section to avoid panic on non-Button widgets during locale refresh - Replace `_ => panic!` with `_ => continue` in update_translations to gracefully skip unknown widget names instead of crashing - Guard against empty widget_name in update_translation_apps_section to prevent passing an empty key to get_locale_text - Log a warning instead of silently skipping when a binary path resolved by which() is not valid UTF-8 in create_apps_section - Remove unused `use std::str` import from mod.rs --- src/pages/i18n.rs | 14 +++++++++----- src/pages/mod.rs | 27 ++++++++++++++++----------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/pages/i18n.rs b/src/pages/i18n.rs index 782d80ce..64abf496 100644 --- a/src/pages/i18n.rs +++ b/src/pages/i18n.rs @@ -12,6 +12,9 @@ fn update_translation_apps_section(section_box: >k::Box) { for child in hbox.children() { if let Ok(btn) = child.downcast::() { let id = btn.widget_name(); + if id.is_empty() { + continue; + } let translated = crate::localization::get_locale_text(&id); btn.set_label(&translated); } @@ -24,10 +27,11 @@ fn update_translation_fixes_section(section_box: >k::Box) { for section_box_element in section_box.children() { if let Ok(button_box) = section_box_element.clone().downcast::() { for button_box_widget in button_box.children() { - let box_element_btn = button_box_widget.downcast::().unwrap(); - let widget_name = box_element_btn.widget_name(); - let translated_text = crate::localization::get_locale_text(&widget_name); - box_element_btn.set_label(&translated_text); + if let Ok(box_element_btn) = button_box_widget.downcast::() { + let widget_name = box_element_btn.widget_name(); + let translated_text = crate::localization::get_locale_text(&widget_name); + box_element_btn.set_label(&translated_text); + } } } else if let Ok(section_label) = section_box_element.downcast::() { section_label.set_text(&fl!("fixes")); @@ -115,7 +119,7 @@ pub fn update_translations(builder: &Builder) { "tweaksBrowserpage_apps" => { update_translation_apps_section(&second_child_child_box); }, - _ => panic!("Unknown widget!"), + _ => continue, } } } diff --git a/src/pages/mod.rs b/src/pages/mod.rs index 2ddc9e03..d6ff0090 100644 --- a/src/pages/mod.rs +++ b/src/pages/mod.rs @@ -6,7 +6,6 @@ use crate::ui::{Action, UI}; use crate::{actions, fl, systemd_units, utils}; use std::path::Path; -use std::str; use gtk::prelude::*; @@ -212,19 +211,25 @@ fn create_apps_section() -> Option { // Show buttons only when the executable is on PATH (same resolution as spawn). if let Ok(path) = which("cachyos-pi") { - if let Some(path_str) = path.to_str() { - let exec_path = path_str.to_owned(); - let cachyos_pi = create_gtk_button!("app-cachyos-pi-label"); - cachyos_pi.connect_clicked(move |_| spawn_cachyos_app(exec_path.clone())); - box_collection.pack_start(&cachyos_pi, true, true, 2); + match path.to_str() { + Some(path_str) => { + let exec_path = path_str.to_owned(); + let cachyos_pi = create_gtk_button!("app-cachyos-pi-label"); + cachyos_pi.connect_clicked(move |_| spawn_cachyos_app(exec_path.clone())); + box_collection.pack_start(&cachyos_pi, true, true, 2); + }, + None => warn!(path = ?path, "cachyos-pi path is not valid UTF-8; skipping button"), } } if let Ok(path) = which("cachyos-kernel-manager") { - if let Some(path_str) = path.to_str() { - let exec_path = path_str.to_owned(); - let cachyos_km = create_gtk_button!("app-cachyos-kernel-manager-label"); - cachyos_km.connect_clicked(move |_| spawn_cachyos_app(exec_path.clone())); - box_collection.pack_start(&cachyos_km, true, true, 2); + match path.to_str() { + Some(path_str) => { + let exec_path = path_str.to_owned(); + let cachyos_km = create_gtk_button!("app-cachyos-kernel-manager-label"); + cachyos_km.connect_clicked(move |_| spawn_cachyos_app(exec_path.clone())); + box_collection.pack_start(&cachyos_km, true, true, 2); + }, + None => warn!(path = ?path, "cachyos-kernel-manager path is not valid UTF-8; skipping button"), } } From fdbe38407fc21eb45359e6ddccd2a0ad5eaf5b50 Mon Sep 17 00:00:00 2001 From: MorphyKutay Date: Wed, 15 Apr 2026 12:21:56 +0300 Subject: [PATCH 4/6] fix(i18n): warn on unexpected section widget instead of silently skipping Replace `_ => continue` with a tracing warn! call so that unknown widget names in the tweaks page match arm produce a visible log entry rather than being swallowed silently, making layout regressions and missing translations easier to detect. --- src/pages/i18n.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/i18n.rs b/src/pages/i18n.rs index 64abf496..d41f7362 100644 --- a/src/pages/i18n.rs +++ b/src/pages/i18n.rs @@ -3,6 +3,7 @@ use crate::fl; use gtk::prelude::*; use gtk::Builder; +use tracing::warn; fn update_translation_apps_section(section_box: >k::Box) { for section_box_element in section_box.children() { @@ -119,7 +120,9 @@ pub fn update_translations(builder: &Builder) { "tweaksBrowserpage_apps" => { update_translation_apps_section(&second_child_child_box); }, - _ => continue, + name => { + warn!(widget_name = %name, "unexpected section box in tweaks page; translations may be incomplete"); + }, } } } From 647a2e1c4c162527637e3611572f0d581d1f3ebb Mon Sep 17 00:00:00 2001 From: MorphyKutay Date: Thu, 16 Apr 2026 10:06:28 +0300 Subject: [PATCH 5/6] fix(pages): extract kwin detection to util and drop Exec import from mod.rs Add utils::is_kwin_wayland() mirroring the upstream helper so mod.rs no longer needs a direct subprocess::Exec import, resolving the merge conflict between our branch and upstream/develop on that import line. Replace the inline pgrep block in create_fixes_section with the new util. --- src/pages/mod.rs | 21 +++++++-------------- src/utils.rs | 9 +++++++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/pages/mod.rs b/src/pages/mod.rs index d6ff0090..8d90cb65 100644 --- a/src/pages/mod.rs +++ b/src/pages/mod.rs @@ -10,7 +10,6 @@ use std::path::Path; use gtk::prelude::*; use gtk::{glib, Builder}; -use subprocess::Exec; use tracing::{debug, warn}; use which::which; @@ -168,20 +167,14 @@ fn create_fixes_section(builder: &Builder) -> gtk::Box { topbox.pack_end(&button_box_s, true, true, 5); topbox.pack_end(&button_box_f, true, true, 5); - if let Ok(pgrep_res) = - Exec::cmd("pgrep").args(&["kwin_wayland"]).stdout(subprocess::NullFile).join() - { - if pgrep_res.success() { - let kwinw_debug_btn = create_gtk_button!("show-kwinw-debug-title"); - kwinw_debug_btn.connect_clicked(move |_| { - // Spawn child process in separate thread. - std::thread::spawn(move || { - // do we even need to start that in separate thread. should be fine without - actions::launch_kwin_debug_window(); - }); + if utils::is_kwin_wayland() { + let kwinw_debug_btn = create_gtk_button!("show-kwinw-debug-title"); + kwinw_debug_btn.connect_clicked(move |_| { + std::thread::spawn(move || { + actions::launch_kwin_debug_window(); }); - button_box_frth.pack_end(&kwinw_debug_btn, true, true, 2); - } + }); + button_box_frth.pack_end(&kwinw_debug_btn, true, true, 2); } topbox.set_hexpand(true); diff --git a/src/utils.rs b/src/utils.rs index 33534ce3..18dc5f7a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -187,6 +187,15 @@ pub fn has_intel_or_amd_gpu() -> bool { data_obj.pci_devices.iter().any(|device| is_intel_amd_gpu(&device.vendor_id, &device.class_id)) } +/// Returns true if KWin is running under a Wayland session. +pub fn is_kwin_wayland() -> bool { + Exec::cmd("pgrep") + .args(&["kwin_wayland"]) + .stdout(subprocess::NullFile) + .join() + .is_ok_and(|status| status.success()) +} + #[cfg(test)] mod test { use super::*; From c98abb32306fcb4dcd6e8672cfaef0a211a61895 Mon Sep 17 00:00:00 2001 From: MorphyKutay Date: Wed, 29 Apr 2026 11:33:55 +0300 Subject: [PATCH 6/6] fix: align Turkish VRAM translation keys --- i18n/tr/cachyos_hello.ftl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/i18n/tr/cachyos_hello.ftl b/i18n/tr/cachyos_hello.ftl index 5db93e34..ed6c3fe1 100644 --- a/i18n/tr/cachyos_hello.ftl +++ b/i18n/tr/cachyos_hello.ftl @@ -12,7 +12,7 @@ orphans-not-found = Hiçbir artık (orphan) paket bulunamadı! package-not-installed = '{$package_name}' paketi kurulmamıştır! gaming-package-installed = Oyun paketleri halihazırda kurulu! winboat-package-installed = Winboat paketleri zaten kurulu! -gpu-boosters-package-installed = GPU güçlendirici paketleri zaten kurulu! +vram-management-package-installed = VRAM yönetim paketleri zaten kurulu! # Tweaks page — quick launch (CachyOS apps) app-cachyos-pi-label = CachyOS Paket Kurucu @@ -86,8 +86,8 @@ dnsserver-title = DNS sunucusunu değiştir show-kwinw-debug-title = KWin (Wayland) hata ayıklama penceresini göster install-gaming-title = Oyun paketlerini kur install-winboat-title = Winboat kur -install-gpu-boosters-title = GPU güçlendiricilerini kur -install-gpu-boosters-tooltip = AMD veya Intel GPU’larda dmemcg-booster ve plasma-foreground-booster paketlerini kur +install-vram-management-title = VRAM yönetimini kur +install-vram-management-tooltip = AMD veya Intel GPU’larda dmemcg-booster ve plasma-foreground-booster paketlerini kur # Main Page (buttons) button-about-tooltip = Hakkında