fix: localize batched app update notifications

This commit is contained in:
VAIO73
2026-09-17 13:12:02 +02:00
parent d61719dcaf
commit 661b944e0c
4 changed files with 85 additions and 23 deletions
File diff suppressed because one or more lines are too long
+36 -22
View File
@@ -582,20 +582,29 @@ def _format_system_startup(data: Dict[str, Any], language: str = 'en') -> Tuple[
return title, '\n'.join(parts)
def _format_app_update_available(data: Dict[str, Any]) -> Tuple[str, str]:
def _format_app_update_available(data: Dict[str, Any],
language: str = 'en') -> Tuple[str, str]:
"""Render one app update or a scheduled multi-app summary."""
hostname = str(data.get("hostname") or _get_hostname())
updates = data.get("updates")
hostname = str(data.get('hostname') or _get_hostname())
app_fallback = runtime_message('appUpdates.app', language) or 'app'
unknown = runtime_message('appUpdates.unknown', language) or 'unknown'
updates = data.get('updates')
if not isinstance(updates, list) or len(updates) < 2:
app_name = str(data.get("app_name") or "app")
vmid = data.get("vmid", "")
ct_name = str(data.get("ct_name") or f"CT-{vmid}")
installed = str(data.get("installed") or "unknown")
latest = str(data.get("latest") or "unknown")
app_name = str(data.get('app_name') or app_fallback)
vmid = data.get('vmid', '')
ct_name = str(data.get('ct_name') or f'CT-{vmid}')
installed = str(data.get('installed') or unknown)
latest = str(data.get('latest') or unknown)
return (
f"{hostname}: {app_name} update available on CT {vmid}",
f"{app_name} on CT {vmid} ({ct_name}) has a new version:\n"
f" {installed}{latest}",
runtime_message(
'appUpdates.singleTitle', language,
hostname=hostname, app_name=app_name, vmid=vmid,
),
runtime_message(
'appUpdates.singleBody', language,
app_name=app_name, vmid=vmid, ct_name=ct_name,
installed=installed, latest=latest,
),
)
clean_updates = []
@@ -607,26 +616,31 @@ def _format_app_update_available(data: Dict[str, Any]) -> Tuple[str, str]:
except (TypeError, ValueError):
continue
clean_updates.append({
"vmid": vmid,
"app_name": str(item.get("app_name") or "app"),
"installed": str(item.get("installed") or "unknown"),
"latest": str(item.get("latest") or "unknown"),
'vmid': vmid,
'app_name': str(item.get('app_name') or app_fallback),
'installed': str(item.get('installed') or unknown),
'latest': str(item.get('latest') or unknown),
})
clean_updates.sort(
key=lambda item: (item["vmid"], item["app_name"].casefold())
)
if not clean_updates:
return (
f"{hostname}: Application updates available",
"Application updates are available.",
runtime_message('appUpdates.emptyTitle', language, hostname=hostname),
runtime_message('appUpdates.emptyBody', language),
)
count = len(clean_updates)
container_count = len({item["vmid"] for item in clean_updates})
title = f"{hostname}: {count} application updates available"
lead = (
f"{count} applications in {container_count} LXC "
f"container{'s' if container_count != 1 else ''} have a newer version:"
title = runtime_message(
'appUpdates.batchTitle', language, hostname=hostname, count=count,
)
lead_key = (
'appUpdates.batchLeadOneContainer'
if container_count == 1 else 'appUpdates.batchLeadManyContainers'
)
lead = runtime_message(
lead_key, language, count=count, container_count=container_count,
)
sections = []
omitted = 0
@@ -645,7 +659,7 @@ def _format_app_update_available(data: Dict[str, Any]) -> Tuple[str, str]:
continue
sections.append("\n".join(section))
if omitted:
sections.append(f"{omitted} additional application(s)")
sections.append(runtime_message('appUpdates.additional', language, count=omitted))
return title, "\n\n".join([lead, *sections])
@@ -135,6 +135,31 @@ class AppUpdateNotificationBatchTests(unittest.TestCase):
self.assertIn("• Docmost: 0.2 → 0.9", rendered["body"])
self.assertIn("• Redis: 7.0 → 8.1", rendered["body"])
def test_batch_formatter_uses_slovak_runtime_messages(self):
data = {
"hostname": "HomeLAB_2",
"updates": [
{"vmid": 115, "app_name": "Redis", "installed": "7.0", "latest": "8.1"},
{"vmid": 100, "app_name": "AdGuard Home", "installed": "1.0", "latest": "1.1"},
{"vmid": 115, "app_name": "Docmost", "installed": "0.2", "latest": "0.9"},
],
}
rendered = notification_templates.render_template(
"app_update_available", data, language="sk",
)
self.assertEqual(
rendered["title"],
"HomeLAB_2: Dostupné aktualizácie aplikácií: 3",
)
self.assertIn(
"Aplikácie s dostupnou novšou verziou: 3 v 2 kontajneroch LXC:",
rendered["body"],
)
self.assertIn("• AdGuard Home: 1.0 → 1.1", rendered["body"])
self.assertNotIn("application updates available", rendered["title"])
if __name__ == "__main__":
unittest.main()
@@ -289,6 +289,29 @@ class RuntimeCatalogTests(unittest.TestCase):
self.assertIn("Vitajte", body)
self.assertIn("profilovú fotografiu", caption)
def test_batch_app_updates_render_from_every_runtime_catalog(self):
data = {
"hostname": "HOST-ŽILINA",
"updates": [
{"vmid": 100, "app_name": "AdGuard Home", "installed": "1.0", "latest": "1.1"},
{"vmid": 115, "app_name": "Redis", "installed": "7.0", "latest": "8.1"},
],
}
for language in self.RUNTIME_LANGUAGES:
rendered = notification_templates.render_template(
"app_update_available", data, language=language,
)
self.assertEqual(
rendered["title"],
notification_templates.runtime_message(
"appUpdates.batchTitle", language,
hostname="HOST-ŽILINA", count=2,
),
language,
)
self.assertIn("CT 100", rendered["body"], language)
self.assertIn("• Redis: 7.0 → 8.1", rendered["body"], language)
def test_ai_disabled_telegram_receives_deterministic_slovak(self):
class RecordingTelegram:
def __init__(self):