Преглед изворни кода

fix(i18n): wire health.rs hardcoded strings + proper plural selectors

Alexander Korolev пре 2 месеци
родитељ
комит
a9d4283879
8 измењених фајлова са 159 додато и 29 уклоњено
  1. 22 3
      locales/de/main.ftl
  2. 22 3
      locales/en/main.ftl
  3. 22 3
      locales/es/main.ftl
  4. 22 3
      locales/fr/main.ftl
  5. 22 3
      locales/it/main.ftl
  6. 26 3
      locales/ru/main.ftl
  7. 10 4
      scripts/verify-locales.sh
  8. 13 7
      src/docker/health.rs

+ 22 - 3
locales/de/main.ftl

@@ -27,11 +27,24 @@ stop-failed = Stop fehlgeschlagen auf { $name }: { $error }
 remove-failed = Remove fehlgeschlagen auf { $name }: { $error }
 failed-to = { $action } fehlgeschlagen auf { $name }: { $error }
 health-section = === Cluster: { $name } ===
+health-cluster-header = === { $name } === { $nodes } { $nodes ->
+        [one] Knoten
+       *[other] Knoten
+    }
+health-switch-off = 🚫 Switch aus
+health-interface-down = 🌐 Schnittstelle down
+health-all-online = ✅ alle online
+health-partial-online =  ({ $online } online, { $offline } offline)
+health-net-status =  [Netz: { $details }]
 health-no-containers = (keine Container)
+health-no-containers-inline = , keine Container
 health-total = Container gesamt: { $count }
 health-docker-unavailable = ✗ Docker nicht verfügbar
 docker-error-line = { $err }
-exec-header = ⚡ exec: { $cmd } ({ $nodes } Knoten)
+exec-header = ⚡ exec: { $cmd } ({ $nodes } { $nodes ->
+        [one] Knoten
+       *[other] Knoten
+    })
 exec-section = --- { $name } ---
 exec-failed = ✗ { $name } :: { $cmd } :: { $error }
 exec-completed-errors = exec mit Fehlern abgeschlossen (einige Knoten meldeten Fehler)
@@ -119,14 +132,20 @@ sync-synced = { $name } OK
 health-node-offline =   ✗ { $name } ({ $ip }) — nicht erreichbar
 health-node-idle =   ○ { $name } ({ $ip }){ $net }
 health-node-online =   ● { $name } ({ $ip }){ $net }
-health-container-count = , { $count } Container
+health-container-count = , { $count } { $count ->
+        [one] Container
+       *[other] Container
+    }
 power-off-head = 🛑 ausschalten: { $nodes } Knoten — sudo shutdown now
 power-switch-head = 🔸 umschalten: { $from } → { $to } ({ $nodes } Knoten + { $entities } Entities zu deaktivieren)
 power-switch-powering-on = 💡 umschalten: { $nodes } Knoten + { $entities } Entities einschalten nach { $to }
 health-task-join = Aufgaben-Join-Fehler: { $error }
 health-no-recipes = Keine sm121-Container laufen.
 health-running-recipes = Laufende Rezepte:
-health-recipe-line =   { $recipe } — { $nodes } Knoten: { $list }
+health-recipe-line =   { $recipe } — { $nodes } { $nodes ->
+        [one] Knoten
+       *[other] Knoten
+    }: { $list }
 tmux-ray-backend = 🐍 Ray-Backend erkannt — Head-Knoten wird zuerst gestartet...
 tmux-mp-backend = 🔗 MP-Backend erkannt — alle Knoten werden parallel gestartet...
 tmux-following-logs = 📜 Logs von '{ $sess }' auf { $name } werden verfolgt...

+ 22 - 3
locales/en/main.ftl

@@ -27,11 +27,24 @@ stop-failed = Stop failed on { $name }: { $error }
 remove-failed = Remove failed on { $name }: { $error }
 failed-to = Failed to { $action } on { $name }: { $error }
 health-section = === Cluster: { $name } ===
+health-cluster-header = === { $name } === { $nodes } { $nodes ->
+        [one] node
+       *[other] nodes
+    }
+health-switch-off = 🚫 switch off
+health-interface-down = 🌐 interface down
+health-all-online = ✅ all online
+health-partial-online =  ({ $online } online, { $offline } offline)
+health-net-status =  [net: { $details }]
 health-no-containers = (no containers)
