Repository: fujiapple852/trippy (language: rust)

Issue:
Get rid of (serde_)y(a)ml
serde_yaml is unmaintained, so trippy switched to the serde_yml fork, but it has a worrying code quality ([hardcoding `c_char` as `i8`](https://github.com/sebastienrousseau/libyml/pull/6)). YAML is a confusing format to begin with. So, it'd be nice if we could switch to TOML, which is already a dependency. Currently (almost) all usage of YAML is in test data. For example, 

https://github.com/fujiapple852/trippy/blob/e2c7726dc924d49c7a98461365f985e88076f394/crates/trippy-core/tests/resources/state/nat.yaml#L1-L22

This could be translated to:

```toml
largest_ttl = 3

[[rounds]]
probes = [
  "1 C 333 10.1.0.1 0 12340 80 43012 43012",
  "2 C 777 10.1.0.2 1 12340 80 20544 20544",
  "3 C 778 10.1.0.3 2 12340 80 20544 20544"
]

[[rounds]]
probes = [
  "1 C 123 10.1.0.1 3 12340 80 43012 43012",
  "2 C 788 10.1.0.2 4 12340 80 20544 20544",
  "3 C 789 10.1.0.3 5 12340 80 20544 20544"
]

[[rounds]]
probes = [
  "1 C 123 10.1.0.1 6 12340 80 43012 43012",
  "2 C 780 10.1.0.2 7 12340 80 20544 20544",
  "3 C 781 10.1.0.3 8 12340 80 20544 20544"
]

[[expected.hops]]
ttl = 1
last_nat_status = "no_nat"

[[expected.hops]]
ttl = 2
last_nat_status = "nat"

[[expected.hops]]
ttl = 3
last_nat_status = "no_nat"
```

Some files use the tag feature of YAML e.g. `!SingleHost`, which presumably could be replaced with an optional key in TOML and some processing in the code.

The usage other than "almost all" is in i18n strings, introduced by rust-i18n, which is not packaged in Debian and "polyfilled" with an [ad-hoc patch](https://salsa.debian.org/debian/trippy/-/blob/debian/sid/debian/patches/ad-hoc-i18n.patch) to deliver the new functionality ASAP without seeing rust-i18n packages through NEW queue. Arguably, it could be replaced with [i18n-embed](https://lib.rs/crates/i18n-embed), which supports the Fluent translation system, as well as the old gettext system, both very popular and widely supported. It has built-in locale resolution through the [locale_config](https://lib.rs/crates/locale_config) crate. But this is probably too big a change, and a too abrupt one shortly after i18n is released.

Note this is strongly influenced by my PoV as a downstream package maintainer, focusing on maintainability (serde_yml) and avoiding unnecessary dependencies (serde_yml, rust-i18n), which are not always the biggest concerns for upstream developers.

I'm willing to implement the change if either is considered acceptable.


Discussion / hints:
Hi again @nc7s,
 
> trippy switched to the serde_yml fork, but it has a worrying code quality. YAML is a confusing format to begin with. So, it'd be nice if we could switch to TOML

I [agree](https://trippy.zulipchat.com/#narrow/channel/436136-general/topic/serde_yaml.20alternative/near/479650688) with your concern about `serde_yml` and also the suggestion to replace `yaml` with `toml` throughout.

> Some files use the tag feature of YAML e.g. !SingleHost, which presumably could be replaced with an optional key in TOML and some processing in the code.

Yes, I don't see that as being a major issue moving to `toml` as I have full control over both the file format and code and there are no backward compatibility concerns as these are only used for internal CI testing.

> The usage other than "almost all" is in i18n strings, introduced by rust-i18n, which is not packaged in Debian and "polyfilled" with an ad-hoc patch to deliver the new functionality ASAP without seeing rust-i18n packages through NEW queue.

I'm not overly fond of the current `rust-i18n` crate, it was the "least worst" option I found when researching at the time. I would quite like to move to something better, provided it is cross platform and works standalone (i.e. does not make any assumption about other packages installed on the system).  Fluent sounds like a good format (I especially like the 3rd party collaborative editing tools) and `i18n-embed` seems solid, i'd be fine with trying that.

I'm also tempted to just do something akin to your patch, as doing this translation is simple enough that pulling in dependencies may be overkill.

> But this is probably too big a change, and a too abrupt one shortly after i18n is released.

The changes would all be internal implementation details so i'm fine with it.  Having said that, the current crate _does_ seem to support `toml` as well, so perhaps that is the easiest option for now?

> Note this is strongly influenced by my PoV as a downstream package maintainer, focusing on maintainability (serde_yml) and avoiding unnecessary dependencies (serde_yml, rust-i18n), which are not always the biggest concerns for upstream developers.

I'm keen to do whatever I can to make it easier for downstream package maintainers, it is very much in my interest as well. I'm super impressed with your extensive efforts to patch it for Debian, kudos.

> I'm willing to implement the change if either is considered acceptable.

Thank you.  To be clear, i'm also fine to do this work as it is something I wanted to do anyway, however if you _want_ to do it then i'd gladly accept a PR.

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index c54e49275..f5243dd95 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1322,16 +1322,6 @@ version = "0.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "64804cc6a5042d4f05379909ba25b503ec04e2c082151d62122d5dcaa274b961"
 
-[[package]]
-name = "libyml"
-version = "0.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3302702afa434ffa30847a83305f0a69d6abd74293b6554c18ec85c7ef30c980"
-dependencies = [
- "anyhow",
- "version_check",
-]
-
 [[package]]
 name = "linked-hash-map"
 version = "0.5.6"
@@ -1825,7 +1815,7 @@ dependencies = [
  "rust-i18n-support",
  "serde",
  "serde_json",
- "serde_yml 0.0.11",
+ "serde_yml",
  "syn 2.0.90",
 ]
 
@@ -1846,7 +1836,7 @@ dependencies = [
  "regex",
  "serde",
  "serde_json",
- "serde_yml 0.0.11",
+ "serde_yml",
  "siphasher",
  "toml 0.7.8",
  "triomphe",
@@ -1900,18 +1890,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "serde"
-version = "1.0.215"
+version = "1.0.216"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
+checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.215"
+version = "1.0.216"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
+checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1970,7 +1960,7 @@ checksum = "48e76bab63c3fd98d27c17f9cbce177f64a91f5e69ac04cafe04e1bb25d1dc3c"
 dependencies = [
  "indexmap",
  "itoa",
- "libyml 0.0.4",
+ "libyml",
  "log",
  "memchr",
  "ryu",
@@ -1979,21 +1969,6 @@ dependencies = [
  "tempfile",
 ]
 
-[[package]]
-name = "serde_yml"
-version = "0.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59e2dd588bf1597a252c3b920e0143eb99b0f76e4e082f4c92ce34fbc9e71ddd"
-dependencies = [
- "indexmap",
- "itoa",
- "libyml 0.0.5",
- "memchr",
- "ryu",
- "serde",
- "version_check",
-]
-
 [[package]]
 name = "sharded-slab"
 version = "0.1.7"
@@ -2532,12 +2507,12 @@ dependencies = [
  "paste",
  "rand",
  "serde",
- "serde_yml 0.0.12",
  "socket2",
  "test-case",
  "thiserror 2.0.6",
  "tokio",
  "tokio-util",
+ "toml 0.8.19",
  "tracing",
  "tracing-subscriber",
  "trippy-packet",
@@ -2711,12 +2686,6 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
 
-[[package]]
-name = "version_check"
-version = "0.9.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
-
 [[package]]
 name = "walkdir"
 version = "2.5.0"
diff --git a/Cargo.toml b/Cargo.toml
index 32b7ab3f0..220350b67 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -65,7 +65,6 @@ rust-i18n = "3.1.2"
 serde = { version = "1.0.201", default-features = false }
 serde_json = { version = "1.0.117", default-features = false }
 serde_with = { version = "3.11.0", default-features = false, features = ["macros"] }
-serde_yml = "0.0.12"
 socket2 = "0.5.8"
 strum = { version = "0.26.3", default-features = false }
 sys-locale = "0.3.2"
diff --git a/crates/trippy-core/Cargo.toml b/crates/trippy-core/Cargo.toml
index 358999179..8c2ab73d5 100644
--- a/crates/trippy-core/Cargo.toml
+++ b/crates/trippy-core/Cargo.toml
@@ -49,10 +49,10 @@ ipnetwork.workspace = true
 mockall.workspace = true
 rand.workspace = true
 serde = { workspace = true, default-features = false, features = [ "derive" ] }
-serde_yml.workspace = true
 test-case.workspace = true
 tokio-util.workspace = true
 tokio = { workspace = true, features = [ "full" ] }
+toml.workspace = true
 tracing-subscriber = { workspace = true, default-features = false, features = [ "env-filter", "fmt" ] }
 
 # see https://github.com/meh/rust-tun/pull/74
@@ -64,4 +64,4 @@ tun2 = { workspace = true, features = [ "async" ] }
 sim-tests = []
 
 [lints]
-workspace = true
\ No newline at end of file
+workspace = true
diff --git a/crates/trippy-core/src/state.rs b/crates/trippy-core/src/state.rs
index 619303a99..cbab1a9da 100644
--- a/crates/trippy-core/src/state.rs
+++ b/crates/trippy-core/src/state.rs
@@ -891,18 +891,18 @@ mod tests {
 
     macro_rules! file {
         ($path:expr) => {{
-            let yaml = include_str!(concat!("../tests/resources/state/", $path));
-            serde_yml::from_str(yaml).unwrap()
+            let data = include_str!(concat!("../tests/resources/state/", $path));
+            toml::from_str(data).unwrap()
         }};
     }
 
-    #[test_case(file!("full_mixed.yaml"))]
-    #[test_case(file!("full_completed.yaml"))]
-    #[test_case(file!("all_status.yaml"))]
-    #[test_case(file!("no_latency.yaml"))]
-    #[test_case(file!("nat.yaml"))]
-    #[test_case(file!("minimal.yaml"))]
-    #[test_case(file!("floss_bloss.yaml"))]
+    #[test_case(file!("full_mixed.toml"))]
+    #[test_case(file!("full_completed.toml"))]
+    #[test_case(file!("all_status.toml"))]
+    #[test_case(file!("no_latency.toml"))]
+    #[test_case(file!("nat.toml"))]
+    #[test_case(file!("minimal.toml"))]
+    #[test_case(file!("floss_bloss.toml"))]
     fn test_scenario(scenario: Scenario) {
         let mut trace = State::new(StateConfig {
             max_flows: 1,
diff --git a/crates/trippy-tui/locales/app.toml b/crates/trippy-tui/locales/app.toml
new file mode 100644
index 000000000..c68b0c453
--- /dev/null
+++ b/crates/trippy-tui/locales/app.toml
@@ -0,0 +1,1308 @@
+_version = 2
+
+[trippy]
+en = "trippy"
+fr = "trippy"
+tr = "trippy"
+it = "trippy"
+pt = "trippy"
+zh = "trippy"
+sv = "trippy"
+ru = "trippy"
+es = "trippy"
+de = "trippy"
+
+[auto]
+en = "auto"
+fr = "automatique"
+tr = "otomatik"
+it = "auto"
+pt = "automático"
+zh = "自动"
+sv = "automatisk"
+ru = "авто"
+es = "automático"
+de = "auto"
+
+[on]
+en = "on"
+fr = "activé"
+tr = "açık"
+it = "on"
+pt = "ligado"
+zh = "开"
+sv = "på"
+ru = "вкл"
+es = "activo"
+de = "an"
+
+[off]
+en = "off"
+fr = "désactivé"
+tr = "kapalı"
+it = "off"
+pt = "desligado"
+zh = "关"
+sv = "av"
+ru = "выкл"
+es = "inactivo"
+de = "aus"
+
+[yes]
+en = "Yes"
+fr = "Oui"
+tr = "Evet"
+it = "Sì"
+pt = "Sim"
+zh = "是"
+sv = "Ja"
+ru = "Да"
+es = "Sí"
+de = "Ja"
+
+[no]
+en = "No"
+fr = "Non"
+tr = "Hayır"
+it = "No"
+pt = "Não"
+zh = "否"
+sv = "Nej"
+ru = "Нет"
+es = "No"
+de = "Nein"
+
+[none]
+en = "none"
+fr = "aucun"
+tr = "hiçbiri"
+it = "nessuno"
+pt = "nenhum"
+zh = "无"
+sv = "ingen"
+ru = "нет"
+es = "ninguno"
+de = "keiner"
+
+[hidden]
+en = "Hidden"
+fr = "Caché"
+tr = "Gizli"
+it = "Nascosto"
+pt = "Oculto"
+zh = "隐藏"
+sv = "Dold"
+ru = "Скрыто"
+es = "Oculto"
+de = "Versteckt"
+
+[flow]
+en = "flow"
+fr = "flux"
+tr = "akış"
+it = "flusso"
+pt = "fluxo"
+zh = "流量"
+sv = "flöde"
+ru = "поток"
+es = "flujo"
+de = "fluss"
+
+[flows]
+en = "flows"
+fr = "flux"
+tr = "akışlar"
+it = "flussi"
+pt = "fluxos"
+zh = "流量"
+sv = "flöden"
+ru = "потоки"
+es = "flujos"
+de = "flüsse"
+
+[target]
+en = "Target"
+fr = "Cible"
+tr = "Hedef"
+it = "Target"
+pt = "Alvo"
+zh = "目标"
+sv = "Mål"
+ru = "Цель"
+es = "Objetivo"
+de = "Ziel"
+
+[status]
+en = "Status"
+fr = "Statut"
+tr = "Durum"
+it = "Stato"
+pt = "Estado"
+zh = "状态"
+sv = "Status"
+ru = "Статус"
+es = "Estado"
+de = "Status"
+
+[details]
+en = "detail"
+fr = "détail"
+tr = "ayrıntılar"
+it = "dettagli"
+pt = "detalhe"
+zh = "详情"
+sv = "detaljer"
+ru = "детали"
+es = "detalles"
+de = "detail"
+
+[privileged]
+en = "privileged"
+fr = "privilégié"
+tr = "ayrıcalıklı"
+it = "privilegiato"
+pt = "privilegiado"
+zh = "特权"
+sv = "privilegierad"
+ru = "привилегированный"
+es = "privilegiado"
+de = "privilegiert"
+
+[unprivileged]
+en = "unprivileged"
+fr = "non privilégié"
+tr = "ayrıcalıksız"
+it = "non privilegiato"
+pt = "não privilegiado"
+zh = "非特权"
+sv = "oprivilegierad"
+ru = "непривилегированный"
+es = "no privilegiado"
+de = "unprivilegiert"
+
+[privacy]
+en = "privacy"
+fr = "confidentialité"
+tr = "gizlilik"
+it = "privacy"
+pt = "privacidade"
+zh = "隐私"
+sv = "integritet"
+ru = "конфиденциальность"
+es = "privacidad"
+de = "datenschutz"
+
+[na]
+en = "n/a"
+fr = "non disponible"
+tr = "yok"
+it = "n/d"
+pt = "n/d"
+zh = "无"
+sv = "ej tillgänglig"
+ru = "н/д"
+es = "n/d"
+de = "n/a"
+
+[discovered]
+en = "discovered %{hop_count} hops"
+fr = "%{hop_count} sauts découverts"
+tr = "%{hop_count} atlanan keşfedildi"
+it = "%{hop_count} salti trovati"
+pt = "descobriu %{hop_count} saltos"
+zh = "发现 %{hop_count} 跳"
+sv = "upptäckte %{hop_count} hopp"
+ru = "обнаружено %{hop_count} прыжков"
+es = "se descubrieron %{hop_count} saltos"
+de = "%{hop_count} gefundene hops"
+
+[discovered_flows]
+en = "discovered %{hop_count} hops and %{flow_count} unique %{plural_flows}"
+fr = "%{hop_count} sauts et %{flow_count} %{plural_flows} uniques découverts"
+tr = "%{hop_count} atlanan ve %{flow_count} benzersiz %{plural_flows} keşfedildi"
+it = "scoperti %{hop_count} salti e %{flow_count} %{plural_flows} unici"
+pt = "descobriu %{hop_count} saltos e %{flow_count} %{plural_flows} únicos"
+zh = "发现 %{hop_count} 跳，%{flow_count} 个唯一%{plural_flow}"
+sv = "%{hop_count} hopp och unika %{flow_count} %{plural_flows} upptäckta"
+ru = "обнаружено %{hop_count} прыжков и %{flow_count} уникальных %{plural_flows}"
+es = "se descubrieron %{hop_count} saltos y %{flow_count} únicos %{plural_flows}"
+de = "%{hop_count} gefundene hops und %{flow_count} eindeutige %{plural_flows}"
+
+[unknown]
+en = "unknown"
+fr = "inconnu"
+tr = "bilinmeyen"
+it = "sconosciuto"
+pt = "desconhecido"
+zh = "未知"
+sv = "okänd"
+ru = "неизвестно"
+es = "desconocido"
+de = "unbekannt"
+
+[icmp]
+en = "icmp"
+fr = "icmp"
+tr = "icmp"
+it = "icmp"
+pt = "icmp"
+zh = "icmp"
+sv = "icmp"
+ru = "icmp"
+es = "icmp"
+de = "icmp"
+
+[udp]
+en = "udp"
+fr = "udp"
+tr = "udp"
+it = "udp"
+pt = "udp"
+zh = "udp"
+sv = "udp"
+ru = "udp"
+es = "udp"
+de = "udp"
+
+[tcp]
+en = "tcp"
+fr = "tcp"
+tr = "tcp"
+it = "tcp"
+pt = "tcp"
+zh = "tcp"
+sv = "tcp"
+ru = "tcp"
+es = "tcp"
+de = "tcp"
+
+[status_failures]
+en = "%{failure_count} of %{total_probes} (%{failure_rate}%) probes failed"
+fr = "%{failure_count} sur %{total_probes} (%{failure_rate}%) sondes ont échoué"
+tr = "%{failure_count} / %{total_probes} (%{failure_rate}%) sondajın başarısız olması"
+it = "%{failure_count} di %{total_probes} (%{failure_rate}%) prove fallite"
+pt = "%{failure_count} de %{total_probes} (%{failure_rate}%) sondas falharam"
+zh = "%{failure_count} 个失败，共探测到 %{total_probes} 个（%{failure_rate}%）"
+sv = "%{failure_count} av %{total_probes} (%{failure_rate}%) misslyckade prober"
+ru = "%{failure_count} из %{total_probes} (%{failure_rate}%) зондов не удалось"
+es = "%{failure_count} de %{total_probes} (%{failure_rate}%) sondas fallaron"
+de = "%{failure_count} von %{total_probes} (%{failure_rate}%) sonden sind fehlgeschlagen"
+
+[status_failed]
+en = "Failed"
+fr = "Échec"
+tr = "Başarısız"
+it = "Fallito"
+pt = "Falhou"
+zh = "失败"
+sv = "Misslyckades"
+ru = "Не удалось"
+es = "Fallido"
+de = "Fehlgeschlagen"
+
+[status_running]
+en = "Running"
+fr = "En cours"
+tr = "Çalışıyor"
+it = "In esecuzione"
+pt = "Executando"
+zh = "运行中"
+sv = "Kör"
+ru = "Запущен"
+es = "En ejecución"
+de = "Läuft"
+
+[status_frozen]
+en = "Frozen"
+fr = "Gelé"
+tr = "Dondurulmuş"
+it = "Congelato"
+pt = "Congelado"
+zh = "冻结"
+sv = "Frusen"
+ru = "Заморожен"
+es = "Congelado"
+de = "Eingefroren"
+
+[awaiting_data]
+en = "Awaiting data..."
+fr = "En attente de données..."
+tr = "Veri bekleniyor..."
+it = "In attesa di dati..."
+pt = "Aguardando dados..."
+zh = "等待数据……"
+sv = "Väntar på data..."
+ru = "Ожидание данных..."
+es = "Esperando datos..."
+de = "Warten auf Daten..."
+
+[header_help]
+en = "help"
+fr = "aide"
+tr = "yardım"
+it = "aiuto"
+pt = "ajuda"
+zh = "帮助"
+sv = "hjälp"
+ru = "помощь"
+es = "ayuda"
+de = "hilfe"
+
+[header_settings]
+en = "settings"
+fr = "paramètres"
+tr = "ayarlar"
+it = "impostazioni"
+pt = "configurações"
+zh = "设置"
+sv = "inställningar"
+ru = "настройки"
+es = "configuraciones"
+de = "einstellungen"
+
+[header_quit]
+en = "quit"
+fr = "quitter"
+tr = "cıkış"
+it = "uscita"
+pt = "sair"
+zh = "退出"
+sv = "avsluta"
+ru = "Выход"
+es = "salir"
+de = "beenden"
+
+[title_hops]
+en = "Hops"
+fr = "Sauts"
+tr = "Atlananlar"
+it = "Salti"
+pt = "Saltos"
+zh = "跳"
+sv = "Hopp"
+ru = "Прыжки"
+es = "Saltos"
+de = "Hops"
+
+[title_frequency]
+en = "Frequency"
+fr = "Fréquence"
+tr = "Sıklık"
+it = "Frequenza"
+pt = "Frequência"
+zh = "频率"
+sv = "Frekvens"
+ru = "Частота"
+es = "Frecuencia"
+de = "Frequenz"
+
+[title_samples]
+en = "Samples"
+fr = "Échantillons"
+tr = "Örnekler"
+it = "Campioni"
+pt = "Amostras"
+zh = "样本"
+sv = "Prover"
+ru = "Образцы"
+es = "Muestras"
+de = "Proben"
+
+[title_traces]
+en = "Traces"
+fr = "Traces"
+tr = "İzler"
+it = "Tracce"
+pt = "Rastreios"
+zh = "跟踪"
+sv = "Spår"
+ru = "Следы"
+es = "Trazas"
+de = "Spuren"
+
+[title_flows]
+en = "Flows"
+fr = "Flux"
+tr = "Akışlar"
+it = "Flussi"
+pt = "Fluxos"
+zh = "流量"
+sv = "Flöden"
+ru = "Потоки"
+es = "Flujos"
+de = "Flüsse"
+
+[title_map]
+en = "Map"
+fr = "Carte"
+tr = "Harita"
+it = "Mappa"
+pt = "Mapa"
+zh = "地图"
+sv = "Karta"
+ru = "Карта"
+es = "Mapa"
+de = "Karte"
+
+[title_help]
+en = "Help"
+fr = "Aide"
+tr = "Yardım"
+it = "Aiuto"
+pt = "Ajuda"
+zh = "帮助"
+sv = "Hjälp"
+ru = "Помощь"
+es = "Ayuda"
+de = "Hilfe"
+
+[title_settings]
+en = "Settings"
+fr = "Paramètres"
+tr = "Ayarlar"
+it = "Impostazioni"
+pt = "Configurações"
+zh = "设置"
+sv = "Inställningar"
+ru = "Настройки"
+es = "Configuraciones"
+de = "Einstellungen"
+
+[bsod_failed]
+en = "Trippy Failed :("
+fr = "Trippy a échoué :("
+tr = "Trippy Başarısız :("
+it = "Trippy ha avuto un problema :("
+pt = "Trippy falhou :("
+zh = "Trippy 失败 :("
+sv = "Trippy misslyckades :("
+ru = "Trippy не удалось :("
+es = "Trippy tuvo un problema :("
+de = "Trippy ist fehlgeschlagen :("
+
+[bsod_quit]
+en = "Press q to quit"
+fr = "Appuyez sur q pour quitter"
+tr = "Çıkmak için q tuşuna basın"
+it = "Premi q per uscire"
+pt = "Pressione q para sair"
+zh = "按 q 退出"
+sv = "Tryck på q för att avsluta"
+ru = "Нажмите q для выхода"
+es = "Presiona q para salir"
+de = "Drücken Sie q, um zu beenden"
+
+[hop]
+en = "Hop"
+fr = "Saut"
+tr = "Atla"
+it = "Salto"
+pt = "Salto"
+zh = "跳"
+sv = "Hopp"
+ru = "Прыжок"
+es = "Salto"
+de = "Hop"
+
+[rtt]
+en = "RTT"
+fr = "RTT"
+tr = "RTT"
+it = "RTT"
+pt = "RTT"
+zh = "往返时间"
+sv = "RTT"
+ru = "RTT"
+es = "RTT"
+de = "RTT"
+
+[title_chart]
+en = "Chart"
+fr = "Graphique"
+tr = "Grafik"
+it = "Grafico"
+pt = "Gráfico"
+zh = "图表"
+sv = "Diagram"
+ru = "Диаграмма"
+es = "Gráfico"
+de = "Diagramm"
+
+[samples]
+en = "Samples"
+fr = "Échantillons"
+tr = "Örnekler"
+it = "Campioni"
+pt = "Amostras"
+zh = "样本"
+sv = "Prover"
+ru = "Образцы"
+es = "Muestras"
+de = "Proben"
+
+[host]
+en = "Host"
+fr = "Hôte"
+tr = "Ana bilgisayar"
+it = "Host"
+pt = "Host"
+zh = "主机"
+sv = "Värd"
+ru = "Хост"
+es = "Host"
+de = "Host"
+
+[no_response]
+en = "No response"
+fr = "Pas de réponse"
+tr = "Yanıt yok"
+it = "Nessuna risposta"
+pt = "Sem resposta"
+zh = "无响应"
+sv = "Inget svar"
+ru = "Нет ответа"
+es = "Sin respuesta"
+de = "Keine Antwort"
+
+[dns_failed]
+en = "Failed"
+fr = "Échec"
+tr = "Başarısız"
+it = "Fallito"
+pt = "Falhou"
+zh = "失败"
+sv = "Misslyckades"
+ru = "Не удалось"
+es = "Fallido"
+de = "Fehlgeschlagen"
+
+[dns_timeout]
+en = "Timeout"
+fr = "Délai dépassé"
+tr = "Zaman aşımı"
+it = "Tempo scaduto"
+pt = "Tempo esgotado"
+zh = "超时"
+sv = "Tidsgräns nådd"
+ru = "Тайм-аут"
+es = "Tiempo de espera"
+de = "Zeitüberschreitung"
+
+[labels]
+en = "labels"
+fr = "étiquettes"
+tr = "etiketler"
+it = "etichette"
+pt = "etiquetas"
+zh = "标签"
+sv = "etiketter"
+ru = "метки"
+es = "etiquetas"
+de = "etiketten"
+
+[not_enabled]
+en = "not enabled"
+fr = "non activé"
+tr = "etkin değil"
+it = "non abilitato"
+pt = "não ativado"
+zh = "未启用"
+sv = "ej aktiverad"
+ru = "не активирован"
+es = "no habilitado"
+de = "nicht aktiviert"
+
+[not_found]
+en = "not found"
+fr = "non trouvé"
+tr = "bulunamadı"
+it = "non trovato"
+pt = "não encontrado"
+zh = "未找到"
+sv = "hittades inte"
+ru = "не найдено"
+es = "no encontrado"
+de = "nicht gefunden"
+
+[awaited]
+en = "awaited"
+fr = "attendu"
+tr = "beklenen"
+it = "atteso"
+pt = "aguardado"
+zh = "等待"
+sv = "väntade"
+ru = "ожидаемый"
+es = "esperado"
+de = "erwartet"
+
+[name]
+en = "Name"
+fr = "Nom"
+tr = "Ad"
+it = "Nome"
+pt = "Nome"
+zh = "名称"
+sv = "Namn"
+ru = "Имя"
+es = "Nombre"
+de = "Name"
+
+[info]
+en = "Info"
+fr = "Information"
+tr = "Bilgi"
+it = "Info"
+pt = "Informação"
+zh = "信息"
+sv = "Information"
+ru = "Информация"
+es = "Información"
+de = "Info"
+
+[geo]
+en = "Geo"
+fr = "Géo"
+tr = "Coğrafi"
+it = "Geo"
+pt = "Geo"
+zh = "地理坐标"
+sv = "Geo"
+ru = "Гео"
+es = "Geo"
+de = "Geo"
+
+[pos]
+en = "Pos"
+fr = "Pos"
+tr = "Poz"
+it = "Pos"
+pt = "Pos"
+zh = "位置"
+sv = "Pos"
+ru = "Поз"
+es = "Pos"
+de = "Pos"
+
+[ext]
+en = "Ext"
+fr = "Ext"
+tr = "Uzantı"
+it = "Est"
+pt = "Ext"
+zh = "扩展"
+sv = "Ext"
+ru = "Расширение"
+es = "Ext"
+de = "Ext"
+
+[help_tagline]
+en = "A network diagnostic tool"
+fr = "Un outil de diagnostic réseau"
+tr = "Bir ağ analiz aracı"
+it = "Uno strumento diagnostico di rete"
+pt = "Uma ferramenta de diagnóstico de rede"
+zh = "网络诊断工具"
+sv = "Ett nätverksdiagnostikverktyg"
+ru = "Инструмент диагностики сети"
+es = "Una herramienta de diagnóstico de red"
+de = "Ein Netzwerkdiagnosetool"
+
+[help_show_settings]
+en = "Press [%{key}] to show all settings"
+fr = "Appuyez sur [%{key}] pour afficher tous les paramètres"
+tr = "Tüm ayarları görmek için [%{key}] tuşuna basın"
+it = "Premi [%{key}] per visualizzare tutte le impostazioni"
+pt = "Pressione [%{key}] para mostrar todas as configurações"
+zh = "按 [%{key}] 显示所有设置"
+sv = "Tryck på [%{key}] för att visa alla inställningar"
+ru = "Нажмите [%{key}], чтобы показать все настройки"
+es = "Presiona [%{key}] para mostrar todas las configuraciones"
+de = "Drücken Sie [%{key}], um alle Einstellungen anzuzeigen"
+
+[help_show_bindings]
+en = "Press [%{key}] to show all bindings"
+fr = "Appuyez sur [%{key}] pour afficher tous les raccourcis clavier"
+tr = "Tüm bağlantıları görmek için [%{key}] tuşuna basın"
+it = "Premi [%{key}] per visualizzare tutti i collegamenti"
+pt = "Pressione [%{key}] para mostrar todos os atalhos"
+zh = "按 [%{key}] 显示所有绑定"
+sv = "Tryck på [%{key}] för att visa alla kortkommando"
+ru = "Нажмите [%{key}], чтобы показать все привязки"
+es = "Presiona [%{key}] para mostrar todos los atajos"
+de = "Drücken Sie [%{key}], um alle Tastenbelegungen anzuzeigen"
+
+[help_show_columns]
+en = "Press [%{key}] to show all columns"
+fr = "Appuyez sur [%{key}] pour afficher toutes les colonnes"
+tr = "Tüm sütunları görmek için [%{key}] tuşuna basın"
+it = "Premi [%{key}] per visualizzare tutte le colonne"
+pt = "Pressione [%{key}] para mostrar todas as colunas"
+zh = "按 [%{key}] 显示所有列"
+sv = "Tryck på [%{key}] för att visa alla kolumner"
+ru = "Нажмите [%{key}], чтобы показать все столбцы"
+es = "Presiona [%{key}] para mostrar todas las columnas"
+de = "Drücken Sie [%{key}], um alle Spalten anzuzeigen"
+
+[help_license]
+en = "Distributed under the Apache License 2.0"
+fr = "Distribué sous licence Apache 2.0"
+tr = "Apache Lisansı 2.0 altında dağıtılmıştır"
+it = "Distribuito con licenza Apache 2.0"
+pt = "Distribuído sob a licença Apache 2.0"
+zh = "以 Apache-2.0 许可分发"
+sv = "Distribueras under Apache License 2.0"
+ru = "Распространяется под лицензией Apache 2.0"
+es = "Distribuido bajo la Licencia Apache 2.0"
+de = "Verteilt unter der Apache-Lizenz 2.0"
+
+[help_copyright]
+en = "Copyright 2022 Trippy Contributors"
+fr = "Copyright 2022 Contributeurs de Trippy"
+tr = "Telif Hakkı 2022 - Trippy'ye Katkıda Bulunanlar"
+it = "Copyright 2022 - Collaboratori di Trippy"
+pt = "Direitos autorais 2022 Colaboradores do Trippy"
+zh = "版权所有 2022 Trippy 贡献者"
+sv = "Upphovsrätt 2022 Trippy-bidragsgivare"
+ru = "Авторское право 2022 Участники Trippy"
+es = "Derechos de autor 2022 Contribuidores de Trippy"
+de = "Copyright 2022 Trippy Mitwirkende"
+
+[geoip_not_enabled]
+en = "GeoIp not enabled"
+fr = "GeoIp non activé"
+tr = "GeoIp etkin değil"
+it = "GeoIp non abilitato"
+pt = "GeoIp não ativado"
+zh = "GeoIp 未启用"
+sv = "GeoIp inte aktiverad"
+ru = "GeoIp не активирован"
+es = "GeoIp no habilitado"
+de = "GeoIp nicht aktiviert"
+
+[geoip_no_data_for_hop]
+en = "No GeoIp data for hop"
+fr = "Pas de données GeoIp pour le saut"
+tr = "Hop için GeoIp verisi yok"
+it = "Nessun dato GeoIp per il salto"
+pt = "Nenhum dado GeoIp para o salto"
+zh = "无 GeoIp 数据"
+sv = "Inga GeoIp-data för hopp"
+ru = "Нет данных GeoIp для прыжка"
+es = "No hay datos de GeoIp para el salto"
+de = "Keine GeoIp-Daten für den Hop"
+
+[geoip_multiple_data_for_hop]
+en = "Multiple GeoIp locations for hop"
+fr = "Emplacements GeoIp multiples pour le saut"
+tr = "Hop için birden fazla GeoIp konumu"
+it = "Posizioni GeoIp multiple per il salto"
+pt = "Múltiplas localizações GeoIp para o salto"
+zh = "多个 GeoIp 位置"
+sv = "Flera GeoIp-platser för hopp"
+ru = "Несколько местоположений GeoIp для прыжка"
+es = "Múltiples ubicaciones de GeoIp para el salto"
+de = "Mehrere GeoIp-Standorte für den Hop"
+
+[kilometer]
+en = "km"
+fr = "km"
+tr = "km"
+it = "km"
+pt = "km"
+zh = "公里"
+sv = "km"
+ru = "км"
+es = "km"
+de = "km"
+
+[settings_info]
+en = "Info"
+fr = "Information"
+tr = "Bilgi"
+it = "Info"
+pt = "Informação"
+zh = "信息"
+sv = "Information"
+ru = "Информация"
+es = "Información"
+de = "Info"
+
+[settings_tab_tui_title]
+en = "Tui"
+fr = "Tui"
+tr = "Tui"
+it = "Tui"
+pt = "Tui"
+zh = "终端用户界面"
+sv = "Tui"
+ru = "Tui"
+es = "Tui"
+de = "Tui"
+
+[settings_tab_trace_title]
+en = "Trace"
+fr = "Tracer"
+tr = "İz"
+it = "Traccia"
+pt = "Rastrear"
+zh = "跟踪"
+sv = "Spåra"
+ru = "След"
+es = "Rastrear"
+de = "Trace"
+
+[settings_tab_dns_title]
+en = "DNS"
+fr = "DNS"
+tr = "DNS"
+it = "DNS"
+pt = "DNS"
+zh = "DNS"
+sv = "DNS"
+ru = "DNS"
+es = "DNS"
+de = "DNS"
+
+[settings_tab_geoip_title]
+en = "GeoIp"
+fr = "GeoIp"
+tr = "GeoIp"
+it = "GeoIp"
+pt = "GeoIp"
+zh = "GeoIp"
+sv = "GeoIp"
+ru = "GeoIp"
+es = "GeoIp"
+de = "GeoIp"
+
+[settings_tab_bindings_title]
+en = "Bindings"
+fr = "Raccourcis clavier"
+tr = "Bağlantılar"
+it = "Collegamenti"
+pt = "Atalhos"
+zh = "绑定"
+sv = "Kortkommando"
+ru = "Привязки"
+es = "Atajos"
+de = "Tastenbelegungen"
+
+[settings_tab_theme_title]
+en = "Theme"
+fr = "Thème"
+tr = "Tema"
+it = "Tema"
+pt = "Tema"
+zh = "主题"
+sv = "Tema"
+ru = "Тема"
+es = "Tema"
+de = "Darstellung"
+
+[settings_tab_columns_title]
+en = "Columns"
+fr = "Colonnes"
+tr = "Sütunlar"
+it = "Colonne"
+pt = "Colunas"
+zh = "列"
+es = "Columnas"
+sv = "Kolumner"
+ru = "Столбцы"
+de = "Spalten"
+
+[settings_tab_tui_desc]
+en = "Settings which control how data is displayed in this Tui"
+fr = "Paramètres qui contrôlent la façon dont les données sont affichées dans ce Tui"
+tr = "Arayüzde verilerin nasıl görüntülendiğini kontrol eden ayarlar"
+it = "Impostazioni che controllano come i dati vengono visualizzati in questo Tui"
+pt = "Configurações que controlam como os dados são exibidos neste Tui"
+zh = "数据显示方式设置"
+sv = "Inställningar som styr hur data visas i detta Tui"
+ru = "Настройки, которые контролируют, как данные отображаются в этом Tui"
+es = "Configuraciones que controlan cómo se muestran los datos en este Tui"
+de = "Einstellungen, die steuern, wie Daten in diesem Tui angezeigt werden"
+
+[settings_tab_trace_desc]
+en = "Settings which control the tracing strategy"
+fr = "Paramètres qui contrôlent la stratégie de traçage"
+tr = "İzleme stratejisini kontrol eden ayarlar"
+it = "Impostazioni che controllano la strategia di tracciamento"
+pt = "Configurações que controlam a estratégia de rastreamento"
+zh = "跟踪策略设置"
+sv = "Inställningar som styr spårningsstrategin"
+ru = "Настройки, которые контролируют стратегию трассировки"
+es = "Configuraciones que controlan la estrategia de rastreo"
+de = "Einstellungen, die die Tracing-Strategie steuern"
+
+[settings_tab_dns_desc]
+en = "Settings which control how DNS lookups are performed"
+fr = "Paramètres qui contrôlent la façon dont les recherches DNS sont effectuées"
+tr = "DNS aramalarının nasıl yapıldığını kontrol eden ayarlar"
+it = "Impostazioni che controllano come vengono eseguite le ricerche DNS"
+pt = "Configurações que controlam como as pesquisas DNS são realizadas"
+zh = "DNS 查询设置"
+sv = "Inställningar som styr hur DNS-uppslag utförs"
+ru = "Настройки, которые контролируют, как выполняются DNS-запросы"
+es = "Configuraciones que controlan cómo se realizan las búsquedas de DNS"
+de = "Einstellungen, die steuern, wie DNS-Lookups durchgeführt werden"
+
+[settings_tab_geoip_desc]
+en = "Settings relating to GeoIp"
+fr = "Paramètres relatifs à GeoIp"
+tr = "GeoIp ile ilgili ayarlar"
+it = "Impostazioni relative a GeoIp"
+pt = "Configurações relacionadas ao GeoIp"
+zh = "GeoIp 设置"
+sv = "Inställningar som rör GeoIp"
+ru = "Настройки, касающиеся GeoIp"
+es = "Configuraciones relacionadas con GeoIp"
+de = "Einstellungen im Zusammenhang mit GeoIp"
+
+[settings_tab_bindings_desc]
+en = "Tui key bindings"
+fr = "Raccourcis clavier Tui"
+tr = "Tui tuş ayarları"
+it = "Collegamenti chiave Tui"
+pt = "Atalhos de teclado Tui"
+zh = "按键绑定设置"
+sv = "Tui-kortkommando"
+ru = "Привязки клавиш Tui"
+es = "Atajos de teclado Tui"
+de = "Tui-Tastenbelegungen"
+
+[settings_tab_theme_desc]
+en = "Tui theme colors"
+fr = "Couleurs du thème Tui"
+tr = "Tui tema renkleri"
+it = "Colori del tema Tui"
+pt = "Cores do tema Tui"
+zh = "主题颜色设置"
+sv = "Tui-temafärger"
+ru = "Цвета темы Tui"
+es = "Colores del tema Tui"
+de = "Tui-Themefarben"
+
+[settings_tab_columns_desc]
+en = "Tui table columns.  Press [%{c}] to toggle a column on or off and use the [%{d}] and [%{u}] keys to change the column order."
+fr = "Colonnes de table Tui. Appuyez sur [%{c}] pour activer ou désactiver une colonne et utilisez les touches [%{d}] et [%{u}] pour changer l'ordre des colonnes."
+tr = "Tui tablo sütunları. Bir sütunu açmak veya kapatmak için [%{c}] tuşuna basın ve sütun sırasını değiştirmek için [%{d}] ve [%{u}] tuşlarını kullanın."
+it = "Colonne della tabella Tui. Premi [%{c}] per attivare o disattivare una colonna e usa i tasti [%{d}] e [%{u}] per cambiare l'ordine delle colonne."
+pt = "Colunas da tabela Tui. Pressione [%{c}] para ativar ou desativar uma coluna e use as teclas [%{d}] e [%{u}] para alterar a ordem das colunas."
+zh = "终端用户界面表格列。按 [%{c}] 切换列的显示和隐藏，使用 [%{d}] 和 [%{u}] 键更改列的顺序。"
+sv = "Tui-tabellkolumner. Tryck på [%{c}] för att slå på eller av en kolumn och använd [%{d}] och [%{u}] för att ändra kolumnordningen."
+ru = "Столбцы таблицы Tui. Нажмите [%{c}], чтобы включить или отключить столбец, и используйте клавиши [%{d}] и [%{u}], чтобы изменить порядок столбцов."
+es = "Columnas de la tabla Tui. Presiona [%{c}] para activar o desactivar una columna y usa las teclas [%{d}] y [%{u}] para cambiar el orden de las columnas."
+de = "Tui-Tabellenspalten. Drücken Sie [%{c}], um eine Spalte ein- oder auszuschalten, und verwenden Sie die Tasten [%{d}] und [%{u}], um die Spaltenreihenfolge zu ändern."
+
+[settings_table_header_setting]
+en = "Setting"
+fr = "Paramètres"
+tr = "Ayar"
+it = "Impostazione"
+pt = "Configuração"
+zh = "设置"
+sv = "Inställning"
+ru = "Настройка"
+es = "Configuración"
+de = "Einstellung"
+
+[settings_table_header_value]
+en = "Value"
+fr = "Valeur"
+tr = "Değer"
+it = "Valore"
+pt = "Valor"
+zh = "值"
+sv = "Värde"
+ru = "Значение"
+es = "Valor"
+de = "Wert"
+
+[column_host]
+en = "Host"
+fr = "Hôte"
+tr = "Ana bilgisayar"
+it = "Host"
+pt = "Host"
+zh = "主机"
+sv = "Värd"
+ru = "Хост"
+es = "Host"
+de = "Host"
+
+[column_loss_pct]
+en = "Loss%"
+fr = "% Perdus"
+tr = "Kayıp%"
+it = "Persi%"
+pt = "% Perdidos"
+zh = "丢包率"
+sv = "Förlust%"
+ru = "Потери%"
+es = "% Perdidos"
+de = "Verlust%"
+
+[column_snd]
+en = "Snd"
+fr = "Envoyés"
+tr = "Gönderilen"
+it = "Snd"
+pt = "Enviados"
+zh = "发出"
+sv = "Skickat"
+ru = "Отпр"
+es = "Enviados"
+de = "Snd"
+
+[column_recv]
+en = "Recv"
+fr = "Reçus"
+tr = "Alınan"
+it = "Recv"
+pt = "Recebidos"
+zh = "接收"
+sv = "Mottagna"
+ru = "Получ"
+es = "Recibidos"
+de = "Recv"
+
+[column_last]
+en = "Last"
+fr = "Dernier"
+tr = "Son"
+it = "Ultimo"
+pt = "Último"
+zh = "最后"
+sv = "Senast"
+ru = "Посл"
+es = "Último"
+de = "Letzte"
+
+[column_avg]
+en = "Avg"
+fr = "Moyenne"
+tr = "Ort"
+it = "Media"
+pt = "Média"
+zh = "平均"
+sv = "Genomsnitt"
+ru = "Сред"
+es = "Prom"
+de = "Durchschnitt"
+
+[column_best]
+en = "Best"
+fr = "Meilleur"
+tr = "En iyi"
+it = "Migliore"
+pt = "Melhor"
+zh = "最佳"
+sv = "Bäst"
+ru = "Луч"
+es = "Mejor"
+de = "Beste"
+
+[column_wrst]
+en = "Wrst"
+fr = "Pire"
+tr = "En kötü"
+it = "Peggiore"
+pt = "Pior"
+zh = "最差"
+sv = "Sämst"
+ru = "Худ"
+es = "Peor"
+de = "Schlechteste"
+
+[column_stdev]
+en = "StDev"
+fr = "ÉcTyp"
+tr = "StDev"
+it = "StDev"
+pt = "DesvPad"
+zh = "标准差"
+sv = "StDev"
+ru = "СКО"
+es = "DesvE"
+de = "StdAbw"
+
+[column_sts]
+en = "Sts"
+fr = "État"
+tr = "Sts"
+it = "Stato"
+pt = "Est"
+zh = "状态"
+sv = "Sts"
+ru = "Статус"
+es = "Est"
+de = "Sts"
+
+[column_jttr]
+en = "Jttr"
+fr = "Gigue"
+tr = "Jttr"
+it = "Jttr"
+pt = "Jttr"
+zh = "抖动"
+sv = "Jttr"
+ru = "Джитр"
+es = "Jttr"
+de = "Jttr"
+
+[column_javg]
+en = "Javg"
+fr = "GigMoy"
+tr = "Javg"
+it = "Javg"
+pt = "Javg"
+zh = "均抖"
+sv = "Javg"
+ru = "СреднДжитр"
+es = "PromJit"
+de = "Javg"
+
+[column_jmax]
+en = "Jmax"
+fr = "GigMax"
+tr = "Jmax"
+it = "Jmax"
+pt = "Jmax"
+zh = "最大抖"
+sv = "Jmax"
+ru = "МаксДжитр"
+es = "JitMax"
+de = "Jmax"
+
+[column_jint]
+en = "Jint"
+fr = "GigInt"
+tr = "Jint"
+it = "Jint"
+pt = "Jint"
+zh = "抖动间隔"
+sv = "Jint"
+ru = "ИнтДжитр"
+es = "JitInt"
+de = "Jint"
+
+[column_sprt]
+en = "Sprt"
+fr = "Psrc"
+tr = "Sprt"
+it = "Sprt"
+zh = "源端"
+sv = "Sprt"
+ru = "Исх"
+es = "Sprt"
+de = "Sprt"
+
+[column_dprt]
+en = "Dprt"
+fr = "Pdest"
+tr = "Dprt"
+it = "Dprt"
+pt = "Dprt"
+zh = "目标"
+sv = "Dprt"
+ru = "Назн"
+es = "Dprt"
+de = "Dprt"
+
+[column_seq]
+en = "Seq"
+fr = "Seq"
+tr = "Seq"
+it = "Seq"
+pt = "Seq"
+zh = "序列"
+sv = "Seq"
+ru = "Посл"
+es = "Seq"
+de = "Seq"
+
+[column_type]
+en = "Type"
+fr = "Type"
+tr = "Type"
+it = "Tipo"
+pt = "Tipo"
+zh = "类型"
+sv = "Typ"
+ru = "Тип"
+es = "Tipo"
+de = "Typ"
+
+[column_code]
+en = "Code"
+fr = "Code"
+tr = "Code"
+it = "Codice"
+pt = "Código"
+zh = "代码"
+sv = "Kod"
+ru = "Код"
+es = "Código"
+de = "Code"
+
+[column_nat]
+en = "Nat"
+fr = "Nat"
+tr = "Nat"
+it = "Nat"
+pt = "Nat"
+zh = "网络地址转换"
+sv = "Nat"
+ru = "Nat"
+es = "Nat"
+de = "Nat"
+
+[column_fail]
+en = "Fail"
+fr = "Échec"
+tr = "Başarısız"
+it = "Falliti"
+pt = "Falha"
+zh = "失败"
+sv = "Misslyckades"
+ru = "Неуд"
+es = "Falló"
+de = "Fehlgeschlagen"
+
+[column_floss]
+en = "Floss"
+fr = "Floss"
+tr = "Floss"
+it = "Floss"
+pt = "Floss"
+zh = "Floss"
+sv = "Floss"
+ru = "Floss"
+es = "Floss"
+de = "Floss"
+
+[column_bloss]
+en = "Bloss"
+fr = "Bloss"
+tr = "Bloss"
+it = "Bloss"
+pt = "Bloss"
+zh = "Bloss"
+sv = "Bloss"
+ru = "Bloss"
+es = "Bloss"
+de = "Bloss"
+
+[column_floss_pct]
+en = "Floss%"
+fr = "Floss%"
+tr = "Floss%"
+it = "Floss%"
+pt = "Floss%"
+zh = "Floss%"
+sv = "Floss%"
+ru = "Floss%"
+es = "Floss%"
+de = "Floss%"
diff --git a/crates/trippy-tui/locales/app.yml b/crates/trippy-tui/locales/app.yml
deleted file mode 100644
index 714b4fcb9..000000000
--- a/crates/trippy-tui/locales/app.yml
+++ /dev/null
@@ -1,1199 +0,0 @@
-_version: 2
-trippy:
-  en: "trippy"
-  fr: "trippy"
-  tr: "trippy"
-  it: "trippy"
-  pt: "trippy"
-  zh: "trippy"
-  sv: "trippy"
-  ru: "trippy"
-  es: "trippy"
-  de: "trippy"
-auto:
-  en: "auto"
-  fr: "automatique"
-  tr: "otomatik"
-  it: "auto"
-  pt: "automático"
-  zh: "自动"
-  sv: "automatisk"
-  ru: "авто"
-  es: "automático"
-  de: "auto"
-on:
-  en: "on"
-  fr: "activé"
-  tr: "açık"
-  it: "on"
-  pt: "ligado"
-  zh: "开"
-  sv: "på"
-  ru: "вкл"
-  es: "activo"
-  de: "an"
-off:
-  en: "off"
-  fr: "désactivé"
-  tr: "kapalı"
-  it: "off"
-  pt: "desligado"
-  zh: "关"
-  sv: "av"
-  ru: "выкл"
-  es: "inactivo"
-  de: "aus"
-yes:
-  en: "Yes"
-  fr: "Oui"
-  tr: "Evet"
-  it: "Sì"
-  pt: "Sim"
-  zh: "是"
-  sv: "Ja"
-  ru: "Да"
-  es: "Sí"
-  de: "Ja"
-no:
-  en: "No"
-  fr: "Non"
-  tr: "Hayır"
-  it: "No"
-  pt: "Não"
-  zh: "否"
-  sv: "Nej"
-  ru: "Нет"
-  es: "No"
-  de: "Nein"
-none:
-  en: "none"
-  fr: "aucun"
-  tr: "hiçbiri"
-  it: "nessuno"
-  pt: "nenhum"
-  zh: "无"
-  sv: "ingen"
-  ru: "нет"
-  es: "ninguno"
-  de: "keiner"
-hidden:
-  en: "Hidden"
-  fr: "Caché"
-  tr: "Gizli"
-  it: "Nascosto"
-  pt: "Oculto"
-  zh: "隐藏"
-  sv: "Dold"
-  ru: "Скрыто"
-  es: "Oculto"
-  de: "Versteckt"
-flow:
-  en: "flow"
-  fr: "flux"
-  tr: "akış"
-  it: "flusso"
-  pt: "fluxo"
-  zh: "流量"
-  sv: "flöde"
-  ru: "поток"
-  es: "flujo"
-  de: "fluss"
-flows:
-  en: "flows"
-  fr: "flux"
-  tr: "akışlar"
-  it: "flussi"
-  pt: "fluxos"
-  zh: "流量"
-  sv: "flöden"
-  ru: "потоки"
-  es: "flujos"
-  de: "flüsse"
-target:
-  en: "Target"
-  fr: "Cible"
-  tr: "Hedef"
-  it: "Target"
-  pt: "Alvo"
-  zh: "目标"
-  sv: "Mål"
-  ru: "Цель"
-  es: "Objetivo"
-  de: "Ziel"
-status:
-  en: "Status"
-  fr: "Statut"
-  tr: "Durum"
-  it: "Stato"
-  pt: "Estado"
-  zh: "状态"
-  sv: "Status"
-  ru: "Статус"
-  es: "Estado"
-  de: "Status"
-details:
-  en: "detail"
-  fr: "détail"
-  tr: "ayrıntılar"
-  it: "dettagli"
-  pt: "detalhe"
-  zh: "详情"
-  sv: "detaljer"
-  ru: "детали"
-  es: "detalles"
-  de: "detail"
-privileged:
-  en: "privileged"
-  fr: "privilégié"
-  tr: "ayrıcalıklı"
-  it: "privilegiato"
-  pt: "privilegiado"
-  zh: "特权"
-  sv: "privilegierad"
-  ru: "привилегированный"
-  es: "privilegiado"
-  de: "privilegiert"
-unprivileged:
-  en: "unprivileged"
-  fr: "non privilégié"
-  tr: "ayrıcalıksız"
-  it: "non privilegiato"
-  pt: "não privilegiado"
-  zh: "非特权"
-  sv: "oprivilegierad"
-  ru: "непривилегированный"
-  es: "no privilegiado"
-  de: "unprivilegiert"
-privacy:
-  en: "privacy"
-  fr: "confidentialité"
-  tr: "gizlilik"
-  it: "privacy"
-  pt: "privacidade"
-  zh: "隐私"
-  sv: "integritet"
-  ru: "конфиденциальность"
-  es: "privacidad"
-  de: "datenschutz"
-na:
-  en: "n/a"
-  fr: "non disponible"
-  tr: "yok"
-  it: "n/d"
-  pt: "n/d"
-  zh: "无"
-  sv: "ej tillgänglig"
-  ru: "н/д"
-  es: "n/d"
-  de: "n/a"
-discovered:
-  en: "discovered %{hop_count} hops"
-  fr: "%{hop_count} sauts découverts"
-  tr: "%{hop_count} atlanan keşfedildi"
-  it: "%{hop_count} salti trovati"
-  pt: "descobriu %{hop_count} saltos"
-  zh: "发现 %{hop_count} 跳"
-  sv: "upptäckte %{hop_count} hopp"
-  ru: "обнаружено %{hop_count} прыжков"
-  es: "se descubrieron %{hop_count} saltos"
-  de: "%{hop_count} gefundene hops"
-discovered_flows:
-  en: "discovered %{hop_count} hops and %{flow_count} unique %{plural_flows}"
-  fr: "%{hop_count} sauts et %{flow_count} %{plural_flows} uniques découverts"
-  tr: "%{hop_count} atlanan ve %{flow_count} benzersiz %{plural_flows} keşfedildi"
-  it: "scoperti %{hop_count} salti e %{flow_count} %{plural_flows} unici"
-  pt: "descobriu %{hop_count} saltos e %{flow_count} %{plural_flows} únicos"
-  zh: "发现 %{hop_count} 跳，%{flow_count} 个唯一%{plural_flow}"
-  sv: "%{hop_count} hopp och unika %{flow_count} %{plural_flows} upptäckta"
-  ru: "обнаружено %{hop_count} прыжков и %{flow_count} уникальных %{plural_flows}"
-  es: "se descubrieron %{hop_count} saltos y %{flow_count} únicos %{plural_flows}"
-  de: "%{hop_count} gefundene hops und %{flow_count} eindeutige %{plural_flows}"
-unknown:
-  en: "unknown"
-  fr: "inconnu"
-  tr: "bilinmeyen"
-  it: "sconosciuto"
-  pt: "desconhecido"
-  zh: "未知"
-  sv: "okänd"
-  ru: "неизвестно"
-  es: "desconocido"
-  de: "unbekannt"
-icmp:
-  en: "icmp"
-  fr: "icmp"
-  tr: "icmp"
-  it: "icmp"
-  pt: "icmp"
-  zh: "icmp"
-  sv: "icmp"
-  ru: "icmp"
-  es: "icmp"
-  de: "icmp"
-udp:
-  en: "udp"
-  fr: "udp"
-  tr: "udp"
-  it: "udp"
-  pt: "udp"
-  zh: "udp"
-  sv: "udp"
-  ru: "udp"
-  es: "udp"
-  de: "udp"
-tcp:
-  en: "tcp"
-  fr: "tcp"
-  tr: "tcp"
-  it: "tcp"
-  pt: "tcp"
-  zh: "tcp"
-  sv: "tcp"
-  ru: "tcp"
-  es: "tcp"
-  de: "tcp"
-status_failures:
-  en: "%{failure_count} of %{total_probes} (%{failure_rate}%) probes failed"
-  fr: "%{failure_count} sur %{total_probes} (%{failure_rate}%) sondes ont échoué"
-  tr: "%{failure_count} / %{total_probes} (%{failure_rate}%) sondajın başarısız olması"
-  it: "%{failure_count} di %{total_probes} (%{failure_rate}%) prove fallite"
-  pt: "%{failure_count} de %{total_probes} (%{failure_rate}%) sondas falharam"
-  zh: "%{failure_count} 个失败，共探测到 %{total_probes} 个（%{failure_rate}%）"
-  sv: "%{failure_count} av %{total_probes} (%{failure_rate}%) misslyckade prober"
-  ru: "%{failure_count} из %{total_probes} (%{failure_rate}%) зондов не удалось"
-  es: "%{failure_count} de %{total_probes} (%{failure_rate}%) sondas fallaron"
-  de: "%{failure_count} von %{total_probes} (%{failure_rate}%) sonden sind fehlgeschlagen"
-status_failed:
-  en: "Failed"
-  fr: "Échec"
-  tr: "Başarısız"
-  it: "Fallito"
-  pt: "Falhou"
-  zh: "失败"
-  sv: "Misslyckades"
-  ru: "Не удалось"
-  es: "Fallido"
-  de: "Fehlgeschlagen"
-status_running:
-  en: "Running"
-  fr: "En cours"
-  tr: "Çalışıyor"
-  it: "In esecuzione"
-  pt: "Executando"
-  zh: "运行中"
-  sv: "Kör"
-  ru: "Запущен"
-  es: "En ejecución"
-  de: "Läuft"
-status_frozen:
-  en: "Frozen"
-  fr: "Gelé"
-  tr: "Dondurulmuş"
-  it: "Congelato"
-  pt: "Congelado"
-  zh: "冻结"
-  sv: "Frusen"
-  ru: "Заморожен"
-  es: "Congelado"
-  de: "Eingefroren"
-awaiting_data:
-  en: "Awaiting data..."
-  fr: "En attente de données..."
-  tr: "Veri bekleniyor..."
-  it: "In attesa di dati..."
-  pt: "Aguardando dados..."
-  zh: "等待数据……"
-  sv: "Väntar på data..."
-  ru: "Ожидание данных..."
-  es: "Esperando datos..."
-  de: "Warten auf Daten..."
-header_help:
-  en: "help"
-  fr: "aide"
-  tr: "yardım"
-  it: "aiuto"
-  pt: "ajuda"
-  zh: "帮助"
-  sv: "hjälp"
-  ru: "помощь"
-  es: "ayuda"
-  de: "hilfe"
-header_settings:
-  en: "settings"
-  fr: "paramètres"
-  tr: "ayarlar"
-  it: "impostazioni"
-  pt: "configurações"
-  zh: "设置"
-  sv: "inställningar"
-  ru: "настройки"
-  es: "configuraciones"
-  de: "einstellungen"
-header_quit:
-  en: "quit"
-  fr: "quitter"
-  tr: "cıkış"
-  it: "uscita"
-  pt: "sair"
-  zh: "退出"
-  sv: "avsluta"
-  ru: "Выход"
-  es: "salir"
-  de: "beenden"
-title_hops:
-  en: "Hops"
-  fr: "Sauts"
-  tr: "Atlananlar"
-  it: "Salti"
-  pt: "Saltos"
-  zh: "跳"
-  sv: "Hopp"
-  ru: "Прыжки"
-  es: "Saltos"
-  de: "Hops"
-title_frequency:
-  en: "Frequency"
-  fr: "Fréquence"
-  tr: "Sıklık"
-  it: "Frequenza"
-  pt: "Frequência"
-  zh: "频率"
-  sv: "Frekvens"
-  ru: "Частота"
-  es: "Frecuencia"
-  de: "Frequenz"
-title_samples:
-  en: "Samples"
-  fr: "Échantillons"
-  tr: "Örnekler"
-  it: "Campioni"
-  pt: "Amostras"
-  zh: "样本"
-  sv: "Prover"
-  ru: "Образцы"
-  es: "Muestras"
-  de: "Proben"
-title_traces:
-  en: "Traces"
-  fr: "Traces"
-  tr: "İzler"
-  it: "Tracce"
-  pt: "Rastreios"
-  zh: "跟踪"
-  sv: "Spår"
-  ru: "Следы"
-  es: "Trazas"
-  de: "Spuren"
-title_flows:
-  en: "Flows"
-  fr: "Flux"
-  tr: "Akışlar"
-  it: "Flussi"
-  pt: "Fluxos"
-  zh: "流量"
-  sv: "Flöden"
-  ru: "Потоки"
-  es: "Flujos"
-  de: "Flüsse"
-title_map:
-  en: "Map"
-  fr: "Carte"
-  tr: "Harita"
-  it: "Mappa"
-  pt: "Mapa"
-  zh: "地图"
-  sv: "Karta"
-  ru: "Карта"
-  es: "Mapa"
-  de: "Karte"
-title_help:
-  en: "Help"
-  fr: "Aide"
-  tr: "Yardım"
-  it: "Aiuto"
-  pt: "Ajuda"
-  zh: "帮助"
-  sv: "Hjälp"
-  ru: "Помощь"
-  es: "Ayuda"
-  de: "Hilfe"
-title_settings:
-  en: "Settings"
-  fr: "Paramètres"
-  tr: "Ayarlar"
-  it: "Impostazioni"
-  pt: "Configurações"
-  zh: "设置"
-  sv: "Inställningar"
-  ru: "Настройки"
-  es: "Configuraciones"
-  de: "Einstellungen"
-bsod_failed:
-  en: "Trippy Failed :("
-  fr: "Trippy a échoué :("
-  tr: "Trippy Başarısız :("
-  it: "Trippy ha avuto un problema :("
-  pt: "Trippy falhou :("
-  zh: "Trippy 失败 :("
-  sv: "Trippy misslyckades :("
-  ru: "Trippy не удалось :("
-  es: "Trippy tuvo un problema :("
-  de: "Trippy ist fehlgeschlagen :("
-bsod_quit:
-  en: "Press q to quit"
-  fr: "Appuyez sur q pour quitter"
-  tr: "Çıkmak için q tuşuna basın"
-  it: "Premi q per uscire"
-  pt: "Pressione q para sair"
-  zh: "按 q 退出"
-  sv: "Tryck på q för att avsluta"
-  ru: "Нажмите q для выхода"
-  es: "Presiona q para salir"
-  de: "Drücken Sie q, um zu beenden"
-hop:
-  en: "Hop"
-  fr: "Saut"
-  tr: "Atla"
-  it: "Salto"
-  pt: "Salto"
-  zh: "跳"
-  sv: "Hopp"
-  ru: "Прыжок"
-  es: "Salto"
-  de: "Hop"
-rtt:
-  en: "RTT"
-  fr: "RTT"
-  tr: "RTT"
-  it: "RTT"
-  pt: "RTT"
-  zh: "往返时间"
-  sv: "RTT"
-  ru: "RTT"
-  es: "RTT"
-  de: "RTT"
-title_chart:
-  en: "Chart"
-  fr: "Graphique"
-  tr: "Grafik"
-  it: "Grafico"
-  pt: "Gráfico"
-  zh: "图表"
-  sv: "Diagram"
-  ru: "Диаграмма"
-  es: "Gráfico"
-  de: "Diagramm"
-samples:
-  en: "Samples"
-  fr: "Échantillons"
-  tr: "Örnekler"
-  it: "Campioni"
-  pt: "Amostras"
-  zh: "样本"
-  sv: "Prover"
-  ru: "Образцы"
-  es: "Muestras"
-  de: "Proben"
-host:
-  en: "Host"
-  fr: "Hôte"
-  tr: "Ana bilgisayar"
-  it: "Host"
-  pt: "Host"
-  zh: "主机"
-  sv: "Värd"
-  ru: "Хост"
-  es: "Host"
-  de: "Host"
-no_response:
-  en: "No response"
-  fr: "Pas de réponse"
-  tr: "Yanıt yok"
-  it: "Nessuna risposta"
-  pt: "Sem resposta"
-  zh: "无响应"
-  sv: "Inget svar"
-  ru: "Нет ответа"
-  es: "Sin respuesta"
-  de: "Keine Antwort"
-dns_failed:
-  en: "Failed"
-  fr: "Échec"
-  tr: "Başarısız"
-  it: "Fallito"
-  pt: "Falhou"
-  zh: "失败"
-  sv: "Misslyckades"
-  ru: "Не удалось"
-  es: "Fallido"
-  de: "Fehlgeschlagen"
-dns_timeout:
-  en: "Timeout"
-  fr: "Délai dépassé"
-  tr: "Zaman aşımı"
-  it: "Tempo scaduto"
-  pt: "Tempo esgotado"
-  zh: "超时"
-  sv: "Tidsgräns nådd"
-  ru: "Тайм-аут"
-  es: "Tiempo de espera"
-  de: "Zeitüberschreitung"
-labels:
-  en: "labels"
-  fr: "étiquettes"
-  tr: "etiketler"
-  it: "etichette"
-  pt: "etiquetas"
-  zh: "标签"
-  sv: "etiketter"
-  ru: "метки"
-  es: "etiquetas"
-  de: "etiketten"
-not_enabled:
-  en: "not enabled"
-  fr: "non activé"
-  tr: "etkin değil"
-  it: "non abilitato"
-  pt: "não ativado"
-  zh: "未启用"
-  sv: "ej aktiverad"
-  ru: "не активирован"
-  es: "no habilitado"
-  de: "nicht aktiviert"
-not_found:
-  en: "not found"
-  fr: "non trouvé"
-  tr: "bulunamadı"
-  it: "non trovato"
-  pt: "não encontrado"
-  zh: "未找到"
-  sv: "hittades inte"
-  ru: "не найдено"
-  es: "no encontrado"
-  de: "nicht gefunden"
-awaited:
-  en: "awaited"
-  fr: "attendu"
-  tr: "beklenen"
-  it: "atteso"
-  pt: "aguardado"
-  zh: "等待"
-  sv: "väntade"
-  ru: "ожидаемый"
-  es: "esperado"
-  de: "erwartet"
-name:
-  en: "Name"
-  fr: "Nom"
-  tr: "Ad"
-  it: "Nome"
-  pt: "Nome"
-  zh: "名称"
-  sv: "Namn"
-  ru: "Имя"
-  es: "Nombre"
-  de: "Name"
-info:
-  en: "Info"
-  fr: "Information"
-  tr: "Bilgi"
-  it: "Info"
-  pt: "Informação"
-  zh: "信息"
-  sv: "Information"
-  ru: "Информация"
-  es: "Información"
-  de: "Info"
-geo:
-  en: "Geo"
-  fr: "Géo"
-  tr: "Coğrafi"
-  it: "Geo"
-  pt: "Geo"
-  zh: "地理坐标"
-  sv: "Geo"
-  ru: "Гео"
-  es: "Geo"
-  de: "Geo"
-pos:
-  en: "Pos"
-  fr: "Pos"
-  tr: "Poz"
-  it: "Pos"
-  pt: "Pos"
-  zh: "位置"
-  sv: "Pos"
-  ru: "Поз"
-  es: "Pos"
-  de: "Pos"
-ext:
-  en: "Ext"
-  fr: "Ext"
-  tr: "Uzantı"
-  it: "Est"
-  pt: "Ext"
-  zh: "扩展"
-  sv: "Ext"
-  ru: "Расширение"
-  es: "Ext"
-  de: "Ext"
-help_tagline:
-  en: "A network diagnostic tool"
-  fr: "Un outil de diagnostic réseau"
-  tr: "Bir ağ analiz aracı"
-  it: "Uno strumento diagnostico di rete"
-  pt: "Uma ferramenta de diagnóstico de rede"
-  zh: "网络诊断工具"
-  sv: "Ett nätverksdiagnostikverktyg"
-  ru: "Инструмент диагностики сети"
-  es: "Una herramienta de diagnóstico de red"
-  de: "Ein Netzwerkdiagnosetool"
-help_show_settings:
-  en: "Press [%{key}] to show all settings"
-  fr: "Appuyez sur [%{key}] pour afficher tous les paramètres"
-  tr: "Tüm ayarları görmek için [%{key}] tuşuna basın"
-  it: "Premi [%{key}] per visualizzare tutte le impostazioni"
-  pt: "Pressione [%{key}] para mostrar todas as configurações"
-  zh: "按 [%{key}] 显示所有设置"
-  sv: "Tryck på [%{key}] för att visa alla inställningar"
-  ru: "Нажмите [%{key}], чтобы показать все настройки"
-  es: "Presiona [%{key}] para mostrar todas las configuraciones"
-  de: "Drücken Sie [%{key}], um alle Einstellungen anzuzeigen"
-help_show_bindings:
-  en: "Press [%{key}] to show all bindings"
-  fr: "Appuyez sur [%{key}] pour afficher tous les raccourcis clavier"
-  tr: "Tüm bağlantıları görmek için [%{key}] tuşuna basın"
-  it: "Premi [%{key}] per visualizzare tutti i collegamenti"
-  pt: "Pressione [%{key}] para mostrar todos os atalhos"
-  zh: "按 [%{key}] 显示所有绑定"
-  sv: "Tryck på [%{key}] för att visa alla kortkommando"
-  ru: "Нажмите [%{key}], чтобы показать все привязки"
-  es: "Presiona [%{key}] para mostrar todos los atajos"
-  de: "Drücken Sie [%{key}], um alle Tastenbelegungen anzuzeigen"
-help_show_columns:
-  en: "Press [%{key}] to show all columns"
-  fr: "Appuyez sur [%{key}] pour afficher toutes les colonnes"
-  tr: "Tüm sütunları görmek için [%{key}] tuşuna basın"
-  it: "Premi [%{key}] per visualizzare tutte le colonne"
-  pt: "Pressione [%{key}] para mostrar todas as colunas"
-  zh: "按 [%{key}] 显示所有列"
-  sv: "Tryck på [%{key}] för att visa alla kolumner"
-  ru: "Нажмите [%{key}], чтобы показать все столбцы"
-  es: "Presiona [%{key}] para mostrar todas las columnas"
-  de: "Drücken Sie [%{key}], um alle Spalten anzuzeigen"
-help_license:
-  en: "Distributed under the Apache License 2.0"
-  fr: "Distribué sous licence Apache 2.0"
-  tr: "Apache Lisansı 2.0 altında dağıtılmıştır"
-  it: "Distribuito con licenza Apache 2.0"
-  pt: "Distribuído sob a licença Apache 2.0"
-  zh: "以 Apache-2.0 许可分发"
-  sv: "Distribueras under Apache License 2.0"
-  ru: "Распространяется под лицензией Apache 2.0"
-  es: "Distribuido bajo la Licencia Apache 2.0"
-  de: "Verteilt unter der Apache-Lizenz 2.0"
-help_copyright:
-  en: "Copyright 2022 Trippy Contributors"
-  fr: "Copyright 2022 Contributeurs de Trippy"
-  tr: "Telif Hakkı 2022 - Trippy'ye Katkıda Bulunanlar"
-  it: "Copyright 2022 - Collaboratori di Trippy"
-  pt: "Direitos autorais 2022 Colaboradores do Trippy"
-  zh: "版权所有 2022 Trippy 贡献者"
-  sv: "Upphovsrätt 2022 Trippy-bidragsgivare"
-  ru: "Авторское право 2022 Участники Trippy"
-  es: "Derechos de autor 2022 Contribuidores de Trippy"
-  de: "Copyright 2022 Trippy Mitwirkende"
-geoip_not_enabled:
-  en: "GeoIp not enabled"
-  fr: "GeoIp non activé"
-  tr: "GeoIp etkin değil"
-  it: "GeoIp non abilitato"
-  pt: "GeoIp não ativado"
-  zh: "GeoIp 未启用"
-  sv: "GeoIp inte aktiverad"
-  ru: "GeoIp не активирован"
-  es: "GeoIp no habilitado"
-  de: "GeoIp nicht aktiviert"
-geoip_no_data_for_hop:
-  en: "No GeoIp data for hop"
-  fr: "Pas de données GeoIp pour le saut"
-  tr: "Hop için GeoIp verisi yok"
-  it: "Nessun dato GeoIp per il salto"
-  pt: "Nenhum dado GeoIp para o salto"
-  zh: "无 GeoIp 数据"
-  sv: "Inga GeoIp-data för hopp"
-  ru: "Нет данных GeoIp для прыжка"
-  es: "No hay datos de GeoIp para el salto"
-  de: "Keine GeoIp-Daten für den Hop"
-geoip_multiple_data_for_hop:
-  en: "Multiple GeoIp locations for hop"
-  fr: "Emplacements GeoIp multiples pour le saut"
-  tr: "Hop için birden fazla GeoIp konumu"
-  it: "Posizioni GeoIp multiple per il salto"
-  pt: "Múltiplas localizações GeoIp para o salto"
-  zh: "多个 GeoIp 位置"
-  sv: "Flera GeoIp-platser för hopp"
-  ru: "Несколько местоположений GeoIp для прыжка"
-  es: "Múltiples ubicaciones de GeoIp para el salto"
-  de: "Mehrere GeoIp-Standorte für den Hop"
-kilometer:
-  en: "km"
-  fr: "km"
-  tr: "km"
-  it: "km"
-  pt: "km"
-  zh: "公里"
-  sv: "km"
-  ru: "км"
-  es: "km"
-  de: "km"
-settings_info:
-  en: "Info"
-  fr: "Information"
-  tr: "Bilgi"
-  it: "Info"
-  pt: "Informação"
-  zh: "信息"
-  sv: "Information"
-  ru: "Информация"
-  es: "Información"
-  de: "Info"
-settings_tab_tui_title:
-  en: "Tui"
-  fr: "Tui"
-  tr: "Tui"
-  it: "Tui"
-  pt: "Tui"
-  zh: "终端用户界面"
-  sv: "Tui"
-  ru: "Tui"
-  es: "Tui"
-  de: "Tui"
-settings_tab_trace_title:
-  en: "Trace"
-  fr: "Tracer"
-  tr: "İz"
-  it: "Traccia"
-  pt: "Rastrear"
-  zh: "跟踪"
-  sv: "Spåra"
-  ru: "След"
-  es: "Rastrear"
-  de: "Trace"
-settings_tab_dns_title:
-  en: "DNS"
-  fr: "DNS"
-  tr: "DNS"
-  it: "DNS"
-  pt: "DNS"
-  zh: "DNS"
-  sv: "DNS"
-  ru: "DNS"
-  es: "DNS"
-  de: "DNS"
-settings_tab_geoip_title:
-  en: "GeoIp"
-  fr: "GeoIp"
-  tr: "GeoIp"
-  it: "GeoIp"
-  pt: "GeoIp"
-  zh: "GeoIp"
-  sv: "GeoIp"
-  ru: "GeoIp"
-  es: "GeoIp"
-  de: "GeoIp"
-settings_tab_bindings_title:
-  en: "Bindings"
-  fr: "Raccourcis clavier"
-  tr: "Bağlantılar"
-  it: "Collegamenti"
-  pt: "Atalhos"
-  zh: "绑定"
-  sv: "Kortkommando"
-  ru: "Привязки"
-  es: "Atajos"
-  de: "Tastenbelegungen"
-settings_tab_theme_title:
-  en: "Theme"
-  fr: "Thème"
-  tr: "Tema"
-  it: "Tema"
-  pt: "Tema"
-  zh: "主题"
-  sv: "Tema"
-  ru: "Тема"
-  es: "Tema"
-  de: "Darstellung"
-settings_tab_columns_title:
-  en: "Columns"
-  fr: "Colonnes"
-  tr: "Sütunlar"
-  it: "Colonne"
-  pt: "Colunas"
-  zh: "列"
-  es: "Columnas"
-  sv: "Kolumner"
-  ru: "Столбцы"
-  de: "Spalten"
-settings_tab_tui_desc:
-  en: "Settings which control how data is displayed in this Tui"
-  fr: "Paramètres qui contrôlent la façon dont les données sont affichées dans ce Tui"
-  tr: "Arayüzde verilerin nasıl görüntülendiğini kontrol eden ayarlar"
-  it: "Impostazioni che controllano come i dati vengono visualizzati in questo Tui"
-  pt: "Configurações que controlam como os dados são exibidos neste Tui"
-  zh: "数据显示方式设置"
-  sv: "Inställningar som styr hur data visas i detta Tui"
-  ru: "Настройки, которые контролируют, как данные отображаются в этом Tui"
-  es: "Configuraciones que controlan cómo se muestran los datos en este Tui"
-  de: "Einstellungen, die steuern, wie Daten in diesem Tui angezeigt werden"
-settings_tab_trace_desc:
-  en: "Settings which control the tracing strategy"
-  fr: "Paramètres qui contrôlent la stratégie de traçage"
-  tr: "İzleme stratejisini kontrol eden ayarlar"
-  it: "Impostazioni che controllano la strategia di tracciamento"
-  pt: "Configurações que controlam a estratégia de rastreamento"
-  zh: "跟踪策略设置"
-  sv: "Inställningar som styr spårningsstrategin"
-  ru: "Настройки, которые контролируют стратегию трассировки"
-  es: "Configuraciones que controlan la estrategia de rastreo"
-  de: "Einstellungen, die die Tracing-Strategie steuern"
-settings_tab_dns_desc:
-  en: "Settings which control how DNS lookups are performed"
-  fr: "Paramètres qui contrôlent la façon dont les recherches DNS sont effectuées"
-  tr: "DNS aramalarının nasıl yapıldığını kontrol eden ayarlar"
-  it: "Impostazioni che controllano come vengono eseguite le ricerche DNS"
-  pt: "Configurações que controlam como as pesquisas DNS são realizadas"
-  zh: "DNS 查询设置"
-  sv: "Inställningar som styr hur DNS-uppslag utförs"
-  ru: "Настройки, которые контролируют, как выполняются DNS-запросы"
-  es: "Configuraciones que controlan cómo se realizan las búsquedas de DNS"
-  de: "Einstellungen, die steuern, wie DNS-Lookups durchgeführt werden"
-settings_tab_geoip_desc:
-  en: "Settings relating to GeoIp"
-  fr: "Paramètres relatifs à GeoIp"
-  tr: "GeoIp ile ilgili ayarlar"
-  it: "Impostazioni relative a GeoIp"
-  pt: "Configurações relacionadas ao GeoIp"
-  zh: "GeoIp 设置"
-  sv: "Inställningar som rör GeoIp"
-  ru: "Настройки, касающиеся GeoIp"
-  es: "Configuraciones relacionadas con GeoIp"
-  de: "Einstellungen im Zusammenhang mit GeoIp"
-settings_tab_bindings_desc:
-  en: "Tui key bindings"
-  fr: "Raccourcis clavier Tui"
-  tr: "Tui tuş ayarları"
-  it: "Collegamenti chiave Tui"
-  pt: "Atalhos de teclado Tui"
-  zh: "按键绑定设置"
-  sv: "Tui-kortkommando"
-  ru: "Привязки клавиш Tui"
-  es: "Atajos de teclado Tui"
-  de: "Tui-Tastenbelegungen"
-settings_tab_theme_desc:
-  en: "Tui theme colors"
-  fr: "Couleurs du thème Tui"
-  tr: "Tui tema renkleri"
-  it: "Colori del tema Tui"
-  pt: "Cores do tema Tui"
-  zh: "主题颜色设置"
-  sv: "Tui-temafärger"
-  ru: "Цвета темы Tui"
-  es: "Colores del tema Tui"
-  de: "Tui-Themefarben"
-settings_tab_columns_desc:
-  en: "Tui table columns.  Press [%{c}] to toggle a column on or off and use the [%{d}] and [%{u}] keys to change the column order."
-  fr: "Colonnes de table Tui. Appuyez sur [%{c}] pour activer ou désactiver une colonne et utilisez les touches [%{d}] et [%{u}] pour changer l'ordre des colonnes."
-  tr: "Tui tablo sütunları. Bir sütunu açmak veya kapatmak için [%{c}] tuşuna basın ve sütun sırasını değiştirmek için [%{d}] ve [%{u}] tuşlarını kullanın."
-  it: "Colonne della tabella Tui. Premi [%{c}] per attivare o disattivare una colonna e usa i tasti [%{d}] e [%{u}] per cambiare l'ordine delle colonne."
-  pt: "Colunas da tabela Tui. Pressione [%{c}] para ativar ou desativar uma coluna e use as teclas [%{d}] e [%{u}] para alterar a ordem das colunas."
-  zh: "终端用户界面表格列。按 [%{c}] 切换列的显示和隐藏，使用 [%{d}] 和 [%{u}] 键更改列的顺序。"
-  sv: "Tui-tabellkolumner. Tryck på [%{c}] för att slå på eller av en kolumn och använd [%{d}] och [%{u}] för att ändra kolumnordningen."
-  ru: "Столбцы таблицы Tui. Нажмите [%{c}], чтобы включить или отключить столбец, и используйте клавиши [%{d}] и [%{u}], чтобы изменить порядок столбцов."
-  es: "Columnas de la tabla Tui. Presiona [%{c}] para activar o desactivar una columna y usa las teclas [%{d}] y [%{u}] para cambiar el orden de las columnas."
-  de: "Tui-Tabellenspalten. Drücken Sie [%{c}], um eine Spalte ein- oder auszuschalten, und verwenden Sie die Tasten [%{d}] und [%{u}], um die Spaltenreihenfolge zu ändern."
-settings_table_header_setting:
-  en: "Setting"
-  fr: "Paramètres"
-  tr: "Ayar"
-  it: "Impostazione"
-  pt: "Configuração"
-  zh: "设置"
-  sv: "Inställning"
-  ru: "Настройка"
-  es: "Configuración"
-  de: "Einstellung"
-settings_table_header_value:
-  en: "Value"
-  fr: "Valeur"
-  tr: "Değer"
-  it: "Valore"
-  pt: "Valor"
-  zh: "值"
-  sv: "Värde"
-  ru: "Значение"
-  es: "Valor"
-  de: "Wert"
-column_host:
-  en: "Host"
-  fr: "Hôte"
-  tr: "Ana bilgisayar"
-  it: "Host"
-  pt: "Host"
-  zh: "主机"
-  sv: "Värd"
-  ru: "Хост"
-  es: "Host"
-  de: "Host"
-column_loss_pct:
-  en: "Loss%"
-  fr: "% Perdus"
-  tr: "Kayıp%"
-  it: "Persi%"
-  pt: "% Perdidos"
-  zh: "丢包率"
-  sv: "Förlust%"
-  ru: "Потери%"
-  es: "% Perdidos"
-  de: "Verlust%"
-column_snd:
-  en: "Snd"
-  fr: "Envoyés"
-  tr: "Gönderilen"
-  it: "Snd"
-  pt: "Enviados"
-  zh: "发出"
-  sv: "Skickat"
-  ru: "Отпр"
-  es: "Enviados"
-  de: "Snd"
-column_recv:
-  en: "Recv"
-  fr: "Reçus"
-  tr: "Alınan"
-  it: "Recv"
-  pt: "Recebidos"
-  zh: "接收"
-  sv: "Mottagna"
-  ru: "Получ"
-  es: "Recibidos"
-  de: "Recv"
-column_last:
-  en: "Last"
-  fr: "Dernier"
-  tr: "Son"
-  it: "Ultimo"
-  pt: "Último"
-  zh: "最后"
-  sv: "Senast"
-  ru: "Посл"
-  es: "Último"
-  de: "Letzte"
-column_avg:
-  en: "Avg"
-  fr: "Moyenne"
-  tr: "Ort"
-  it: "Media"
-  pt: "Média"
-  zh: "平均"
-  sv: "Genomsnitt"
-  ru: "Сред"
-  es: "Prom"
-  de: "Durchschnitt"
-column_best:
-  en: "Best"
-  fr: "Meilleur"
-  tr: "En iyi"
-  it: "Migliore"
-  pt: "Melhor"
-  zh: "最佳"
-  sv: "Bäst"
-  ru: "Луч"
-  es: "Mejor"
-  de: "Beste"
-column_wrst:
-  en: "Wrst"
-  fr: "Pire"
-  tr: "En kötü"
-  it: "Peggiore"
-  pt: "Pior"
-  zh: "最差"
-  sv: "Sämst"
-  ru: "Худ"
-  es: "Peor"
-  de: "Schlechteste"
-column_stdev:
-  en: "StDev"
-  fr: "ÉcTyp"
-  tr: "StDev"
-  it: "StDev"
-  pt: "DesvPad"
-  zh: "标准差"
-  sv: "StDev"
-  ru: "СКО"
-  es: "DesvE"
-  de: "StdAbw"
-column_sts:
-  en: "Sts"
-  fr: "État"
-  tr: "Sts"
-  it: "Stato"
-  pt: "Est"
-  zh: "状态"
-  sv: "Sts"
-  ru: "Статус"
-  es: "Est"
-  de: "Sts"
-column_jttr:
-  en: "Jttr"
-  fr: "Gigue"
-  tr: "Jttr"
-  it: "Jttr"
-  pt: "Jttr"
-  zh: "抖动"
-  sv: "Jttr"
-  ru: "Джитр"
-  es: "Jttr"
-  de: "Jttr"
-column_javg:
-  en: "Javg"
-  fr: "GigMoy"
-  tr: "Javg"
-  it: "Javg"
-  pt: "Javg"
-  zh: "均抖"
-  sv: "Javg"
-  ru: "СреднДжитр"
-  es: "PromJit"
-  de: "Javg"
-column_jmax:
-  en: "Jmax"
-  fr: "GigMax"
-  tr: "Jmax"
-  it: "Jmax"
-  pt: "Jmax"
-  zh: "最大抖"
-  sv: "Jmax"
-  ru: "МаксДжитр"
-  es: "JitMax"
-  de: "Jmax"
-column_jint:
-  en: "Jint"
-  fr: "GigInt"
-  tr: "Jint"
-  it: "Jint"
-  pt: "Jint"
-  zh: "抖动间隔"
-  sv: "Jint"
-  ru: "ИнтДжитр"
-  es: "JitInt"
-  de: "Jint"
-column_sprt:
-  en: "Sprt"
-  fr: "Psrc"
-  tr: "Sprt"
-  it: "Sprt"
-  zh: "源端"
-  sv: "Sprt"
-  ru: "Исх"
-  es: "Sprt"
-  de: "Sprt"
-column_dprt:
-  en: "Dprt"
-  fr: "Pdest"
-  tr: "Dprt"
-  it: "Dprt"
-  pt: "Dprt"
-  zh: "目标"
-  sv: "Dprt"
-  ru: "Назн"
-  es: "Dprt"
-  de: "Dprt"
-column_seq:
-  en: "Seq"
-  fr: "Seq"
-  tr: "Seq"
-  it: "Seq"
-  pt: "Seq"
-  zh: "序列"
-  sv: "Seq"
-  ru: "Посл"
-  es: "Seq"
-  de: "Seq"
-column_type:
-  en: "Type"
-  fr: "Type"
-  tr: "Type"
-  it: "Tipo"
-  pt: "Tipo"
-  zh: "类型"
-  sv: "Typ"
-  ru: "Тип"
-  es: "Tipo"
-  de: "Typ"
-column_code:
-  en: "Code"
-  fr: "Code"
-  tr: "Code"
-  it: "Codice"
-  pt: "Código"
-  zh: "代码"
-  sv: "Kod"
-  ru: "Код"
-  es: "Código"
-  de: "Code"
-column_nat:
-  en: "Nat"
-  fr: "Nat"
-  tr: "Nat"
-  it: "Nat"
-  pt: "Nat"
-  zh: "网络地址转换"
-  sv: "Nat"
-  ru: "Nat"
-  es: "Nat"
-  de: "Nat"
-column_fail:
-  en: "Fail"
-  fr: "Échec"
-  tr: "Başarısız"
-  it: "Falliti"
-  pt: "Falha"
-  zh: "失败"
-  sv: "Misslyckades"
-  ru: "Неуд"
-  es: "Falló"
-  de: "Fehlgeschlagen"
-column_floss:
-  en: "Floss"
-  fr: "Floss"
-  tr: "Floss"
-  it: "Floss"
-  pt: "Floss"
-  zh: "Floss"
-  sv: "Floss"
-  ru: "Floss"
-  es: "Floss"
-  de: "Floss"
-column_bloss:
-  en: "Bloss"
-  fr: "Bloss"
-  tr: "Bloss"
-  it: "Bloss"
-  pt: "Bloss"
-  zh: "Bloss"
-  sv: "Bloss"
-  ru: "Bloss"
-  es: "Bloss"
-  de: "Bloss"
-column_floss_pct:
-  en: "Floss%"
-  fr: "Floss%"
-  tr: "Floss%"
-  it: "Floss%"
-  pt: "Floss%"
-  zh: "Floss%"
-  sv: "Floss%"
-  ru: "Floss%"
-  es: "Floss%"
-  de: "Floss%"
\ No newline at end of file


Test patch:
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp.toml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp.toml
new file mode 100644
index 000000000..fcb1d85b9
--- /dev/null
+++ b/crates/trippy-core/tests/resources/simulation/ipv4_icmp.toml
@@ -0,0 +1,32 @@
+name = "IPv4/ICMP"
+target = "10.0.0.107"
+protocol = "Icmp"
+icmp_identifier = 1
+
+[[hops]]
+ttl = 1
+resp = { tag = "SingleHost", addr = "10.0.0.101", rtt_ms = 10 }
+
+[[hops]]
+ttl = 2
+resp = { tag = "SingleHost", addr = "10.0.0.102", rtt_ms = 20 }
+
+[[hops]]
+ttl = 3
+resp = { tag = "SingleHost", addr = "10.0.0.103", rtt_ms = 30 }
+
+[[hops]]
+ttl = 4
+resp = { tag = "SingleHost", addr = "10.0.0.104", rtt_ms = 40 }
+
+[[hops]]
+ttl = 5
+resp = { tag = "SingleHost", addr = "10.0.0.105", rtt_ms = 50 }
+
+[[hops]]
+ttl = 6
+resp = { tag = "SingleHost", addr = "10.0.0.106", rtt_ms = 60 }
+
+[[hops]]
+ttl = 7
+resp = { tag = "SingleHost", addr = "10.0.0.107", rtt_ms = 70 }
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp.yaml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp.yaml
deleted file mode 100644
index b37fa7c0e..000000000
--- a/crates/trippy-core/tests/resources/simulation/ipv4_icmp.yaml
+++ /dev/null
@@ -1,33 +0,0 @@
-name: IPv4/ICMP
-target: 10.0.0.107
-protocol: Icmp
-icmp_identifier: 1
-hops:
-  - ttl: 1
-    resp: !SingleHost
-      addr: 10.0.0.101
-      rtt_ms: 10
-  - ttl: 2
-    resp: !SingleHost
-      addr: 10.0.0.102
-      rtt_ms: 20
-  - ttl: 3
-    resp: !SingleHost
-      addr: 10.0.0.103
-      rtt_ms: 30
-  - ttl: 4
-    resp: !SingleHost
-      addr: 10.0.0.104
-      rtt_ms: 40
-  - ttl: 5
-    resp: !SingleHost
-      addr: 10.0.0.105
-      rtt_ms: 50
-  - ttl: 6
-    resp: !SingleHost
-      addr: 10.0.0.106
-      rtt_ms: 60
-  - ttl: 7
-    resp: !SingleHost
-      addr: 10.0.0.107
-      rtt_ms: 70
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_gaps.toml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_gaps.toml
new file mode 100644
index 000000000..9e5a44204
--- /dev/null
+++ b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_gaps.toml
@@ -0,0 +1,40 @@
+name = "IPv4/ICMP with 9 hops, 2 of which do not respond"
+target = "10.0.0.109"
+protocol = "Icmp"
+icmp_identifier = 3
+
+[[hops]]
+ttl = 1
+resp = { tag = "SingleHost", addr = "10.0.0.101", rtt_ms = 20 }
+
+[[hops]]
+ttl = 2
+resp.tag = "NoResponse"
+
+[[hops]]
+ttl = 3
+resp = { tag = "SingleHost", addr = "10.0.0.103", rtt_ms = 20 }
+
+[[hops]]
+ttl = 4
+resp = { tag = "SingleHost", addr = "10.0.0.104", rtt_ms = 20 }
+
+[[hops]]
+ttl = 5
+resp = { tag = "SingleHost", addr = "10.0.0.105", rtt_ms = 20 }
+
+[[hops]]
+ttl = 6
+resp = { tag = "SingleHost", addr = "10.0.0.106", rtt_ms = 20 }
+
+[[hops]]
+ttl = 7
+resp = { tag = "SingleHost", addr = "10.0.0.107", rtt_ms = 20 }
+
+[[hops]]
+ttl = 8
+resp.tag = "NoResponse"
+
+[[hops]]
+ttl = 9
+resp = { tag = "SingleHost", addr = "10.0.0.109", rtt_ms = 20 }
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_gaps.yaml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_gaps.yaml
deleted file mode 100644
index 28a34070b..000000000
--- a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_gaps.yaml
+++ /dev/null
@@ -1,37 +0,0 @@
-name: IPv4/ICMP with 9 hops, 2 of which do not respond
-target: 10.0.0.109
-protocol: Icmp
-icmp_identifier: 3
-hops:
-  - ttl: 1
-    resp: !SingleHost
-      addr: 10.0.0.101
-      rtt_ms: 10
-  - ttl: 2
-    resp: NoResponse
-  - ttl: 3
-    resp: !SingleHost
-      addr: 10.0.0.103
-      rtt_ms: 20
-  - ttl: 4
-    resp: !SingleHost
-      addr: 10.0.0.104
-      rtt_ms: 20
-  - ttl: 5
-    resp: !SingleHost
-      addr: 10.0.0.105
-      rtt_ms: 20
-  - ttl: 6
-    resp: !SingleHost
-      addr: 10.0.0.106
-      rtt_ms: 20
-  - ttl: 7
-    resp: !SingleHost
-      addr: 10.0.0.107
-      rtt_ms: 20
-  - ttl: 8
-    resp: NoResponse
-  - ttl: 9
-    resp: !SingleHost
-      addr: 10.0.0.109
-      rtt_ms: 20
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_min.toml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_min.toml
new file mode 100644
index 000000000..6a1967cec
--- /dev/null
+++ b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_min.toml
@@ -0,0 +1,17 @@
+name = "IPv4/ICMP with a minimum packet size"
+target = "10.0.0.103"
+protocol = "Icmp"
+icmp_identifier = 5
+packet_size = 28
+
+[[hops]]
+ttl = 1
+resp = { tag = "SingleHost", addr = "10.0.0.101", rtt_ms = 10 }
+
+[[hops]]
+ttl = 2
+resp = { tag = "SingleHost", addr = "10.0.0.102", rtt_ms = 20 }
+
+[[hops]]
+ttl = 3
+resp = { tag = "SingleHost", addr = "10.0.0.103", rtt_ms = 30 }
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_min.yaml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_min.yaml
deleted file mode 100644
index 8128905cc..000000000
--- a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_min.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-name: IPv4/ICMP with a minimum packet size
-target: 10.0.0.103
-protocol: Icmp
-icmp_identifier: 5
-packet_size: 28
-hops:
-  - ttl: 1
-    resp: !SingleHost
-      addr: 10.0.0.101
-      rtt_ms: 10
-  - ttl: 2
-    resp: !SingleHost
-      addr: 10.0.0.102
-      rtt_ms: 20
-  - ttl: 3
-    resp: !SingleHost
-      addr: 10.0.0.103
-      rtt_ms: 30
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_ooo.toml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_ooo.toml
new file mode 100644
index 000000000..55f72d0a2
--- /dev/null
+++ b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_ooo.toml
@@ -0,0 +1,25 @@
+name = "IPv4/ICMP with out of order responses"
+target = "10.0.0.105"
+protocol = "Icmp"
+icmp_identifier = 4
+grace_period = 300
+
+[[hops]]
+ttl = 1
+resp = { tag = "SingleHost", addr = "10.0.0.101", rtt_ms = 20 }
+
+[[hops]]
+ttl = 2
+resp = { tag = "SingleHost", addr = "10.0.0.102", rtt_ms = 15 }
+
+[[hops]]
+ttl = 3
+resp = { tag = "SingleHost", addr = "10.0.0.103", rtt_ms = 10 }
+
+[[hops]]
+ttl = 4
+resp = { tag = "SingleHost", addr = "10.0.0.104", rtt_ms = 5 }
+
+[[hops]]
+ttl = 5
+resp = { tag = "SingleHost", addr = "10.0.0.105", rtt_ms = 0 }
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_ooo.yaml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_ooo.yaml
deleted file mode 100644
index 126f7eac2..000000000
--- a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_ooo.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-name: IPv4/ICMP with out of order responses
-target: 10.0.0.105
-protocol: Icmp
-icmp_identifier: 4
-grace_period: 300
-hops:
-  - ttl: 1
-    resp: !SingleHost
-      addr: 10.0.0.101
-      rtt_ms: 20
-  - ttl: 2
-    resp: !SingleHost
-      addr: 10.0.0.102
-      rtt_ms: 15
-  - ttl: 3
-    resp: !SingleHost
-      addr: 10.0.0.103
-      rtt_ms: 10
-  - ttl: 4
-    resp: !SingleHost
-      addr: 10.0.0.104
-      rtt_ms: 5
-  - ttl: 5
-    resp: !SingleHost
-      addr: 10.0.0.105
-      rtt_ms: 0
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_pattern.toml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_pattern.toml
new file mode 100644
index 000000000..bdae74f9e
--- /dev/null
+++ b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_pattern.toml
@@ -0,0 +1,17 @@
+name = "IPv4/ICMP with an alternative payload pattern (0xFF)"
+target = "10.0.0.103"
+protocol = "Icmp"
+icmp_identifier = 6
+payload_pattern = 255
+
+[[hops]]
+ttl = 1
+resp = { tag = "SingleHost", addr = "10.0.0.101", rtt_ms = 10 }
+
+[[hops]]
+ttl = 2
+resp = { tag = "SingleHost", addr = "10.0.0.102", rtt_ms = 20 }
+
+[[hops]]
+ttl = 3
+resp = { tag = "SingleHost", addr = "10.0.0.103", rtt_ms = 30 }
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_pattern.yaml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_pattern.yaml
deleted file mode 100644
index 7738faaca..000000000
--- a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_pattern.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-name: IPv4/ICMP with an alternative payload pattern (0xFF)
-target: 10.0.0.103
-protocol: Icmp
-icmp_identifier: 6
-payload_pattern: 255
-hops:
-  - ttl: 1
-    resp: !SingleHost
-      addr: 10.0.0.101
-      rtt_ms: 10
-  - ttl: 2
-    resp: !SingleHost
-      addr: 10.0.0.102
-      rtt_ms: 20
-  - ttl: 3
-    resp: !SingleHost
-      addr: 10.0.0.103
-      rtt_ms: 30
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_quick.toml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_quick.toml
new file mode 100644
index 000000000..72261bb21
--- /dev/null
+++ b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_quick.toml
@@ -0,0 +1,47 @@
+name = "IPv4/ICMP wih min/max round duration 250ms and grace 50ms"
+target = "10.0.0.110"
+protocol = "Icmp"
+icmp_identifier = 7
+min_round_duration = 250
+max_round_duration = 250
+grace_period = 50
+
+[[hops]]
+ttl = 1
+resp = { tag = "SingleHost", addr = "10.0.0.101", rtt_ms = 1 }
+
+[[hops]]
+ttl = 2
+resp = { tag = "SingleHost", addr = "10.0.0.102", rtt_ms = 2 }
+
+[[hops]]
+ttl = 3
+resp = { tag = "SingleHost", addr = "10.0.0.103", rtt_ms = 3 }
+
+[[hops]]
+ttl = 4
+resp = { tag = "SingleHost", addr = "10.0.0.104", rtt_ms = 4 }
+
+[[hops]]
+ttl = 5
+resp = { tag = "SingleHost", addr = "10.0.0.105", rtt_ms = 5 }
+
+[[hops]]
+ttl = 6
+resp = { tag = "SingleHost", addr = "10.0.0.106", rtt_ms = 6 }
+
+[[hops]]
+ttl = 7
+resp = { tag = "SingleHost", addr = "10.0.0.107", rtt_ms = 7 }
+
+[[hops]]
+ttl = 8
+resp = { tag = "SingleHost", addr = "10.0.0.108", rtt_ms = 8 }
+
+[[hops]]
+ttl = 9
+resp = { tag = "SingleHost", addr = "10.0.0.109", rtt_ms = 9 }
+
+[[hops]]
+ttl = 10
+resp = { tag = "SingleHost", addr = "10.0.0.110", rtt_ms = 10 }
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_quick.yaml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_quick.yaml
deleted file mode 100644
index 79d53dab1..000000000
--- a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_quick.yaml
+++ /dev/null
@@ -1,48 +0,0 @@
-name: IPv4/ICMP wih min/max round duration 250ms and grace 50ms
-target: 10.0.0.110
-protocol: Icmp
-icmp_identifier: 7
-min_round_duration: 250
-max_round_duration: 250
-grace_period: 50
-hops:
-  - ttl: 1
-    resp: !SingleHost
-      addr: 10.0.0.101
-      rtt_ms: 1
-  - ttl: 2
-    resp: !SingleHost
-      addr: 10.0.0.102
-      rtt_ms: 2
-  - ttl: 3
-    resp: !SingleHost
-      addr: 10.0.0.103
-      rtt_ms: 3
-  - ttl: 4
-    resp: !SingleHost
-      addr: 10.0.0.104
-      rtt_ms: 4
-  - ttl: 5
-    resp: !SingleHost
-      addr: 10.0.0.105
-      rtt_ms: 5
-  - ttl: 6
-    resp: !SingleHost
-      addr: 10.0.0.106
-      rtt_ms: 6
-  - ttl: 7
-    resp: !SingleHost
-      addr: 10.0.0.107
-      rtt_ms: 7
-  - ttl: 8
-    resp: !SingleHost
-      addr: 10.0.0.108
-      rtt_ms: 8
-  - ttl: 9
-    resp: !SingleHost
-      addr: 10.0.0.109
-      rtt_ms: 9
-  - ttl: 10
-    resp: !SingleHost
-      addr: 10.0.0.110
-      rtt_ms: 10
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_wrap.toml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_wrap.toml
new file mode 100644
index 000000000..f5211d5ff
--- /dev/null
+++ b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_wrap.toml
@@ -0,0 +1,126 @@
+name = "IPv4/ICMP wrap sequence"
+target = "10.0.0.130"
+rounds = 20
+protocol = "Icmp"
+icmp_identifier = 8
+initial_sequence = 64511
+
+[[hops]]
+ttl = 1
+resp = { tag = "SingleHost", addr = "10.0.0.101", rtt_ms = 0 }
+
+[[hops]]
+ttl = 2
+resp = { tag = "SingleHost", addr = "10.0.0.102", rtt_ms = 0 }
+
+[[hops]]
+ttl = 3
+resp = { tag = "SingleHost", addr = "10.0.0.103", rtt_ms = 0 }
+
+[[hops]]
+ttl = 4
+resp = { tag = "SingleHost", addr = "10.0.0.104", rtt_ms = 0 }
+
+[[hops]]
+ttl = 5
+resp = { tag = "SingleHost", addr = "10.0.0.105", rtt_ms = 0 }
+
+[[hops]]
+ttl = 6
+resp = { tag = "SingleHost", addr = "10.0.0.106", rtt_ms = 0 }
+
+[[hops]]
+ttl = 7
+resp = { tag = "SingleHost", addr = "10.0.0.107", rtt_ms = 0 }
+
+[[hops]]
+ttl = 8
+resp = { tag = "SingleHost", addr = "10.0.0.108", rtt_ms = 0 }
+
+[[hops]]
+ttl = 9
+resp = { tag = "SingleHost", addr = "10.0.0.109", rtt_ms = 0 }
+
+[[hops]]
+ttl = 10
+resp = { tag = "SingleHost", addr = "10.0.0.110", rtt_ms = 0 }
+
+[[hops]]
+ttl = 11
+resp = { tag = "SingleHost", addr = "10.0.0.111", rtt_ms = 0 }
+
+[[hops]]
+ttl = 12
+resp = { tag = "SingleHost", addr = "10.0.0.112", rtt_ms = 0 }
+
+[[hops]]
+ttl = 13
+resp = { tag = "SingleHost", addr = "10.0.0.113", rtt_ms = 0 }
+
+[[hops]]
+ttl = 14
+resp = { tag = "SingleHost", addr = "10.0.0.114", rtt_ms = 0 }
+
+[[hops]]
+ttl = 15
+resp = { tag = "SingleHost", addr = "10.0.0.115", rtt_ms = 0 }
+
+[[hops]]
+ttl = 16
+resp = { tag = "SingleHost", addr = "10.0.0.116", rtt_ms = 0 }
+
+[[hops]]
+ttl = 17
+resp = { tag = "SingleHost", addr = "10.0.0.117", rtt_ms = 0 }
+
+[[hops]]
+ttl = 18
+resp = { tag = "SingleHost", addr = "10.0.0.118", rtt_ms = 0 }
+
+[[hops]]
+ttl = 19
+resp = { tag = "SingleHost", addr = "10.0.0.119", rtt_ms = 0 }
+
+[[hops]]
+ttl = 20
+resp = { tag = "SingleHost", addr = "10.0.0.120", rtt_ms = 0 }
+
+[[hops]]
+ttl = 21
+resp = { tag = "SingleHost", addr = "10.0.0.121", rtt_ms = 0 }
+
+[[hops]]
+ttl = 22
+resp = { tag = "SingleHost", addr = "10.0.0.122", rtt_ms = 0 }
+
+[[hops]]
+ttl = 23
+resp = { tag = "SingleHost", addr = "10.0.0.123", rtt_ms = 0 }
+
+[[hops]]
+ttl = 24
+resp = { tag = "SingleHost", addr = "10.0.0.124", rtt_ms = 0 }
+
+[[hops]]
+ttl = 25
+resp = { tag = "SingleHost", addr = "10.0.0.125", rtt_ms = 0 }
+
+[[hops]]
+ttl = 26
+resp = { tag = "SingleHost", addr = "10.0.0.126", rtt_ms = 0 }
+
+[[hops]]
+ttl = 27
+resp = { tag = "SingleHost", addr = "10.0.0.127", rtt_ms = 0 }
+
+[[hops]]
+ttl = 28
+resp = { tag = "SingleHost", addr = "10.0.0.128", rtt_ms = 0 }
+
+[[hops]]
+ttl = 29
+resp = { tag = "SingleHost", addr = "10.0.0.129", rtt_ms = 0 }
+
+[[hops]]
+ttl = 30
+resp = { tag = "SingleHost", addr = "10.0.0.130", rtt_ms = 0 }
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_wrap.yaml b/crates/trippy-core/tests/resources/simulation/ipv4_icmp_wrap.yaml
deleted file mode 100644
index ff7174902..000000000
--- a/crates/trippy-core/tests/resources/simulation/ipv4_icmp_wrap.yaml
+++ /dev/null
@@ -1,127 +0,0 @@
-name: IPv4/ICMP wrap sequence
-target: 10.0.0.130
-rounds: 20
-protocol: Icmp
-icmp_identifier: 8
-initial_sequence: 64511
-hops:
-  - ttl: 1
-    resp: !SingleHost
-      addr: 10.0.0.101
-      rtt_ms: 0
-  - ttl: 2
-    resp: !SingleHost
-      addr: 10.0.0.102
-      rtt_ms: 0
-  - ttl: 3
-    resp: !SingleHost
-      addr: 10.0.0.103
-      rtt_ms: 0
-  - ttl: 4
-    resp: !SingleHost
-      addr: 10.0.0.104
-      rtt_ms: 0
-  - ttl: 5
-    resp: !SingleHost
-      addr: 10.0.0.105
-      rtt_ms: 0
-  - ttl: 6
-    resp: !SingleHost
-      addr: 10.0.0.106
-      rtt_ms: 0
-  - ttl: 7
-    resp: !SingleHost
-      addr: 10.0.0.107
-      rtt_ms: 0
-  - ttl: 8
-    resp: !SingleHost
-      addr: 10.0.0.108
-      rtt_ms: 0
-  - ttl: 9
-    resp: !SingleHost
-      addr: 10.0.0.109
-      rtt_ms: 0
-  - ttl: 10
-    resp: !SingleHost
-      addr: 10.0.0.110
-      rtt_ms: 0
-  - ttl: 11
-    resp: !SingleHost
-      addr: 10.0.0.111
-      rtt_ms: 0
-  - ttl: 12
-    resp: !SingleHost
-      addr: 10.0.0.112
-      rtt_ms: 0
-  - ttl: 13
-    resp: !SingleHost
-      addr: 10.0.0.113
-      rtt_ms: 0
-  - ttl: 14
-    resp: !SingleHost
-      addr: 10.0.0.114
-      rtt_ms: 0
-  - ttl: 15
-    resp: !SingleHost
-      addr: 10.0.0.115
-      rtt_ms: 0
-  - ttl: 16
-    resp: !SingleHost
-      addr: 10.0.0.116
-      rtt_ms: 0
-  - ttl: 17
-    resp: !SingleHost
-      addr: 10.0.0.117
-      rtt_ms: 0
-  - ttl: 18
-    resp: !SingleHost
-      addr: 10.0.0.118
-      rtt_ms: 0
-  - ttl: 19
-    resp: !SingleHost
-      addr: 10.0.0.119
-      rtt_ms: 0
-  - ttl: 20
-    resp: !SingleHost
-      addr: 10.0.0.120
-      rtt_ms: 0
-  - ttl: 21
-    resp: !SingleHost
-      addr: 10.0.0.121
-      rtt_ms: 0
-  - ttl: 22
-    resp: !SingleHost
-      addr: 10.0.0.122
-      rtt_ms: 0
-  - ttl: 23
-    resp: !SingleHost
-      addr: 10.0.0.123
-      rtt_ms: 0
-  - ttl: 24
-    resp: !SingleHost
-      addr: 10.0.0.124
-      rtt_ms: 0
-  - ttl: 25
-    resp: !SingleHost
-      addr: 10.0.0.125
-      rtt_ms: 0
-  - ttl: 26
-    resp: !SingleHost
-      addr: 10.0.0.126
-      rtt_ms: 0
-  - ttl: 27
-    resp: !SingleHost
-      addr: 10.0.0.127
-      rtt_ms: 0
-  - ttl: 28
-    resp: !SingleHost
-      addr: 10.0.0.128
-      rtt_ms: 0
-  - ttl: 29
-    resp: !SingleHost
-      addr: 10.0.0.129
-      rtt_ms: 0
-  - ttl: 30
-    resp: !SingleHost
-      addr: 10.0.0.130
-      rtt_ms: 0
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_tcp_fixed_dest.toml b/crates/trippy-core/tests/resources/simulation/ipv4_tcp_fixed_dest.toml
new file mode 100644
index 000000000..805992af0
--- /dev/null
+++ b/crates/trippy-core/tests/resources/simulation/ipv4_tcp_fixed_dest.toml
@@ -0,0 +1,16 @@
+name = "IPv4/TCP with a fixed dest port"
+target = "10.0.0.103"
+protocol = "Tcp"
+port_direction = { tag = "FixedDest", value = 80 }
+
+[[hops]]
+ttl = 1
+resp = { tag = "SingleHost", addr = "10.0.0.101", rtt_ms = 10 }
+
+[[hops]]
+ttl = 2
+resp = { tag = "SingleHost", addr = "10.0.0.102", rtt_ms = 20 }
+
+[[hops]]
+ttl = 3
+resp = { tag = "SingleHost", addr = "10.0.0.103", rtt_ms = 20 }
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_tcp_fixed_dest.yaml b/crates/trippy-core/tests/resources/simulation/ipv4_tcp_fixed_dest.yaml
deleted file mode 100644
index ab10efa67..000000000
--- a/crates/trippy-core/tests/resources/simulation/ipv4_tcp_fixed_dest.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-name: IPv4/TCP with a fixed dest port
-target: 10.0.0.103
-protocol: Tcp
-port_direction: !FixedDest 80
-hops:
-  - ttl: 1
-    resp: !SingleHost
-      addr: 10.0.0.101
-      rtt_ms: 10
-  - ttl: 2
-    resp: !SingleHost
-      addr: 10.0.0.102
-      rtt_ms: 20
-  - ttl: 3
-    resp: !SingleHost
-      addr: 10.0.0.103
-      rtt_ms: 20
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_fixed_dest.toml b/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_fixed_dest.toml
new file mode 100644
index 000000000..e1fe5809d
--- /dev/null
+++ b/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_fixed_dest.toml
@@ -0,0 +1,17 @@
+name = "IPv4/UDP classic with a fixed dest port"
+target = "10.0.0.103"
+protocol = "Udp"
+port_direction = { tag = "FixedDest", value = 33434 }
+multipath_strategy = "Classic"
+
+[[hops]]
+ttl = 1
+resp = { tag = "SingleHost", addr = "10.0.0.101", rtt_ms = 10 }
+
+[[hops]]
+ttl = 2
+resp = { tag = "SingleHost", addr = "10.0.0.102", rtt_ms = 20 }
+
+[[hops]]
+ttl = 3
+resp = { tag = "SingleHost", addr = "10.0.0.103", rtt_ms = 20 }
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_fixed_dest.yaml b/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_fixed_dest.yaml
deleted file mode 100644
index 046df810c..000000000
--- a/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_fixed_dest.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-name: IPv4/UDP classic with a fixed dest port
-target: 10.0.0.103
-protocol: Udp
-port_direction: !FixedDest 33434
-multipath_strategy: Classic
-hops:
-  - ttl: 1
-    resp: !SingleHost
-      addr: 10.0.0.101
-      rtt_ms: 10
-  - ttl: 2
-    resp: !SingleHost
-      addr: 10.0.0.102
-      rtt_ms: 20
-  - ttl: 3
-    resp: !SingleHost
-      addr: 10.0.0.103
-      rtt_ms: 20
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_fixed_src.toml b/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_fixed_src.toml
new file mode 100644
index 000000000..9ff2d806c
--- /dev/null
+++ b/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_fixed_src.toml
@@ -0,0 +1,17 @@
+name = "IPv4/UDP classic with a fixed src port"
+target = "10.0.0.103"
+protocol = "Udp"
+port_direction = { tag = "FixedSrc", value = 5000 }
+multipath_strategy = "Classic"
+
+[[hops]]
+ttl = 1
+resp = { tag = "SingleHost", addr = "10.0.0.101", rtt_ms = 10 }
+
+[[hops]]
+ttl = 2
+resp = { tag = "SingleHost", addr = "10.0.0.102", rtt_ms = 20 }
+
+[[hops]]
+ttl = 3
+resp = { tag = "SingleHost", addr = "10.0.0.103", rtt_ms = 20 }
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_fixed_src.yaml b/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_fixed_src.yaml
deleted file mode 100644
index fa4da1b23..000000000
--- a/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_fixed_src.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-name: IPv4/UDP classic with a fixed src port
-target: 10.0.0.103
-protocol: Udp
-port_direction: !FixedSrc 5000
-multipath_strategy: Classic
-hops:
-  - ttl: 1
-    resp: !SingleHost
-      addr: 10.0.0.101
-      rtt_ms: 10
-  - ttl: 2
-    resp: !SingleHost
-      addr: 10.0.0.102
-      rtt_ms: 20
-  - ttl: 3
-    resp: !SingleHost
-      addr: 10.0.0.103
-      rtt_ms: 20
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_unprivileged.toml b/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_unprivileged.toml
new file mode 100644
index 000000000..67d8312f0
--- /dev/null
+++ b/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_unprivileged.toml
@@ -0,0 +1,18 @@
+name = "IPv4/UDP classic unprivileged"
+privilege_mode = "Unprivileged"
+target = "10.0.0.103"
+protocol = "Udp"
+port_direction = { tag = "FixedDest", value = 33434 }
+multipath_strategy = "Classic"
+
+[[hops]]
+ttl = 1
+resp = { tag = "SingleHost", addr = "10.0.0.101", rtt_ms = 10 }
+
+[[hops]]
+ttl = 2
+resp = { tag = "SingleHost", addr = "10.0.0.102", rtt_ms = 20 }
+
+[[hops]]
+ttl = 3
+resp = { tag = "SingleHost", addr = "10.0.0.103", rtt_ms = 20 }
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_unprivileged.yaml b/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_unprivileged.yaml
deleted file mode 100644
index 16d3ba3f0..000000000
--- a/crates/trippy-core/tests/resources/simulation/ipv4_udp_classic_unprivileged.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-name: IPv4/UDP classic unprivileged
-privilege_mode: Unprivileged
-target: 10.0.0.103
-protocol: Udp
-port_direction: !FixedDest 33434
-multipath_strategy: Classic
-hops:
-  - ttl: 1
-    resp: !SingleHost
-      addr: 10.0.0.101
-      rtt_ms: 10
-  - ttl: 2
-    resp: !SingleHost
-      addr: 10.0.0.102
-      rtt_ms: 20
-  - ttl: 3
-    resp: !SingleHost
-      addr: 10.0.0.103
-      rtt_ms: 20
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_udp_dublin_fixed_both.toml b/crates/trippy-core/tests/resources/simulation/ipv4_udp_dublin_fixed_both.toml
new file mode 100644
index 000000000..efc594bb5
--- /dev/null
+++ b/crates/trippy-core/tests/resources/simulation/ipv4_udp_dublin_fixed_both.toml
@@ -0,0 +1,17 @@
+name = "IPv4/UDP Dublin with a fixed src and dest port"
+target = "10.0.0.103"
+protocol = "Udp"
+multipath_strategy = "Dublin"
+port_direction = { tag = "FixedBoth", value = { src = 5000, dest = 33434 } }
+
+[[hops]]
+ttl = 1
+resp = { tag = "SingleHost", addr = "10.0.0.101", rtt_ms = 10 }
+
+[[hops]]
+ttl = 2
+resp = { tag = "SingleHost", addr = "10.0.0.102", rtt_ms = 20 }
+
+[[hops]]
+ttl = 3
+resp = { tag = "SingleHost", addr = "10.0.0.103", rtt_ms = 20 }
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_udp_dublin_fixed_both.yaml b/crates/trippy-core/tests/resources/simulation/ipv4_udp_dublin_fixed_both.yaml
deleted file mode 100644
index 17ab3b827..000000000
--- a/crates/trippy-core/tests/resources/simulation/ipv4_udp_dublin_fixed_both.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-name: IPv4/UDP Dublin with a fixed src and dest port
-target: 10.0.0.103
-protocol: Udp
-port_direction: !FixedBoth
-  src: 5000
-  dest: 33434
-multipath_strategy: Dublin
-hops:
-  - ttl: 1
-    resp: !SingleHost
-      addr: 10.0.0.101
-      rtt_ms: 10
-  - ttl: 2
-    resp: !SingleHost
-      addr: 10.0.0.102
-      rtt_ms: 20
-  - ttl: 3
-    resp: !SingleHost
-      addr: 10.0.0.103
-      rtt_ms: 20
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_udp_paris_fixed_both.toml b/crates/trippy-core/tests/resources/simulation/ipv4_udp_paris_fixed_both.toml
new file mode 100644
index 000000000..e5ac88144
--- /dev/null
+++ b/crates/trippy-core/tests/resources/simulation/ipv4_udp_paris_fixed_both.toml
@@ -0,0 +1,17 @@
+name = "IPv4/UDP Paris with a fixed src and dest port"
+target = "10.0.0.103"
+protocol = "Udp"
+multipath_strategy = "Paris"
+port_direction = { tag = "FixedBoth", value = { src = 5000, dest = 33434 } }
+
+[[hops]]
+ttl = 1
+resp = { tag = "SingleHost", addr = "10.0.0.101", rtt_ms = 10 }
+
+[[hops]]
+ttl = 2
+resp = { tag = "SingleHost", addr = "10.0.0.102", rtt_ms = 20 }
+
+[[hops]]
+ttl = 3
+resp = { tag = "SingleHost", addr = "10.0.0.103", rtt_ms = 20 }
diff --git a/crates/trippy-core/tests/resources/simulation/ipv4_udp_paris_fixed_both.yaml b/crates/trippy-core/tests/resources/simulation/ipv4_udp_paris_fixed_both.yaml
deleted file mode 100644
index 99b65a86d..000000000
--- a/crates/trippy-core/tests/resources/simulation/ipv4_udp_paris_fixed_both.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-name: IPv4/UDP Paris with a fixed src and dest port
-target: 10.0.0.103
-protocol: Udp
-port_direction: !FixedBoth
-  src: 5000
-  dest: 33434
-multipath_strategy: Paris
-hops:
-  - ttl: 1
-    resp: !SingleHost
-      addr: 10.0.0.101
-      rtt_ms: 10
-  - ttl: 2
-    resp: !SingleHost
-      addr: 10.0.0.102
-      rtt_ms: 20
-  - ttl: 3
-    resp: !SingleHost
-      addr: 10.0.0.103
-      rtt_ms: 20
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/state/all_status.toml b/crates/trippy-core/tests/resources/state/all_status.toml
new file mode 100644
index 000000000..2af891cf9
--- /dev/null
+++ b/crates/trippy-core/tests/resources/state/all_status.toml
@@ -0,0 +1,36 @@
+largest_ttl = 1
+
+[[rounds]]
+probes = [
+    "1 A 300 10.1.0.2 0 12340 80 0 0",
+]
+
+[[rounds]]
+probes = [
+    "1 C 700 10.1.0.2 0 12340 80 0 0",
+]
+
+[[rounds]]
+probes = [
+    "1 N 300 10.1.0.2 0 12340 80 0 0",
+]
+
+[[rounds]]
+probes = [
+    "1 S 300 10.1.0.2 0 12340 80 0 0",
+]
+
+[[expected.hops]]
+ttl = 1
+total_sent = 2
+total_recv = 1
+loss_pct = 50
+best_ms = 700
+worst_ms = 700
+avg_ms = 700
+samples = [700.0, 0.0]
+last_ms = 700
+last_sequence = 0
+last_src = 12340
+last_dest = 80
+addrs = { "10.1.0.2" = 1 }
diff --git a/crates/trippy-core/tests/resources/state/all_status.yaml b/crates/trippy-core/tests/resources/state/all_status.yaml
deleted file mode 100644
index d6140684b..000000000
--- a/crates/trippy-core/tests/resources/state/all_status.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-largest_ttl: 1
-rounds:
-  - probes:
-      - 1 A 300 10.1.0.2 0 12340 80 0 0
-  - probes:
-      - 1 C 700 10.1.0.2 0 12340 80 0 0
-  - probes:
-      - 1 N 300 10.1.0.2 0 12340 80 0 0
-  - probes:
-      - 1 S 300 10.1.0.2 0 12340 80 0 0
-expected:
-  hops:
-    - ttl: 1
-      total_sent: 2
-      total_recv: 1
-      loss_pct: 50
-      best_ms: 700
-      worst_ms: 700
-      avg_ms: 700
-      addrs:
-        10.1.0.2: 1
-      samples: [700.0, 0.0]
-      last_ms: 700
-      last_sequence: 0
-      last_src: 12340
-      last_dest: 80
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/state/floss_bloss.toml b/crates/trippy-core/tests/resources/state/floss_bloss.toml
new file mode 100644
index 000000000..b98031c5b
--- /dev/null
+++ b/crates/trippy-core/tests/resources/state/floss_bloss.toml
@@ -0,0 +1,43 @@
+largest_ttl = 3
+
+[[rounds]]
+probes = [
+    "1 C 333 10.1.0.1 0 12340 80 0 0",
+    "2 C 777 10.1.0.2 1 12340 80 0 0",
+    "3 C 778 10.1.0.3 2 12340 80 0 0",
+]
+
+[[rounds]]
+probes = [
+    "1 C 333 10.1.0.1 3 12340 80 0 0",
+    "2 A 777 10.1.0.2 4 12340 80 0 0",
+    "3 A 778 10.1.0.3 5 12340 80 0 0",
+]
+
+[[rounds]]
+probes = [
+    "1 C 333 10.1.0.1 6 12340 80 0 0",
+    "2 C 777 10.1.0.2 7 12340 80 0 0",
+    "3 C 778 10.1.0.3 8 12340 80 0 0",
+]
+
+[[expected.hops]]
+ttl = 1
+total_sent = 3
+total_recv = 3
+total_forward_loss = 0
+total_backward_loss = 0
+
+[[expected.hops]]
+ttl = 2
+total_sent = 3
+total_recv = 2
+total_forward_loss = 1
+total_backward_loss = 0
+
+[[expected.hops]]
+ttl = 3
+total_sent = 3
+total_recv = 2
+total_forward_loss = 0
+total_backward_loss = 1
diff --git a/crates/trippy-core/tests/resources/state/floss_bloss.yaml b/crates/trippy-core/tests/resources/state/floss_bloss.yaml
deleted file mode 100644
index 91dbf87e0..000000000
--- a/crates/trippy-core/tests/resources/state/floss_bloss.yaml
+++ /dev/null
@@ -1,32 +0,0 @@
-# Test forward and backward loss.
-largest_ttl: 3
-rounds:
-  - probes:
-      - 1 C 333 10.1.0.1 0 12340 80 0 0
-      - 2 C 777 10.1.0.2 1 12340 80 0 0
-      - 3 C 778 10.1.0.3 2 12340 80 0 0
-  - probes:
-      - 1 C 333 10.1.0.1 3 12340 80 0 0
-      - 2 A 777 10.1.0.2 4 12340 80 0 0
-      - 3 A 778 10.1.0.3 5 12340 80 0 0
-  - probes:
-      - 1 C 333 10.1.0.1 6 12340 80 0 0
-      - 2 C 777 10.1.0.2 7 12340 80 0 0
-      - 3 C 778 10.1.0.3 8 12340 80 0 0
-expected:
-  hops:
-    - ttl: 1
-      total_sent: 3
-      total_recv: 3
-      total_forward_loss: 0
-      total_backward_loss: 0
-    - ttl: 2
-      total_sent: 3
-      total_recv: 2
-      total_forward_loss: 1
-      total_backward_loss: 0
-    - ttl: 3
-      total_sent: 3
-      total_recv: 2
-      total_forward_loss: 0
-      total_backward_loss: 1
diff --git a/crates/trippy-core/tests/resources/state/full_completed.toml b/crates/trippy-core/tests/resources/state/full_completed.toml
new file mode 100644
index 000000000..fc3c42b3f
--- /dev/null
+++ b/crates/trippy-core/tests/resources/state/full_completed.toml
@@ -0,0 +1,82 @@
+largest_ttl = 3
+
+[[rounds]]
+probes = [
+    "1 C 333 10.1.0.1 0 12340 80 0 0",
+    "2 C 777 10.1.0.2 1 12340 80 0 0",
+    "3 C 778 10.1.0.3 2 12340 80 0 0",
+]
+
+[[rounds]]
+probes = [
+    "1 C 123 10.1.0.1 3 12340 80 0 0",
+    "2 C 788 10.1.0.2 4 12340 80 0 0",
+    "3 C 789 10.1.0.3 5 12340 80 0 0",
+]
+
+[[rounds]]
+probes = [
+    "1 C 123 10.1.0.1 6 12340 80 0 0",
+    "2 C 780 10.1.0.2 7 12340 80 0 0",
+    "3 C 781 10.1.0.3 8 12340 80 0 0",
+]
+
+[[expected.hops]]
+ttl = 1
+total_sent = 3
+total_recv = 3
+loss_pct = 0
+best_ms = 123
+worst_ms = 333
+avg_ms = 193
+jitter = 0
+javg = 181.0
+jinta = 488.642578125
+jmax = 333
+last_nat_status = "no_nat"
+samples = [123, 123, 333]
+last_ms = 123
+last_sequence = 6
+last_src = 12340
+last_dest = 80
+addrs = { "10.1.0.1" = 3 }
+
+[[expected.hops]]
+ttl = 2
+total_sent = 3
+total_recv = 3
+loss_pct = 0
+best_ms = 777
+worst_ms = 788
+avg_ms = 781.6666666666665
+jitter = 8
+javg = 265.33333333333337
+jinta = 699.814453125
+jmax = 777.0
+last_nat_status = "no_nat"
+samples = [780, 788, 777]
+last_ms = 780
+last_sequence = 7
+last_src = 12340
+last_dest = 80
+addrs = { "10.1.0.2" = 3 }
+
+[[expected.hops]]
+ttl = 3
+total_sent = 3
+total_recv = 3
+loss_pct = 0
+best_ms = 778
+worst_ms = 789
+avg_ms = 782.6666666666666
+jitter = 8
+javg = 265.66666666666663
+jinta = 700.693359375
+jmax = 778.0
+last_nat_status = "no_nat"
+samples = [781, 789, 778]
+last_ms = 781
+last_sequence = 8
+last_src = 12340
+last_dest = 80
+addrs = { "10.1.0.3" = 3 }
diff --git a/crates/trippy-core/tests/resources/state/full_completed.yaml b/crates/trippy-core/tests/resources/state/full_completed.yaml
deleted file mode 100644
index 2e12ace40..000000000
--- a/crates/trippy-core/tests/resources/state/full_completed.yaml
+++ /dev/null
@@ -1,73 +0,0 @@
-largest_ttl: 3
-rounds:
-  - probes:
-      - 1 C 333 10.1.0.1 0 12340 80 0 0
-      - 2 C 777 10.1.0.2 1 12340 80 0 0
-      - 3 C 778 10.1.0.3 2 12340 80 0 0
-  - probes:
-      - 1 C 123 10.1.0.1 3 12340 80 0 0
-      - 2 C 788 10.1.0.2 4 12340 80 0 0
-      - 3 C 789 10.1.0.3 5 12340 80 0 0
-  - probes:
-      - 1 C 123 10.1.0.1 6 12340 80 0 0
-      - 2 C 780 10.1.0.2 7 12340 80 0 0
-      - 3 C 781 10.1.0.3 8 12340 80 0 0
-expected:
-  hops:
-    - ttl: 1
-      total_sent: 3
-      total_recv: 3
-      loss_pct: 0
-      best_ms: 123
-      worst_ms: 333
-      avg_ms: 193
-      jitter: 0
-      javg: 181.0
-      jinta: 488.642578125
-      jmax: 333
-      last_nat_status: no_nat
-      addrs:
-        10.1.0.1: 3
-      samples: [123, 123, 333]
-      last_ms: 123
-      last_sequence: 6
-      last_src: 12340
-      last_dest: 80 
-    - ttl: 2
-      total_sent: 3
-      total_recv: 3
-      loss_pct: 0
-      best_ms: 777
-      worst_ms: 788
-      avg_ms: 781.6666666666665
-      jitter: 8
-      javg: 265.33333333333337
-      jinta: 699.814453125
-      jmax: 777.0
-      last_nat_status: no_nat
-      addrs:
-        10.1.0.2: 3
-      samples: [780, 788, 777]
-      last_ms: 780
-      last_sequence: 7
-      last_src: 12340
-      last_dest: 80 
-    - ttl: 3
-      total_sent: 3
-      total_recv: 3
-      loss_pct: 0
-      best_ms: 778
-      worst_ms: 789
-      avg_ms: 782.6666666666666
-      jitter: 8
-      javg: 265.66666666666663
-      jinta: 700.693359375
-      jmax: 778.0
-      last_nat_status: no_nat
-      addrs:
-        10.1.0.3: 3
-      samples: [781, 789, 778]
-      last_ms: 781
-      last_sequence: 8
-      last_src: 12340
-      last_dest: 80 
diff --git a/crates/trippy-core/tests/resources/state/full_mixed.toml b/crates/trippy-core/tests/resources/state/full_mixed.toml
new file mode 100644
index 000000000..aeb65316f
--- /dev/null
+++ b/crates/trippy-core/tests/resources/state/full_mixed.toml
@@ -0,0 +1,69 @@
+largest_ttl = 3
+
+[[rounds]]
+probes = [
+    "1 C 10 10.0.0.1 0 12345 80 0 0",
+    "2 A 12 10.0.0.2 1 12345 80 0 0",
+    "3 C 11 10.0.0.3 2 12345 80 0 0",
+]
+
+[[rounds]]
+probes = [
+    "1 C 101 10.0.0.1 3 12345 80 0 0",
+    "2 A 121 10.0.0.2 4 12345 80 0 0",
+    "3 C 111 10.0.0.4 5 12345 80 0 0",
+]
+
+[[expected.hops]]
+ttl = 1
+total_sent = 2
+total_recv = 2
+loss_pct = 0
+best_ms = 10
+worst_ms = 101
+avg_ms = 55.5
+jitter = 91
+javg = 50.5
+jinta = 99.40625
+jmax = 91
+last_nat_status = "no_nat"
+samples = [101, 10]
+last_ms = 101
+last_src = 12345
+last_dest = 80
+last_sequence = 3
+addrs = { "10.0.0.1" = 2 }
+
+[[expected.hops]]
+ttl = 2
+total_sent = 2
+total_recv = 0
+loss_pct = 100
+avg_ms = 0
+javg = 0
+jinta = 0
+last_nat_status = "none"
+samples = [0, 0]
+last_src = 12345
+last_dest = 80
+last_sequence = 4
+
+[[expected.hops]]
+ttl = 3
+total_sent = 2
+total_recv = 2
+loss_pct = 0
+best_ms = 11
+worst_ms = 111
+avg_ms = 61
+jitter = 100
+javg = 55.5
+jinta = 109.34375
+jmax = 100
+last_nat_status = "no_nat"
+samples = [111, 11]
+last_ms = 111
+last_src = 12345
+last_dest = 80
+last_sequence = 5
+addrs = { "10.0.0.3" = 1, "10.0.0.4" = 1 }
diff --git a/crates/trippy-core/tests/resources/state/full_mixed.yaml b/crates/trippy-core/tests/resources/state/full_mixed.yaml
deleted file mode 100644
index b4ff16805..000000000
--- a/crates/trippy-core/tests/resources/state/full_mixed.yaml
+++ /dev/null
@@ -1,64 +0,0 @@
-largest_ttl: 3
-rounds:
-  - probes:
-      - 1 C 10 10.0.0.1 0 12345 80 0 0
-      - 2 A 12 10.0.0.2 1 12345 80 0 0
-      - 3 C 11 10.0.0.3 2 12345 80 0 0
-  - probes:
-      - 1 C 101 10.0.0.1 3 12345 80 0 0
-      - 2 A 121 10.0.0.2 4 12345 80 0 0
-      - 3 C 111 10.0.0.4 5 12345 80 0 0
-expected:
-  hops:
-    - ttl: 1
-      total_sent: 2
-      total_recv: 2
-      loss_pct: 0
-      best_ms: 10
-      worst_ms: 101
-      avg_ms: 55.5
-      jitter: 91
-      javg: 50.5
-      jinta: 99.40625
-      jmax: 91
-      last_nat_status: no_nat
-      addrs:
-        10.0.0.1: 2
-      samples: [101, 10]
-      last_ms: 101
-      last_src: 12345
-      last_dest: 80
-      last_sequence: 3
-    - ttl: 2
-      total_sent: 2
-      total_recv: 0
-      loss_pct: 100
-      avg_ms: 0
-      javg: 0
-      jinta: 0
-      last_nat_status: none
-      addrs:
-      samples: [0, 0]
-      last_src: 12345
-      last_dest: 80
-      last_sequence: 4
-    - ttl: 3
-      total_sent: 2
-      total_recv: 2
-      loss_pct: 0
-      best_ms: 11
-      worst_ms: 111
-      avg_ms: 61
-      jitter: 100
-      javg:  55.5
-      jinta: 109.34375
-      jmax: 100
-      last_nat_status: no_nat
-      addrs:
-        10.0.0.3: 1
-        10.0.0.4: 1
-      samples: [111, 11]
-      last_ms: 111
-      last_src: 12345
-      last_dest: 80
-      last_sequence: 5
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/state/minimal.toml b/crates/trippy-core/tests/resources/state/minimal.toml
new file mode 100644
index 000000000..f379058de
--- /dev/null
+++ b/crates/trippy-core/tests/resources/state/minimal.toml
@@ -0,0 +1,17 @@
+largest_ttl = 3
+
+[[rounds]]
+probes = [
+    "1 C 333 10.1.0.1 0 12340 80 0 0",
+    "2 C 777 10.1.0.2 1 12340 80 0 0",
+    "3 C 778 10.1.0.3 2 12340 80 0 0",
+]
+
+[[expected.hops]]
+ttl = 1
+
+[[expected.hops]]
+ttl = 2
+
+[[expected.hops]]
+ttl = 3
diff --git a/crates/trippy-core/tests/resources/state/minimal.yaml b/crates/trippy-core/tests/resources/state/minimal.yaml
deleted file mode 100644
index e37980304..000000000
--- a/crates/trippy-core/tests/resources/state/minimal.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-largest_ttl: 3
-rounds:
-  - probes:
-      - 1 C 333 10.1.0.1 0 12340 80 0 0
-      - 2 C 777 10.1.0.2 1 12340 80 0 0
-      - 3 C 778 10.1.0.3 2 12340 80 0 0
-expected:
-  hops:
-    - ttl: 1
-    - ttl: 2
-    - ttl: 3
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/state/nat.toml b/crates/trippy-core/tests/resources/state/nat.toml
new file mode 100644
index 000000000..4ab10bd57
--- /dev/null
+++ b/crates/trippy-core/tests/resources/state/nat.toml
@@ -0,0 +1,34 @@
+largest_ttl = 3
+
+[[rounds]]
+probes = [
+    "1 C 333 10.1.0.1 0 12340 80 43012 43012",
+    "2 C 777 10.1.0.2 1 12340 80 20544 20544",
+    "3 C 778 10.1.0.3 2 12340 80 20544 20544",
+]
+
+[[rounds]]
+probes = [
+    "1 C 123 10.1.0.1 3 12340 80 43012 43012",
+    "2 C 788 10.1.0.2 4 12340 80 20544 20544",
+    "3 C 789 10.1.0.3 5 12340 80 20544 20544",
+]
+
+[[rounds]]
+probes = [
+    "1 C 123 10.1.0.1 6 12340 80 43012 43012",
+    "2 C 780 10.1.0.2 7 12340 80 20544 20544",
+    "3 C 781 10.1.0.3 8 12340 80 20544 20544",
+]
+
+[[expected.hops]]
+ttl = 1
+last_nat_status = "no_nat"
+
+[[expected.hops]]
+ttl = 2
+last_nat_status = "nat"
+
+[[expected.hops]]
+ttl = 3
+last_nat_status = "no_nat"
diff --git a/crates/trippy-core/tests/resources/state/nat.yaml b/crates/trippy-core/tests/resources/state/nat.yaml
deleted file mode 100644
index 197fb17b9..000000000
--- a/crates/trippy-core/tests/resources/state/nat.yaml
+++ /dev/null
@@ -1,22 +0,0 @@
-largest_ttl: 3
-rounds:
-  - probes:
-      - 1 C 333 10.1.0.1 0 12340 80 43012 43012
-      - 2 C 777 10.1.0.2 1 12340 80 20544 20544
-      - 3 C 778 10.1.0.3 2 12340 80 20544 20544
-  - probes:
-      - 1 C 123 10.1.0.1 3 12340 80 43012 43012
-      - 2 C 788 10.1.0.2 4 12340 80 20544 20544
-      - 3 C 789 10.1.0.3 5 12340 80 20544 20544
-  - probes:
-      - 1 C 123 10.1.0.1 6 12340 80 43012 43012
-      - 2 C 780 10.1.0.2 7 12340 80 20544 20544
-      - 3 C 781 10.1.0.3 8 12340 80 20544 20544
-expected:
-  hops:
-    - ttl: 1
-      last_nat_status: no_nat
-    - ttl: 2
-      last_nat_status: nat
-    - ttl: 3
-      last_nat_status: no_nat
\ No newline at end of file
diff --git a/crates/trippy-core/tests/resources/state/no_latency.toml b/crates/trippy-core/tests/resources/state/no_latency.toml
new file mode 100644
index 000000000..ca89f8dbc
--- /dev/null
+++ b/crates/trippy-core/tests/resources/state/no_latency.toml
@@ -0,0 +1,26 @@
+largest_ttl = 1
+
+[[rounds]]
+probes = ["1 C 0 127.0.0.1 0 80 80 0 0"]
+
+[[rounds]]
+probes = ["1 C 0 127.0.0.1 0 80 80 0 0"]
+
+[[rounds]]
+probes = ["1 C 0 127.0.0.1 0 80 80 0 0"]
+
+[[rounds]]
+probes = ["1 C 0 127.0.0.1 0 80 80 0 0"]
+
+[[expected.hops]]
+ttl = 1
+loss_pct = 0
+last_ms = 0.0
+best_ms = 0
+worst_ms = 0
+avg_ms = 0
+samples = [0, 0, 0, 0]
+jitter = 0
+javg = 0.0
+jmax = 0.0
+jinta = 0.0
diff --git a/crates/trippy-core/tests/resources/state/no_latency.yaml b/crates/trippy-core/tests/resources/state/no_latency.yaml
deleted file mode 100644
index 34ab80703..000000000
--- a/crates/trippy-core/tests/resources/state/no_latency.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-largest_ttl: 1
-rounds:
-  - probes:
-      - 1 C 0 127.0.0.1 0 80 80 0 0
-  - probes:
-      - 1 C 0 127.0.0.1 0 80 80 0 0
-  - probes:
-      - 1 C 0 127.0.0.1 0 80 80 0 0
-  - probes:
-      - 1 C 0 127.0.0.1 0 80 80 0 0
-expected:
-  hops:
-    - ttl: 1
-      loss_pct: 0
-      last_ms: 0.0
-      best_ms: 0
-      worst_ms: 0
-      avg_ms: 0
-      samples: [0, 0, 0, 0]
-      jitter: 0
-      javg: 0.0
-      jmax: 0.0
-      jinta: 0.0
\ No newline at end of file
diff --git a/crates/trippy-core/tests/sim/simulation.rs b/crates/trippy-core/tests/sim/simulation.rs
index c5d5445c3..aacb76e86 100644
--- a/crates/trippy-core/tests/sim/simulation.rs
+++ b/crates/trippy-core/tests/sim/simulation.rs
@@ -47,6 +47,7 @@ pub struct Hop {
 
 /// A simulated probe response.
 #[derive(Debug, Deserialize)]
+#[serde(tag = "tag")]
 pub enum Response {
     /// Simulate a hop which does not response to probes.
     NoResponse,
@@ -97,6 +98,7 @@ impl From<Protocol> for trippy_core::Protocol {
 }
 
 #[derive(Copy, Clone, Debug, Default, Deserialize)]
+#[serde(tag = "tag", content = "value")]
 pub enum PortDirection {
     #[default]
     None,
diff --git a/crates/trippy-core/tests/sim/tests.rs b/crates/trippy-core/tests/sim/tests.rs
index 86d8e4a43..ae8180c2f 100644
--- a/crates/trippy-core/tests/sim/tests.rs
+++ b/crates/trippy-core/tests/sim/tests.rs
@@ -30,30 +30,30 @@ pub fn runtime() -> &'static Arc<Mutex<Runtime>> {
 
 macro_rules! sim {
     ($path:expr) => {{
-        let yaml = include_str!(concat!("../resources/simulation/", $path));
-        serde_yml::from_str(yaml)?
+        let data = include_str!(concat!("../resources/simulation/", $path));
+        toml::from_str(data)?
     }};
 }
 
-#[test_case(sim!("ipv4_icmp.yaml"))]
-#[test_case(sim!("ipv4_icmp_gaps.yaml"))]
-#[test_case(sim!("ipv4_icmp_ooo.yaml"))]
-#[test_case(sim!("ipv4_icmp_min.yaml"))]
-#[test_case(sim!("ipv4_icmp_pattern.yaml"))]
-#[test_case(sim!("ipv4_icmp_quick.yaml"))]
-#[test_case(sim!("ipv4_icmp_wrap.yaml"))]
-#[test_case(sim!("ipv4_udp_classic_fixed_src.yaml"))]
-#[test_case(sim!("ipv4_udp_classic_fixed_dest.yaml"))]
-#[test_case(sim!("ipv4_udp_paris_fixed_both.yaml"))]
-#[test_case(sim!("ipv4_udp_dublin_fixed_both.yaml"))]
-#[test_case(sim!("ipv4_tcp_fixed_dest.yaml"))]
+#[test_case(sim!("ipv4_icmp.toml"))]
+#[test_case(sim!("ipv4_icmp_gaps.toml"))]
+#[test_case(sim!("ipv4_icmp_ooo.toml"))]
+#[test_case(sim!("ipv4_icmp_min.toml"))]
+#[test_case(sim!("ipv4_icmp_pattern.toml"))]
+#[test_case(sim!("ipv4_icmp_quick.toml"))]
+#[test_case(sim!("ipv4_icmp_wrap.toml"))]
+#[test_case(sim!("ipv4_udp_classic_fixed_src.toml"))]
+#[test_case(sim!("ipv4_udp_classic_fixed_dest.toml"))]
+#[test_case(sim!("ipv4_udp_paris_fixed_both.toml"))]
+#[test_case(sim!("ipv4_udp_dublin_fixed_both.toml"))]
+#[test_case(sim!("ipv4_tcp_fixed_dest.toml"))]
 fn test_simulation(simulation: Simulation) -> anyhow::Result<()> {
     run_simulation_with_retry(simulation)
 }
 
 // unprivileged mode is only supported on macOS
 #[cfg(target_os = "macos")]
-#[test_case(sim!("ipv4_udp_classic_unprivileged.yaml"))]
+#[test_case(sim!("ipv4_udp_classic_unprivileged.toml"))]
 fn test_simulation_macos(simulation: Simulation) -> anyhow::Result<()> {
     run_simulation_with_retry(simulation)
 }