Skip to content

Commit b3cb1f3

Browse files
committed
✨ feat: Add i18n support and fix application icon
- Add APP_ICON constant to config.py for proper icon loading - Update i18n.py with correct text domain (biglinux-swap) - Add translation function import to all UI files: - application.py - window.py - utils.py - ui/unified_view.py - ui/components.py - Replace local gettext implementation in utils.py with centralized i18n module - Update application.py to use APP_ICON in about dialog
1 parent d3f7c77 commit b3cb1f3

9 files changed

Lines changed: 97 additions & 23 deletions

File tree

src/biglinux_swap/application.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
gi.require_version("Adw", "1")
1717
from gi.repository import Adw, Gio, GLib
1818

19-
from biglinux_swap.config import APP_ID, APP_NAME, APP_VERSION
19+
from biglinux_swap.config import APP_ICON, APP_ID, APP_NAME, APP_VERSION
20+
from biglinux_swap.i18n import _
2021
from biglinux_swap.services import ConfigService, MeminfoService, SwapService
2122
from biglinux_swap.window import SwapWindow
2223

@@ -153,7 +154,7 @@ def _on_about(
153154
about.set_issue_url(
154155
"https://github.com/biglinux/biglinux-systemd-swap-gui/issues"
155156
)
156-
about.set_application_icon(APP_ID)
157+
about.set_application_icon(APP_ICON)
157158

158159
about.set_developers(
159160
[

src/biglinux_swap/config.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
APP_DEVELOPER = "BigLinux Team"
2828
APP_WEBSITE = "https://github.com/biglinux/biglinux-systemd-swap-gui"
2929
APP_ISSUE_URL = f"{APP_WEBSITE}/issues"
30+
APP_ICON = "biglinux-swap"
31+
3032

3133
# =============================================================================
3234
# Window Configuration
@@ -305,7 +307,7 @@ class DiscardPolicy(Enum):
305307
class ZswapConfig:
306308
"""Zswap configuration."""
307309

308-
compressor: Compressor = Compressor.ZSTD
310+
compressor: Compressor = Compressor.LZ4
309311
max_pool_percent: int = ZSWAP_MAX_POOL_DEFAULT
310312
zpool: str = "zsmalloc"
311313
shrinker_enabled: bool = True
@@ -432,7 +434,7 @@ def from_dict(cls, data: dict[str, Any]) -> SwapConfig:
432434
if "zswap" in data:
433435
zs = data["zswap"]
434436
config.zswap = ZswapConfig(
435-
compressor=Compressor(zs.get("compressor", "zstd")),
437+
compressor=Compressor(zs.get("compressor", "lz4")),
436438
max_pool_percent=zs.get("max_pool_percent", ZSWAP_MAX_POOL_DEFAULT),
437439
zpool=zs.get("zpool", "zsmalloc"),
438440
shrinker_enabled=zs.get("shrinker_enabled", True),

src/biglinux_swap/i18n.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
#
4+
# i18n.py - Utilities for translation support
5+
#
6+
import gettext
7+
import os
8+
from typing import Callable
9+
10+
# Determine locale directory (works in AppImage and system install)
11+
locale_dir = "/usr/share/locale" # Default for system install
12+
13+
# Check if we're in an AppImage
14+
if "APPIMAGE" in os.environ or "APPDIR" in os.environ:
15+
# Running from AppImage
16+
# i18n.py is in: src/biglinux_swap/i18n.py
17+
# We need to get to: usr/share/locale
18+
script_dir = os.path.dirname(os.path.abspath(__file__)) # src/biglinux_swap
19+
src_dir = os.path.dirname(script_dir) # src
20+
appdir_root = os.path.dirname(src_dir) # AppDir root (squashfs-root)
21+
appimage_locale = os.path.join(appdir_root, "usr", "share", "locale") # usr/share/locale
22+
23+
if os.path.isdir(appimage_locale):
24+
locale_dir = appimage_locale
25+
26+
# Configure the translation text domain for biglinux-swap
27+
gettext.bindtextdomain("biglinux-swap", locale_dir)
28+
gettext.textdomain("biglinux-swap")
29+
30+
# Export _ directly as the translation function with explicit type
31+
_: Callable[[str], str] = gettext.gettext

src/biglinux_swap/services.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,69 @@ def __init__(self) -> None:
6565
self._config: SwapConfig | None = None
6666

6767
def load(self) -> SwapConfig:
68-
"""Load configuration from system files."""
68+
"""Load configuration from system files.
69+
70+
Priority:
71+
1. /etc/systemd/swap.conf (user config)
72+
2. /usr/share/systemd-swap/swap-default.conf (defaults)
73+
3. Current kernel values from /sys/module/zswap/parameters/ (fallback)
74+
"""
6975
config = SwapConfig()
7076

77+
# Track which values were explicitly set in config files
78+
explicitly_set: set[str] = set()
79+
7180
if DEFAULT_CONFIG.exists():
7281
default_values = self._parse_config_file(DEFAULT_CONFIG)
82+
explicitly_set.update(default_values.keys())
7383
config = self._apply_values(config, default_values)
7484

7585
if CONFIG_FILE.exists():
7686
user_values = self._parse_config_file(CONFIG_FILE)
87+
explicitly_set.update(user_values.keys())
7788
config = self._apply_values(config, user_values)
7889

90+
# Read current kernel values for parameters not explicitly configured
91+
self._apply_kernel_values(config, explicitly_set)
92+
7993
self._config = config
8094
logger.info("Configuration loaded")
8195
return config
8296

97+
def _apply_kernel_values(
98+
self, config: SwapConfig, explicitly_set: set[str]
99+
) -> None:
100+
"""Read current kernel values for parameters not in config files.
101+
102+
This ensures the GUI shows the actual system state, not hardcoded defaults.
103+
"""
104+
zswap_params = Path("/sys/module/zswap/parameters")
105+
106+
# Read zswap compressor from kernel if not in config
107+
if "zswap_compressor" not in explicitly_set and zswap_params.is_dir():
108+
compressor_path = zswap_params / "compressor"
109+
if compressor_path.exists():
110+
try:
111+
kernel_compressor = compressor_path.read_text().strip()
112+
with contextlib.suppress(ValueError):
113+
config.zswap.compressor = Compressor(kernel_compressor)
114+
logger.debug(
115+
"Using kernel zswap compressor: %s", kernel_compressor
116+
)
117+
except OSError:
118+
pass
119+
120+
# Read zswap max_pool_percent from kernel if not in config
121+
if "zswap_max_pool_percent" not in explicitly_set and zswap_params.is_dir():
122+
pool_path = zswap_params / "max_pool_percent"
123+
if pool_path.exists():
124+
try:
125+
kernel_pool = pool_path.read_text().strip()
126+
config.zswap.max_pool_percent = int(kernel_pool)
127+
logger.debug("Using kernel zswap max_pool_percent: %s", kernel_pool)
128+
except (OSError, ValueError):
129+
pass
130+
83131
def get(self) -> SwapConfig:
84132
"""Get current config, loading if necessary."""
85133
if self._config is None:

src/biglinux_swap/ui/components.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
gi.require_version("Adw", "1")
1616
from gi.repository import Adw, Gtk
1717

18+
from biglinux_swap.i18n import _
19+
20+
1821

1922
def create_preferences_group(
2023
title: str,

src/biglinux_swap/ui/settings_view.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,6 @@ def _setup_ui(self) -> None:
192192
"Compressor",
193193
subtitle="Compression algorithm",
194194
options=compressor_names,
195-
selected_index=1, # zstd
196195
on_selected=self._on_zswap_compressor_changed,
197196
)
198197
self._zswap_expander.add_row(self._zswap_compressor_combo)

src/biglinux_swap/ui/unified_view.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@
6868
)
6969
from biglinux_swap.ui.memory_chart import MemoryChartWidget
7070
from biglinux_swap.utils import TooltipHelper
71+
from biglinux_swap.i18n import _
72+
7173

7274
if TYPE_CHECKING:
7375
from biglinux_swap.services import (

src/biglinux_swap/utils.py

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
from __future__ import annotations
99

1010
import contextlib
11-
import gettext
12-
import locale
1311
import logging
1412
import shutil
1513
import subprocess
@@ -24,6 +22,7 @@
2422
from gi.repository import Adw, Gdk, GLib, Gtk
2523

2624
from biglinux_swap.config import CONFIG_PATH
25+
from biglinux_swap.i18n import _
2726

2827
logger = logging.getLogger(__name__)
2928

@@ -157,23 +156,9 @@ def run_as_root(command: list[str]) -> tuple[bool, str, str]:
157156

158157

159158
# =============================================================================
160-
# Internationalization
159+
# X11 Detection Helper
161160
# =============================================================================
162161

163-
LOCALE_DIR = Path("/usr/share/locale")
164-
DOMAIN = "biglinux-swap"
165-
166-
with contextlib.suppress(locale.Error):
167-
locale.setlocale(locale.LC_ALL, "")
168-
169-
try:
170-
translation = gettext.translation(DOMAIN, LOCALE_DIR, fallback=True)
171-
_ = translation.gettext
172-
except Exception:
173-
174-
def _(text: str) -> str:
175-
return text
176-
177162

178163
def _is_x11_backend() -> bool:
179164
"""Check if running on X11 backend."""
@@ -190,6 +175,7 @@ def _is_x11_backend() -> bool:
190175
# Tooltip Texts
191176
# =============================================================================
192177

178+
193179
TOOLTIPS = {
194180
# Mode selection
195181
"mode_auto": _(

src/biglinux_swap/window.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
enable_systemd_swap,
2424
stop_systemd_swap,
2525
)
26+
from biglinux_swap.i18n import _
27+
2628

2729
if TYPE_CHECKING:
2830
from biglinux_swap.services import ConfigService, MeminfoService, SwapService

0 commit comments

Comments
 (0)