+health-no-containers-inline = , no containers
 health-total = Total containers: { $count }
 health-docker-unavailable = ✗ Docker unavailable
 docker-error-line = { $err }
-exec-header = ⚡ exec: { $cmd } ({ $nodes } node(s))
+exec-header = ⚡ exec: { $cmd } ({ $nodes } { $nodes ->
+        [one] node
+       *[other] nodes
+    })
 exec-section = --- { $name } ---
 exec-failed = ✗ { $name } :: { $cmd } :: { $error }
 exec-completed-errors = exec completed with errors (some nodes reported failures)
@@ -119,14 +132,20 @@ sync-synced = { $name } OK
 health-node-offline =   ✗ { $name } ({ $ip }) — offline
 health-node-idle =   ○ { $name } ({ $ip }){ $net }
 health-node-online =   ● { $name } ({ $ip }){ $net }
-health-container-count = , { $count } container(s)
+health-container-count = , { $count } { $count ->
+        [one] container
+       *[other] containers
+    }
 power-off-head = 🛑 power off: { $nodes } node(s) — sudo shutdown now
 power-switch-head = 🔌 switch: { $from } → { $to } ({ $nodes } node(s) + { $entities } entity(ies) to disable)
 power-switch-powering-on = 💡 switch: powering on { $nodes } node(s) + { $entities } entity(ies) to { $to }
 health-task-join = task join: { $error }
 health-no-recipes = No sm121 containers running.
 health-running-recipes = Running recipes:
-health-recipe-line =   { $recipe } — { $nodes } node(s): { $list }
+health-recipe-line =   { $recipe } — { $nodes } { $nodes ->
+        [one] node
+       *[other] nodes
+    }: { $list }
 tmux-ray-backend = 🐍 Ray backend detected — starting head node first...
 tmux-mp-backend = 🔗 MP backend detected — starting all nodes in parallel...
 tmux-following-logs = 📜 Following logs from '{ $sess }' on { $name }...

+ 22 - 3
locales/es/main.ftl

@@ -27,11 +27,24 @@ stop-failed = Detención falló en { $name }: { $error }
 remove-failed = Eliminación falló en { $name }: { $error }
 failed-to = Falló { $action } en { $name }: { $error }
 health-section = === Cluster: { $name } ===
+health-cluster-header = === { $name } === { $nodes } { $nodes ->
+        [one] nodo
+       *[other] nodos
+    }
+health-switch-off = 🚫 switch apagado
+health-interface-down = 🌐 interfaz caída
+health-all-online = ✅ todos en línea
+health-partial-online =  ({ $online } en línea, { $offline } desconectados)
+health-net-status =  [red: { $details }]
 health-no-containers = (sin contenedores)
+health-no-containers-inline = , sin contenedores
 health-total = Contenedores totales: { $count }
 health-docker-unavailable = ✗ Docker no disponible
 docker-error-line = { $err }
-exec-header = ⚡ exec: { $cmd } ({ $nodes } nodo(s))
+exec-header = ⚡ exec: { $cmd } ({ $nodes } { $nodes ->
+        [one] nodo
+       *[other] nodos
+    })
 exec-section = --- { $name } ---
 exec-failed = ✗ { $name } :: { $cmd } :: { $error }
 exec-completed-errors = exec completó con errores (algunos nodos reportaron fallos)
@@ -119,14 +132,20 @@ sync-synced = { $name } OK
 health-node-offline =   ✗ { $name } ({ $ip }) — desconectado
 health-node-idle =   ○ { $name } ({ $ip }){ $net }
 health-node-online =   ● { $name } ({ $ip }){ $net }
-health-container-count = , { $count } contenedor(es)
+health-container-count = , { $count } { $count ->
+        [one] contenedor
+       *[other] contenedores
+    }
 power-off-head = 🛑 apagar: { $nodes } nodo(s) — sudo shutdown now
 power-switch-head = 🔌 conmutar: { $from } → { $to } ({ $nodes } nodo(s) + { $entities } entidade(s) a desactivar)
 power-switch-powering-on = 💡 conmutar: encendiendo { $nodes } nodo(s) + { $entities } entidade(s) a { $to }
 health-task-join = error de unión de tarea: { $error }
 health-no-recipes = No hay contenedores sm121 ejecutándose.
 health-running-recipes = Recetas en ejecución:
-health-recipe-line =   { $recipe } — { $nodes } nodo(s): { $list }
+health-recipe-line =   { $recipe } — { $nodes } { $nodes ->
+        [one] nodo
+       *[other] nodos
+    }: { $list }
 tmux-ray-backend = 🐍 Backend Ray detectado — iniciando nodo principal primero...
 tmux-mp-backend = 🔗 Backend MP detectado — iniciando todos los nodos en paralelo...
 tmux-following-logs = 📜 Siguiendo logs de '{ $sess }' en { $name }...

+ 22 - 3
locales/fr/main.ftl

@@ -27,11 +27,24 @@ stop-failed = Échec de l'arrêt sur { $name } : { $error }
 remove-failed = Échec de la suppression sur { $name } : { $error }
 failed-to = Échec de { $action } sur { $name } : { $error }
 health-section = === Cluster : { $name } ===
+health-cluster-header = === { $name } === { $nodes } { $nodes ->
+        [one] nœud
+       *[other] nœuds
+    }
+health-switch-off = 🚫 switch éteint
+health-interface-down = 🌐 interface indisponible
+health-all-online = ✅ tous en ligne
+health-partial-online =  ({ $online } en ligne, { $offline } hors ligne)
+health-net-status =  [réseau : { $details }]
 health-no-containers = (aucun conteneur)
+health-no-containers-inline = , aucun conteneur
 health-total = Conteneurs totaux : { $count }
 health-docker-unavailable = ✗ Docker indisponible
 docker-error-line = { $err }
-exec-header = ⚡ exec : { $cmd } ({ $nodes } nœud(s))
+exec-header = ⚡ exec : { $cmd } ({ $nodes } { $nodes ->
+        [one] nœud
+       *[other] nœuds
+    })
 exec-section = --- { $name } ---
 exec-failed = ✗ { $name } :: { $cmd } :: { $error }
 exec-completed-errors = exec terminé avec des erreurs (certains nœuds ont signalé des échecs)
@@ -119,14 +132,20 @@ sync-synced = { $name } OK
 health-node-offline =   ✗ { $name } ({ $ip }) — hors ligne
 health-node-idle =   ○ { $name } ({ $ip }){ $net }
 health-node-online =   ● { $name } ({ $ip }){ $net }
-health-container-count = , { $count } conteneur(s)
+health-container-count = , { $count } { $count ->
+        [one] conteneur
+       *[other] conteneurs
+    }
 power-off-head = 🛑 extinction : { $nodes } nœud(s) — sudo shutdown now
 power-switch-head = 🔌 commutation : { $from } → { $to } ({ $nodes } nœud(s) + { $entities } entité(s) à désactiver)
 power-switch-powering-on = 💡 commutation : allumage de { $nodes } nœud(s) + { $entities } entité(s) vers { $to }
 health-task-join = erreur de jointure de tâche : { $error }
 health-no-recipes = Aucun conteneur sm121 en cours d'exécution.
 health-running-recipes = Recettes en cours d'exécution :
-health-recipe-line =   { $recipe } — { $nodes } nœud(s) : { $list }
+health-recipe-line =   { $recipe } — { $nodes } { $nodes ->
+        [one] nœud
+       *[other] nœuds
+    } : { $list }
 tmux-ray-backend = 🐍 Backend Ray détecté — démarrage du nœud head en premier...
 tmux-mp-backend = 🔗 Backend MP détecté — démarrage de tous les nœuds en parallèle...
 tmux-following-logs = 📜 Suivi des logs de '{ $sess }' sur { $name }...

+ 22 - 3
locales/it/main.ftl

@@ -27,11 +27,24 @@ stop-failed = Arresto fallito su { $name }: { $error }
 remove-failed = Rimozione fallita su { $name }: { $error }
 failed-to = { $action } fallita su { $name }: { $error }
 health-section = === Cluster: { $name } ===
+health-cluster-header = === { $name } === { $nodes } { $nodes ->
+        [one] nodo
+       *[other] nodi
+    }
+health-switch-off = 🚫 switch spento
+health-interface-down = 🌐 interfaccia down
+health-all-online = ✅ tutti online
+health-partial-online =  ({ $online } online, { $offline } offline)
+health-net-status =  [rete: { $details }]
 health-no-containers = (nessun container)
+health-no-containers-inline = , nessun container
 health-total = Container totali: { $count }
 health-docker-unavailable = ✗ Docker non disponibile
 docker-error-line = { $err }
-exec-header = ⚡ exec: { $cmd } ({ $nodes } nodo/i)
+exec-header = ⚡ exec: { $cmd } ({ $nodes } { $nodes ->
+        [one] nodo
+       *[other] nodi
+    })
 exec-section = --- { $name } ---
 exec-failed = ✗ { $name } :: { $cmd } :: { $error }
 exec-completed-errors = exec completato con errori (alcuni nodi hanno riportato fallimenti)
@@ -119,14 +132,20 @@ sync-synced = { $name } OK
 health-node-offline =   ✗ { $name } ({ $ip }) — offline
 health-node-idle =   ○ { $name } ({ $ip }){ $net }
 health-node-online =   ● { $name } ({ $ip }){ $net }
-health-container-count = , { $count } container
+health-container-count = , { $count } { $count ->
+        [one] container
+       *[other] container
+    }
 power-off-head = 🛑 spegnimento: { $nodes } nodo/i — sudo shutdown now
 power-switch-head = 🔌 commuta: { $from } → { $to } ({ $nodes } nodo/i + { $entities } entità da disattivare)
 power-switch-powering-on = 💡 commuta: accensione { $nodes } nodo/i + { $entities } entità verso { $to }
 health-task-join = errore di join dell'attività: { $error }
 health-no-recipes = Nessun container sm121 in esecuzione.
 health-running-recipes = Ricette in esecuzione:
-health-recipe-line =   { $recipe } — { $nodes } nodo/i: { $list }
+health-recipe-line =   { $recipe } — { $nodes } { $nodes ->
+        [one] nodo
+       *[other] nodi
+    }: { $list }
 tmux-ray-backend = 🐍 Backend Ray rilevato — avvio del nodo head per primo...
 tmux-mp-backend = 🔗 Backend MP rilevato — avvio di tutti i nodi in parallelo...
 tmux-following-logs = 📜 Seguendo i log da '{ $sess }' su { $name }...

+ 26 - 3
locales/ru/main.ftl

@@ -28,11 +28,26 @@ stop-failed = Не удалось остановить { $name }: { $error }
 remove-failed = Не удалось удалить { $name }: { $error }
 failed-to = Не удалось { $action } на { $name }: { $error }
 health-section = === Кластер: { $name } ===
+health-cluster-header = === { $name } === { $nodes } { $nodes ->
+        [one] узел
+        [few] узла
+       *[many] узлов
+    }
+health-switch-off = 🚫 переключатель выключен
+health-interface-down = 🌐 интерфейс недоступен
+health-all-online = ✅ все онлайн
+health-partial-online =  ({ $online } онлайн, { $offline } офлайн)
+health-net-status =  [сеть: { $details }]
 health-no-containers = (нет контейнеров)
+health-no-containers-inline = , нет контейнеров
 health-total = Всего контейнеров: { $count }
 health-docker-unavailable = ✗ Docker недоступен
 docker-error-line = { $err }
-exec-header = ⚡ exec: { $cmd } ({ $nodes } узлов)
+exec-header = ⚡ exec: { $cmd } ({ $nodes } { $nodes ->
+        [one] узел
+        [few] узла
+       *[many] узлов
+    })
 exec-section = --- { $name } ---
 exec-failed = ✗ { $name } :: { $cmd } :: { $error }
 exec-completed-errors = exec завершен с ошибками (некоторые узлы не ответили)
@@ -120,14 +135,22 @@ sync-synced = { $name } OK
 health-node-offline =   ✗ { $name } ({ $ip }) — офлайн
 health-node-idle =   ○ { $name } ({ $ip }){ $net }
 health-node-online =   ● { $name } ({ $ip }){ $net }
-health-container-count = , { $count } контейнер(ов)
+health-container-count = , { $count } { $count ->
+        [one] контейнер
+        [few] контейнера
+       *[many] контейнеров
+    }
 power-off-head = 🛑 выключение: { $nodes } узлов — sudo shutdown now
 power-switch-head = 🔌 переключение: { $from } → { $to } ({ $nodes } узлов + { $entities } сущностей для отключения)
 power-switch-powering-on = 💡 переключение: включение { $nodes } узлов + { $entities } сущностей в { $to }
 health-task-join = ошибка присоединения задачи: { $error }
 health-no-recipes = Нет запущенных контейнеров sm121.
 health-running-recipes = Запущенные рецепты:
-health-recipe-line =   { $recipe } — { $nodes } узлов: { $list }
+health-recipe-line =   { $recipe } — { $nodes } { $nodes ->
+        [one] узел
+        [few] узла
+       *[many] узлов
+    }: { $list }
 tmux-ray-backend = 🐍 Обнаружен Ray backend — запуск главного узла первым...
 tmux-mp-backend = 🔗 Обнаружен MP backend — запуск всех узлов параллельно...
 tmux-following-logs = 📜 Наблюдаю за логами '{ $sess }' на { $name }...

+ 10 - 4
scripts/verify-locales.sh

@@ -27,12 +27,18 @@ is_loanword() { echo "$LOANWORDS" | grep -qwi "$1"; }
 # Extract top-level key names (lines starting with `identifier =`).
 keys_of() { grep -oE '^[a-z0-9-]+ = ' "$1" | sed 's/ = $//'; }
 
-# Extract the value portion of a given key (first match, trailing whitespace
-# trimmed). Returns empty if the key is absent.
+# Extract the value portion of a given key (full multi-line value,
+# trailing whitespace trimmed). Captures selector blocks ({ $count -> ... }).
+# Returns empty if the key is absent.
 value_of() {
   local file="$1" key="$2"
-  awk -v k="^$key = " '$0 ~ k { sub(/^[^=]+= /, ""); print; exit }' "$file" \
-    | sed 's/[[:space:]]*$//'
+  awk -v k="^$key = " '
+    $0 ~ k { in_val=1; sub(/^[^=]+= /, ""); print; next }
+    in_val && /^[a-z0-9-]+ = / { exit }
+    in_val && /^#/ { exit }
+    in_val && /^$/ { exit }
+    in_val { print }
+  ' "$file" | sed 's/[[:space:]]*$//' | sed '/^$/d'
 }
 
 en_keys=$(keys_of "$EN" | sort -u)

+ 13 - 7
src/docker/health.rs

@@ -155,15 +155,21 @@ pub async fn health_check(config: &Config, cluster: &Cluster, dry_run: bool) ->
     let container_count: usize = node_health.iter().map(|n| n.containers.len()).sum();
     let net_ok = node_health.iter().all(|n| !n.online || n.net_up);
 
-    print!("=== {} === {} nodes", cluster_label, total);
+    print!(
+        "{}",
+        fluent_i18n::t!("health-cluster-header", { "name" => &cluster_label, "nodes" => total })
+    );
     if !ha_ok && !cluster.extra_entities.is_empty() {
-        print!(" 🚫 switch off");
+        print!(" {}", fluent_i18n::t!("health-switch-off"));
     } else if !net_ok {
-        print!(" 🌐 interface down");
+        print!(" {}", fluent_i18n::t!("health-interface-down"));
     } else if online == total {
-        print!(" ✅ all online");
+        print!(" {}", fluent_i18n::t!("health-all-online"));
     } else {
-        print!(" ({} online, {} offline)", online, offline);
+        print!(
+            "{}",
+            fluent_i18n::t!("health-partial-online", { "online" => online, "offline" => offline })
+        );
     }
     if container_count > 0 {
         println!(
@@ -171,7 +177,7 @@ pub async fn health_check(config: &Config, cluster: &Cluster, dry_run: bool) ->
             fluent_i18n::t!("health-container-count", { "count" => container_count })
         );
     } else {
-        println!(", no containers");
+        print!("{}", fluent_i18n::t!("health-no-containers-inline"));
     }
 
     for nh in &node_health {
@@ -183,7 +189,7 @@ pub async fn health_check(config: &Config, cluster: &Cluster, dry_run: bool) ->
             continue;
         }
         let net_status = if !nh.net_up {
-            format!(" [net: {}]", nh.net_details.join(", "))
+            fluent_i18n::t!("health-net-status", { "details" => nh.net_details.join(", ") })
         } else {
             String::new()
         };