diff --git a/Cargo.lock b/Cargo.lock index ea3e9d1..7693c20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "arctracker-sync" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anyhow", "base64", @@ -1741,7 +1741,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" dependencies = [ "heck 0.4.1", - "proc-macro-crate 2.0.2", + "proc-macro-crate 2.0.0", "proc-macro-error", "proc-macro2", "quote", @@ -2458,12 +2458,6 @@ dependencies = [ "x11", ] -[[package]] -name = "libyml" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64804cc6a5042d4f05379909ba25b503ec04e2c082151d62122d5dcaa274b961" - [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -3422,11 +3416,10 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "2.0.2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" dependencies = [ - "toml_datetime 0.6.3", "toml_edit 0.20.2", ] @@ -3690,12 +3683,11 @@ dependencies = [ [[package]] name = "rust-i18n" -version = "3.1.2" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039f57d22229db401af3458ca939300178e99e88b938573cea12b7c2b0f09724" +checksum = "55691a65892c33ee2de49c15ea5600c6f4a70e8eeb8e6c3cd96d2a231d230c40" dependencies = [ "globwalk", - "once_cell", "regex", "rust-i18n-macro", "rust-i18n-support", @@ -3704,41 +3696,36 @@ dependencies = [ [[package]] name = "rust-i18n-macro" -version = "3.1.2" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde5c022360a2e54477882843d56b6f9bcb4bc62f504b651a2f497f0028d174f" +checksum = "30de488acadcf767d97cd48518a8da8ea9777b1c9a5beca4eab78bbf77d07309" dependencies = [ "glob", - "once_cell", "proc-macro2", "quote", "rust-i18n-support", "serde", "serde_json", - "serde_yml", + "serde_yaml", "syn 2.0.117", ] [[package]] name = "rust-i18n-support" -version = "3.1.2" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75d2844d36f62b5d6b66f9cf8f8cbdbbbdcdb5fd37a473a9cc2fb45fdcf485d2" +checksum = "aea0fef8a93c06326b66392c95a115120e609674cb2132d37d276a6b05b545b4" dependencies = [ "arc-swap", "base62", "globwalk", "itertools", - "lazy_static", "normpath", - "once_cell", - "proc-macro2", - "regex", "serde", "serde_json", - "serde_yml", + "serde_yaml", "siphasher", - "toml 0.7.8", + "toml 0.8.23", "triomphe", ] @@ -3969,20 +3956,16 @@ dependencies = [ ] [[package]] -name = "serde_yml" -version = "0.0.11" +name = "serde_yaml" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e76bab63c3fd98d27c17f9cbce177f64a91f5e69ac04cafe04e1bb25d1dc3c" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ "indexmap", "itoa", - "libyml", - "log 0.4.32", - "memchr", "ryu", "serde", - "serde_json", - "tempfile", + "unsafe-libyaml", ] [[package]] @@ -4226,7 +4209,7 @@ dependencies = [ "cfg-expr", "heck 0.5.0", "pkg-config", - "toml 0.8.2", + "toml 0.8.23", "version-compare", ] @@ -4372,26 +4355,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" -dependencies = [ - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.3", - "toml_edit 0.19.15", -] - -[[package]] -name = "toml" -version = "0.8.2" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned 0.6.9", - "toml_datetime 0.6.3", - "toml_edit 0.20.2", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", ] [[package]] @@ -4411,9 +4382,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] @@ -4434,9 +4405,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap", - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.3", + "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -4445,12 +4414,24 @@ name = "toml_edit" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "toml_datetime 0.6.11", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", "serde_spanned 0.6.9", - "toml_datetime 0.6.3", - "winnow 0.5.40", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", ] [[package]] @@ -4474,6 +4455,12 @@ dependencies = [ "winnow 1.0.3", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "toml_writer" version = "1.1.1+spec-1.1.0" @@ -4626,6 +4613,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" @@ -5662,6 +5655,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "1.0.3" diff --git a/Cargo.toml b/Cargo.toml index e29c395..0c555f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "arctracker-sync" -version = "0.1.0" +version = "0.2.0" edition = "2021" publish = false description = "Windows desktop helper that syncs your ARC Raiders inventory to ARCTracker." @@ -28,7 +28,7 @@ getrandom = "0.2" hex = "0.4" pcapsql-core = { path = "vendor/pcapsql-core", default-features = false } rfd = "0.15" -rust-i18n = "3" +rust-i18n = "4" self-replace = "1.5" semver = "1" serde = { version = "1", features = ["derive"] } diff --git a/README.md b/README.md index 799699c..9302c04 100644 --- a/README.md +++ b/README.md @@ -60,9 +60,21 @@ ARCTracker sign-in is kept in Windows Credential Manager. To notice your game account connecting, ARCTracker Sync watches your own computer's network traffic using Windows raw sockets, which Windows only allows -with Administrator rights. There's no kernel driver, bundled network library, or -extra capture tool to install — and it only ever looks at traffic on your own -machine. +with Administrator rights. By default there's no kernel driver, bundled network +library, or extra capture tool to install — and it only ever looks at traffic on +your own machine. + +### Optional: Npcap capture + +Some antivirus products (Avast Web Shield, for example) interfere with +raw-socket capture. If sync won't connect on your machine, Settings → Network +lets you switch the capture method to **Npcap**, a separately installed +packet-capture driver from . ARCTracker Sync never bundles, +downloads, or installs Npcap — its license forbids redistribution — so if you +select Npcap without installing it, the app tells you and links to npcap.com. +With Npcap selected, the app loads Npcap's `wpcap.dll` at runtime and captures +through Npcap's kernel driver instead of raw sockets. It still only looks at +traffic on your own machine, and Administrator is still required. --- @@ -85,7 +97,8 @@ cargo run The app ships a manifest that requests elevation, so it runs as Administrator (required for the raw-socket capture described above). No kernel driver or -external tooling is needed. +external tooling is needed for the default raw-socket capture; the optional +Npcap capture method uses Npcap's driver, installed separately by the user. ## Contributing diff --git a/THIRD-PARTY-NOTICES.md b/THIRD-PARTY-NOTICES.md index ce222a4..71b7481 100644 --- a/THIRD-PARTY-NOTICES.md +++ b/THIRD-PARTY-NOTICES.md @@ -14,6 +14,15 @@ listed below, each of which remains under its own license. TLS decryption and protocol-registration code). See [`vendor/pcapsql-core/LOCAL-MODIFICATIONS.md`](vendor/pcapsql-core/LOCAL-MODIFICATIONS.md). +## Optional runtime dependency (not distributed) + +- **Npcap** — + - An optional packet-capture driver the user can select in Settings as an + alternative to the built-in raw-socket capture. ARCTracker Sync never + bundles, downloads, or installs Npcap (its free license does not permit + redistribution); when selected, the app loads the user's own installed + `wpcap.dll` at runtime. Npcap remains under its own license. + ## Statically linked dependencies The compiled `arctracker-sync.exe` statically links a number of open-source Rust diff --git a/locales/da.json b/locales/da.json index 398fbae..a3566bd 100644 --- a/locales/da.json +++ b/locales/da.json @@ -6,6 +6,17 @@ "SyncApp.progress.signedIn": "Logget ind", "SyncApp.progress.launcherReady": "Launcher klar", "SyncApp.progress.playing": "Spiller", + "SyncApp.phase.account.label": "Konto", + "SyncApp.phase.account.sub": "Forbind ARCTracker", + "SyncApp.phase.launcher.label": "Launcher", + "SyncApp.phase.launcher.sub": "Forbered %{launcher}", + "SyncApp.phase.play.label": "Spil", + "SyncApp.phase.play.sub": "Start ARC Raiders", + "SyncApp.phase.sync.label": "Synkronisering", + "SyncApp.phase.sync.sub": "Hold inventaret opdateret", + "SyncApp.hero.step": "Trin %{n} af 4", + "SyncApp.footer.synced": "Synkroniseret · %{account}", + "SyncApp.footer.syncedLabel": "Synkroniseret ·", "SyncApp.progress.synced": "Synkroniseret", "SyncApp.footer.signedInAs": "Logget ind som %{account}", "SyncApp.footer.notSignedIn": "Ikke logget ind", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker genstarter %{launcher}, så det kan læse dit ARC Raiders-inventar mens du spiller. Dine %{launcher}-spil, downloads og logins røres ikke.", "SyncApp.state.preparingLauncher.title": "Forbereder %{launcher}…", "SyncApp.state.preparingLauncher.body": "Lukker og genstarter %{launcher}. Dette tager et par sekunder.", + "SyncApp.state.preparingLauncher.waiting": "Forbereder %{launcher}…", "SyncApp.state.closeLauncher.title": "Luk %{launcher} for at fortsætte", "SyncApp.state.closeLauncher.body": "%{launcher} skal lukkes, så ARCTracker kan forberede det. Gem alt, der pågår, og luk det derefter.", "SyncApp.state.launcherReady.title": "%{launcher} er klar. Gå og spil.", "SyncApp.state.launcherReady.body": "Start ARC Raiders fra %{launcher} når som helst. Dit inventar synkroniseres automatisk mens du spiller.", "SyncApp.state.connecting.title": "Leder efter din ARC Raiders-konto…", "SyncApp.state.connecting.body": "Hold ARC Raiders åbent. Dette forbindes normalt et par sekunder efter, du når hovedmenuen.", + "SyncApp.state.connecting.waiting": "Venter på ARC Raiders…", "SyncApp.state.updating.title": "Opdaterer ARCTracker…", "SyncApp.state.updating.body": "Næsten færdig. Gemmer din konto.", + "SyncApp.state.updating.waiting": "Gemmer dit inventar…", "SyncApp.state.synced.title": "Du er synkroniseret", "SyncApp.state.synced.body": "Spiller som %{account}. Dit ARC Raiders-inventar er opdateret på ARCTracker.", "SyncApp.state.synced.session": "Dit inventar forbliver synkroniseret indtil %{time}.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} blev genstartet på egen hånd, så ARCTracker kan ikke læse dit inventar lige nu. Forbered det igen for at fortsætte synkroniseringen.", "SyncApp.state.needsAttention.title": "Synkronisering kræver opmærksomhed", "SyncApp.state.needsAttention.body": "ARCTracker Sync stødte på et problem med tilslutningen. Åbn fejlfinding for detaljer.", + "SyncApp.state.needsAttention.npcapBody": "Opsamlingsmetoden er sat til Npcap, men Npcap er ikke installeret på denne pc. Installer det fra npcap.com, eller skift tilbage til raw sockets i Indstillinger.", "SyncApp.action.signIn": "Log ind på ARCTracker", "SyncApp.action.cancel": "Annuller", "SyncApp.action.chooseGame": "Vælg ARC Raiders", "SyncApp.action.prepareLauncher": "Forbered %{launcher}", "SyncApp.action.whatDoesThisDo": "Hvad gør dette?", "SyncApp.action.closeLauncher": "Luk %{launcher}", + "SyncApp.action.viewStash": "Se dit inventar", "SyncApp.action.hideToTray": "Skjul i systemstatusfeltet", "SyncApp.action.getHelp": "Få hjælp", "SyncApp.action.tryAgain": "Prøv igen", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Sprog", "SyncApp.settings.displayLanguage": "Visningssprog", "SyncApp.settings.matchesWindows": "Svarer til Windows som standard", + "SyncApp.settings.matchWindows": "Svar til Windows", "SyncApp.settings.network": "Netværk", "SyncApp.settings.networkAdapter": "Netværkskort", "SyncApp.settings.networkAdapterSub": "Auto-valgt. Skift kun hvis synkronisering ikke forbindes.", "SyncApp.settings.refresh": "Opdater", + "SyncApp.settings.captureMethod": "Opsamlingsmetode", + "SyncApp.settings.captureMethodSub": "Sådan læser Sync din pc's egen spiltrafik. Skift til Npcap, hvis antivirussoftware blokerer den indbyggede metode — det kan også fungere bedre, hvis du bruger en VPN eller proxy.", + "SyncApp.settings.captureRawSockets": "Windows raw sockets (indbygget)", + "SyncApp.settings.captureNpcap": "Npcap (installeres separat)", + "SyncApp.settings.npcapMissing": "Npcap er ikke installeret, så synkronisering kan ikke opsamle trafik. Installer det, og brug derefter Prøv igen på hovedskærmen.", + "SyncApp.settings.npcapLink": "Hent Npcap (gratis) på npcap.com", "SyncApp.settings.troubleshooting": "Fejlfinding", "SyncApp.settings.activityLog": "Aktivitetslog", "SyncApp.settings.activityLogSub": "Seneste begivenheder til support", "SyncApp.settings.view": "Vis", + "SyncApp.settings.hide": "Skjul", "SyncApp.settings.copyDiagnostics": "Kopier diagnose", "SyncApp.settings.copyDiagnosticsSub": "Del med ARCTracker support", "SyncApp.settings.copy": "Kopier", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Kontroller for opdateringer", + "SyncApp.settings.whatIsSync": "Hvad gør synkronisering?", + "SyncApp.settings.quit": "Afslut ARCTracker Sync", "SyncApp.tray.open": "Åbn ARCTracker Sync", "SyncApp.tray.pause": "Pause synkronisering", "SyncApp.tray.resume": "Genoptag synkronisering", diff --git a/locales/de.json b/locales/de.json index e306b12..01331ba 100644 --- a/locales/de.json +++ b/locales/de.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "Starter bereit", "SyncApp.progress.playing": "Spielt", "SyncApp.progress.synced": "Synchronisiert", + "SyncApp.phase.account.label": "Konto", + "SyncApp.phase.account.sub": "Mit ARCTracker verbinden", + "SyncApp.phase.launcher.label": "Starter", + "SyncApp.phase.launcher.sub": "Bereite %{launcher} vor", + "SyncApp.phase.play.label": "Spielen", + "SyncApp.phase.play.sub": "Starte ARC Raiders", + "SyncApp.phase.sync.label": "Synchronisieren", + "SyncApp.phase.sync.sub": "Halte dein Inventar auf dem neuesten Stand", + "SyncApp.hero.step": "Schritt %{n} von 4", "SyncApp.footer.signedInAs": "Angemeldet als %{account}", + "SyncApp.footer.synced": "Synchronisiert · %{account}", + "SyncApp.footer.syncedLabel": "Synchronisiert ·", "SyncApp.footer.notSignedIn": "Nicht angemeldet", "SyncApp.footer.settings": "Einstellungen", "SyncApp.state.needsAdmin.title": "Zunächst eine kurze Berechtigung", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker startet %{launcher} neu, damit es dein ARC Raiders-Inventar während des Spiels lesen kann. Deine %{launcher}-Spiele, Downloads und Anmeldungen werden nicht beeinträchtigt.", "SyncApp.state.preparingLauncher.title": "%{launcher} wird vorbereitet…", "SyncApp.state.preparingLauncher.body": "%{launcher} wird geschlossen und neu geöffnet. Das dauert nur wenige Sekunden.", + "SyncApp.state.preparingLauncher.waiting": "Bereite %{launcher} vor…", "SyncApp.state.closeLauncher.title": "Schließe %{launcher}, um fortzufahren", "SyncApp.state.closeLauncher.body": "%{launcher} muss geschlossen werden, damit ARCTracker es vorbereiten kann. Speichere alles, woran du arbeitest, und schließe es dann.", "SyncApp.state.launcherReady.title": "%{launcher} ist bereit. Auf zum Spielen.", "SyncApp.state.launcherReady.body": "Starte ARC Raiders über %{launcher}, wann immer du möchtest. Dein Inventar wird während des Spiels automatisch synchronisiert.", "SyncApp.state.connecting.title": "Suche nach deinem ARC Raiders-Konto…", "SyncApp.state.connecting.body": "Halte ARC Raiders offen. Dies verbindet sich normalerweise wenige Sekunden nach dem Erreichen des Hauptmenüs.", + "SyncApp.state.connecting.waiting": "Warte auf ARC Raiders…", "SyncApp.state.updating.title": "ARCTracker wird aktualisiert…", "SyncApp.state.updating.body": "Fast geschafft. Dein Konto wird gespeichert.", + "SyncApp.state.updating.waiting": "Speichere dein Inventar…", "SyncApp.state.synced.title": "Du bist synchronisiert", "SyncApp.state.synced.body": "Spielt als %{account}. Dein ARC Raiders-Inventar ist auf ARCTracker aktuell.", "SyncApp.state.synced.session": "Dein Inventar bleibt bis %{time} synchronisiert.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} wurde von selbst neu gestartet, daher kann ARCTracker dein Inventar momentan nicht lesen. Bereite es erneut vor, um die Synchronisierung weiterhin zu gewährleisten.", "SyncApp.state.needsAttention.title": "Synchronisierung benötigt Aufmerksamkeit", "SyncApp.state.needsAttention.body": "ARCTracker Sync hatte ein Problem beim Verbinden. Öffne die Fehlerbehebung für weitere Details.", + "SyncApp.state.needsAttention.npcapBody": "Die Erfassungsmethode ist auf Npcap eingestellt, aber Npcap ist auf diesem PC nicht installiert. Installiere es von npcap.com oder wechsle in den Einstellungen zurück zu Raw Sockets.", "SyncApp.action.signIn": "Bei ARCTracker anmelden", "SyncApp.action.cancel": "Abbrechen", "SyncApp.action.chooseGame": "ARC Raiders wählen", "SyncApp.action.prepareLauncher": "%{launcher} vorbereiten", "SyncApp.action.whatDoesThisDo": "Was macht das?", "SyncApp.action.closeLauncher": "%{launcher} schließen", + "SyncApp.action.viewStash": "Zeige dein Inventar", "SyncApp.action.hideToTray": "In den Hintergrund minimieren", "SyncApp.action.getHelp": "Hilfe erhalten", "SyncApp.action.tryAgain": "Nochmal versuchen", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Sprache", "SyncApp.settings.displayLanguage": "Anzeigesprache", "SyncApp.settings.matchesWindows": "Entspricht standardmäßig Windows", + "SyncApp.settings.matchWindows": "Windows abgleichen", "SyncApp.settings.network": "Netzwerk", "SyncApp.settings.networkAdapter": "Netzwerkadapter", "SyncApp.settings.networkAdapterSub": "Automatisch ausgewählt. Nur ändern, wenn Sync sich nicht verbindet.", "SyncApp.settings.refresh": "Aktualisieren", + "SyncApp.settings.captureMethod": "Erfassungsmethode", + "SyncApp.settings.captureMethodSub": "Wie Sync den eigenen Spielverkehr deines PCs liest. Wechsle zu Npcap, wenn Antivirensoftware die integrierte Methode blockiert — es kann auch besser funktionieren, wenn du ein VPN oder einen Proxy verwendest.", + "SyncApp.settings.captureRawSockets": "Windows Raw Sockets (integriert)", + "SyncApp.settings.captureNpcap": "Npcap (separat installiert)", + "SyncApp.settings.npcapMissing": "Npcap ist nicht installiert, daher kann die Synchronisierung keinen Datenverkehr erfassen. Installiere es und nutze dann „Nochmal versuchen“ auf dem Hauptbildschirm.", + "SyncApp.settings.npcapLink": "Npcap (kostenlos) auf npcap.com herunterladen", "SyncApp.settings.troubleshooting": "Fehlerbehebung", "SyncApp.settings.activityLog": "Aktivitätsprotokoll", "SyncApp.settings.activityLogSub": "Aktuelle Ereignisse für den Support", "SyncApp.settings.view": "Anzeigen", + "SyncApp.settings.hide": "Ausblenden", "SyncApp.settings.copyDiagnostics": "Diagnose kopieren", "SyncApp.settings.copyDiagnosticsSub": "Mit dem ARCTracker-Support teilen", "SyncApp.settings.copy": "Kopieren", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Nach Updates suchen", + "SyncApp.settings.whatIsSync": "Was macht Sync?", + "SyncApp.settings.quit": "ARCTracker Sync beenden", "SyncApp.tray.open": "ARCTracker Sync öffnen", "SyncApp.tray.pause": "Synchronisierung anhalten", "SyncApp.tray.resume": "Synchronisierung fortsetzen", diff --git a/locales/en.json b/locales/en.json index 784f60c..9bf5afd 100644 --- a/locales/en.json +++ b/locales/en.json @@ -53,6 +53,7 @@ "SyncApp.state.needsLauncher.body": "%{launcher} was restarted on its own, so ARCTracker can't read your inventory right now. Prepare it again to keep syncing.", "SyncApp.state.needsAttention.title": "Sync needs attention", "SyncApp.state.needsAttention.body": "ARCTracker Sync hit a problem connecting. Open troubleshooting for details.", + "SyncApp.state.needsAttention.npcapBody": "The capture method is set to Npcap, but Npcap isn't installed on this PC. Install it from npcap.com, or switch back to raw sockets in Settings.", "SyncApp.action.signIn": "Sign in to ARCTracker", "SyncApp.action.cancel": "Cancel", "SyncApp.action.chooseGame": "Choose ARC Raiders", @@ -87,6 +88,12 @@ "SyncApp.settings.networkAdapter": "Network adapter", "SyncApp.settings.networkAdapterSub": "Auto-selected. Only change it if sync won't connect.", "SyncApp.settings.refresh": "Refresh", + "SyncApp.settings.captureMethod": "Capture method", + "SyncApp.settings.captureMethodSub": "How Sync reads your PC's own game traffic. Switch to Npcap if antivirus software blocks the built-in method — it may also work better if you use a VPN or proxy.", + "SyncApp.settings.captureRawSockets": "Windows raw sockets (built in)", + "SyncApp.settings.captureNpcap": "Npcap (installed separately)", + "SyncApp.settings.npcapMissing": "Npcap isn't installed, so sync can't capture traffic. Install it, then use Try again on the main screen.", + "SyncApp.settings.npcapLink": "Get Npcap (free) at npcap.com", "SyncApp.settings.troubleshooting": "Troubleshooting", "SyncApp.settings.activityLog": "Activity log", "SyncApp.settings.activityLogSub": "Recent events, for support", diff --git a/locales/es.json b/locales/es.json index d4f579d..2a6b837 100644 --- a/locales/es.json +++ b/locales/es.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "Lanzador listo", "SyncApp.progress.playing": "Jugando", "SyncApp.progress.synced": "Sincronizado", + "SyncApp.phase.account.label": "Cuenta", + "SyncApp.phase.account.sub": "Conectar ARCTracker", + "SyncApp.phase.launcher.label": "Lanzador", + "SyncApp.phase.launcher.sub": "Prepara %{launcher}", + "SyncApp.phase.play.label": "Jugar", + "SyncApp.phase.play.sub": "Lanza ARC Raiders", + "SyncApp.phase.sync.label": "Sincronizar", + "SyncApp.phase.sync.sub": "Mantén tu inventario actualizado", + "SyncApp.hero.step": "Paso %{n} de 4", "SyncApp.footer.signedInAs": "Sesión iniciada como %{account}", + "SyncApp.footer.synced": "Sincronizado · %{account}", + "SyncApp.footer.syncedLabel": "Sincronizado ·", "SyncApp.footer.notSignedIn": "Sesión no iniciada", "SyncApp.footer.settings": "Configuración", "SyncApp.state.needsAdmin.title": "Un permiso rápido primero", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker reinicia %{launcher} para poder leer tu inventario de ARC Raiders mientras juegas. Tus juegos, descargas e inicios de sesión de %{launcher} no se ven afectados.", "SyncApp.state.preparingLauncher.title": "Preparando %{launcher}…", "SyncApp.state.preparingLauncher.body": "Cerrando y reabriendo %{launcher}. Esto tarda unos segundos.", + "SyncApp.state.preparingLauncher.waiting": "Preparando %{launcher}…", "SyncApp.state.closeLauncher.title": "Cierra %{launcher} para continuar", "SyncApp.state.closeLauncher.body": "%{launcher} debe cerrarse para que ARCTracker lo pueda preparar. Guarda cualquier progreso en marcha y luego ciérralo.", "SyncApp.state.launcherReady.title": "%{launcher} está listo. Ve a jugar.", "SyncApp.state.launcherReady.body": "Inicia ARC Raiders desde %{launcher} cuando quieras. Tu inventario se sincroniza automáticamente mientras juegas.", "SyncApp.state.connecting.title": "Buscando tu cuenta de ARC Raiders…", "SyncApp.state.connecting.body": "Mantén ARC Raiders abierto. Normalmente se conecta unos segundos después de que llegues al menú principal.", + "SyncApp.state.connecting.waiting": "Esperando ARC Raiders…", "SyncApp.state.updating.title": "Actualizando ARCTracker…", "SyncApp.state.updating.body": "Ya casi. Guardando tu cuenta.", + "SyncApp.state.updating.waiting": "Guardando tu inventario…", "SyncApp.state.synced.title": "Estás sincronizado", "SyncApp.state.synced.body": "Jugando como %{account}. Tu inventario de ARC Raiders está actualizado en ARCTracker.", "SyncApp.state.synced.session": "Tu inventario permanece sincronizado hasta las %{time}.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} se reinició por sí solo, así que ARCTracker no puede leer tu inventario ahora. Prepáralo de nuevo para seguir sincronizando.", "SyncApp.state.needsAttention.title": "La sincronización necesita atención", "SyncApp.state.needsAttention.body": "ARCTracker Sync tuvo un problema al conectar. Abre la solución de problemas para obtener más detalles.", + "SyncApp.state.needsAttention.npcapBody": "El método de captura está configurado en Npcap, pero Npcap no está instalado en este PC. Instálalo desde npcap.com o vuelve a los sockets sin procesar en Configuración.", "SyncApp.action.signIn": "Iniciar sesión en ARCTracker", "SyncApp.action.cancel": "Cancelar", "SyncApp.action.chooseGame": "Elige ARC Raiders", "SyncApp.action.prepareLauncher": "Prepara %{launcher}", "SyncApp.action.whatDoesThisDo": "¿Qué hace esto?", "SyncApp.action.closeLauncher": "Cierra %{launcher}", + "SyncApp.action.viewStash": "Ver tu inventario", "SyncApp.action.hideToTray": "Ocultar en la bandeja", "SyncApp.action.getHelp": "Obtener ayuda", "SyncApp.action.tryAgain": "Intentar de nuevo", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Idioma", "SyncApp.settings.displayLanguage": "Idioma de visualización", "SyncApp.settings.matchesWindows": "Coincide con Windows de forma predeterminada", + "SyncApp.settings.matchWindows": "Coincidir con Windows", "SyncApp.settings.network": "Red", "SyncApp.settings.networkAdapter": "Adaptador de red", "SyncApp.settings.networkAdapterSub": "Seleccionado automáticamente. Solo cambia si la sincronización no se conecta.", "SyncApp.settings.refresh": "Actualizar", + "SyncApp.settings.captureMethod": "Método de captura", + "SyncApp.settings.captureMethodSub": "Cómo Sync lee el tráfico de juego de tu propio PC. Cambia a Npcap si un antivirus bloquea el método integrado — también puede funcionar mejor si utilizas un VPN o proxy.", + "SyncApp.settings.captureRawSockets": "Sockets sin procesar de Windows (integrado)", + "SyncApp.settings.captureNpcap": "Npcap (se instala por separado)", + "SyncApp.settings.npcapMissing": "Npcap no está instalado, así que la sincronización no puede capturar el tráfico. Instálalo y luego usa Intentar de nuevo en la pantalla principal.", + "SyncApp.settings.npcapLink": "Consigue Npcap (gratis) en npcap.com", "SyncApp.settings.troubleshooting": "Solución de problemas", "SyncApp.settings.activityLog": "Registro de actividad", "SyncApp.settings.activityLogSub": "Eventos recientes, para soporte", "SyncApp.settings.view": "Ver", + "SyncApp.settings.hide": "Ocultar", "SyncApp.settings.copyDiagnostics": "Copiar diagnósticos", "SyncApp.settings.copyDiagnosticsSub": "Compartir con el soporte de ARCTracker", "SyncApp.settings.copy": "Copiar", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Buscar actualizaciones", + "SyncApp.settings.whatIsSync": "¿Qué hace Sync?", + "SyncApp.settings.quit": "Salir de ARCTracker Sync", "SyncApp.tray.open": "Abrir ARCTracker Sync", "SyncApp.tray.pause": "Pausar sincronización", "SyncApp.tray.resume": "Reanudar sincronización", diff --git a/locales/fr.json b/locales/fr.json index 8b334e7..ed95e2d 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "Lanceur prêt", "SyncApp.progress.playing": "En jeu", "SyncApp.progress.synced": "Synchronisé", + "SyncApp.phase.account.label": "Compte", + "SyncApp.phase.account.sub": "Connectez ARCTracker", + "SyncApp.phase.launcher.label": "Lanceur", + "SyncApp.phase.launcher.sub": "Préparer %{launcher}", + "SyncApp.phase.play.label": "Jouer", + "SyncApp.phase.play.sub": "Lancez ARC Raiders", + "SyncApp.phase.sync.label": "Synchronisation", + "SyncApp.phase.sync.sub": "Gardez votre inventaire à jour", + "SyncApp.hero.step": "Étape %{n} sur 4", "SyncApp.footer.signedInAs": "Connecté en tant que %{account}", + "SyncApp.footer.synced": "Synchronisé · %{account}", + "SyncApp.footer.syncedLabel": "Synchronisé ·", "SyncApp.footer.notSignedIn": "Non connecté", "SyncApp.footer.settings": "Paramètres", "SyncApp.state.needsAdmin.title": "Une permission rapide d'abord", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker redémarre %{launcher} pour pouvoir lire votre inventaire ARC Raiders pendant que vous jouez. Vos jeux %{launcher}, téléchargements et identifiants ne sont pas affectés.", "SyncApp.state.preparingLauncher.title": "Préparation de %{launcher}…", "SyncApp.state.preparingLauncher.body": "Fermeture et réouverture de %{launcher}. Cela prend quelques secondes.", + "SyncApp.state.preparingLauncher.waiting": "Préparation de %{launcher}…", "SyncApp.state.closeLauncher.title": "Fermez %{launcher} pour continuer", "SyncApp.state.closeLauncher.body": "%{launcher} doit se fermer pour qu'ARCTracker puisse le préparer. Sauvegardez vos progrès, puis fermez-le.", "SyncApp.state.launcherReady.title": "%{launcher} est prêt. Allez jouer.", "SyncApp.state.launcherReady.body": "Lancez ARC Raiders à partir de %{launcher} quand vous le souhaitez. Votre inventaire se synchronise automatiquement pendant que vous jouez.", "SyncApp.state.connecting.title": "Recherche de votre compte ARC Raiders…", "SyncApp.state.connecting.body": "Gardez ARC Raiders ouvert. Cela se connecte généralement quelques secondes après que vous atteignez le menu principal.", + "SyncApp.state.connecting.waiting": "Attente d'ARC Raiders…", "SyncApp.state.updating.title": "Mise à jour d'ARCTracker…", "SyncApp.state.updating.body": "Presque terminé. Enregistrement de votre compte.", + "SyncApp.state.updating.waiting": "Enregistrement de votre inventaire…", "SyncApp.state.synced.title": "Vous êtes synchronisé", "SyncApp.state.synced.body": "Vous jouez en tant que %{account}. Votre inventaire ARC Raiders est à jour sur ARCTracker.", "SyncApp.state.synced.session": "Votre inventaire reste synchronisé jusqu'à %{time}.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} a été redémarré de lui-même, donc ARCTracker ne peut pas lire votre inventaire maintenant. Préparez-le à nouveau pour continuer la synchronisation.", "SyncApp.state.needsAttention.title": "La synchronisation nécessite une attention", "SyncApp.state.needsAttention.body": "ARCTracker Sync a rencontré un problème de connexion. Ouvrez le dépannage pour plus de détails.", + "SyncApp.state.needsAttention.npcapBody": "La méthode de capture est définie sur Npcap, mais Npcap n'est pas installé sur ce PC. Installez-le depuis npcap.com, ou revenez aux sockets bruts dans les Paramètres.", "SyncApp.action.signIn": "Connectez-vous à ARCTracker", "SyncApp.action.cancel": "Annuler", "SyncApp.action.chooseGame": "Sélectionnez ARC Raiders", "SyncApp.action.prepareLauncher": "Préparer %{launcher}", "SyncApp.action.whatDoesThisDo": "À quoi ça sert ?", "SyncApp.action.closeLauncher": "Fermer %{launcher}", + "SyncApp.action.viewStash": "Afficher votre inventaire", "SyncApp.action.hideToTray": "Masquer dans la barre d'état système", "SyncApp.action.getHelp": "Obtenir de l'aide", "SyncApp.action.tryAgain": "Réessayer", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Langue", "SyncApp.settings.displayLanguage": "Langue d'affichage", "SyncApp.settings.matchesWindows": "Correspond à Windows par défaut", + "SyncApp.settings.matchWindows": "Correspondre à Windows", "SyncApp.settings.network": "Réseau", "SyncApp.settings.networkAdapter": "Adaptateur réseau", "SyncApp.settings.networkAdapterSub": "Sélectionné automatiquement. Ne changez que si la synchronisation ne se connecte pas.", "SyncApp.settings.refresh": "Actualiser", + "SyncApp.settings.captureMethod": "Méthode de capture", + "SyncApp.settings.captureMethodSub": "Comment Sync lit le trafic de jeu de votre propre PC. Passez à Npcap si un antivirus bloque la méthode intégrée — cela peut également mieux fonctionner si vous utilisez un VPN ou un proxy.", + "SyncApp.settings.captureRawSockets": "Sockets bruts Windows (intégré)", + "SyncApp.settings.captureNpcap": "Npcap (installé séparément)", + "SyncApp.settings.npcapMissing": "Npcap n'est pas installé, donc la synchronisation ne peut pas capturer le trafic. Installez-le, puis utilisez « Réessayer » sur l'écran principal.", + "SyncApp.settings.npcapLink": "Obtenez Npcap (gratuit) sur npcap.com", "SyncApp.settings.troubleshooting": "Dépannage", "SyncApp.settings.activityLog": "Journal d'activité", "SyncApp.settings.activityLogSub": "Événements récents, pour le support", "SyncApp.settings.view": "Afficher", + "SyncApp.settings.hide": "Masquer", "SyncApp.settings.copyDiagnostics": "Copier les diagnostics", "SyncApp.settings.copyDiagnosticsSub": "Partagez avec le support ARCTracker", "SyncApp.settings.copy": "Copier", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Vérifier les mises à jour", + "SyncApp.settings.whatIsSync": "À quoi sert Sync ?", + "SyncApp.settings.quit": "Quitter ARCTracker Sync", "SyncApp.tray.open": "Ouvrir ARCTracker Sync", "SyncApp.tray.pause": "Mettre en pause la synchronisation", "SyncApp.tray.resume": "Reprendre la synchronisation", diff --git a/locales/he.json b/locales/he.json index 5ee578b..e3e65f3 100644 --- a/locales/he.json +++ b/locales/he.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "משקיף מוכן", "SyncApp.progress.playing": "משחק", "SyncApp.progress.synced": "סונכרן", + "SyncApp.phase.account.label": "חשבון", + "SyncApp.phase.account.sub": "חבר ARCTracker", + "SyncApp.phase.launcher.label": "משקיף", + "SyncApp.phase.launcher.sub": "הכן %{launcher}", + "SyncApp.phase.play.label": "משחק", + "SyncApp.phase.play.sub": "הפעל ARC Raiders", + "SyncApp.phase.sync.label": "סנכרון", + "SyncApp.phase.sync.sub": "שמור מלאי עדכני", + "SyncApp.hero.step": "שלב %{n} מתוך 4", "SyncApp.footer.signedInAs": "מחובר כ-%{account}", + "SyncApp.footer.synced": "סונכרן · %{account}", + "SyncApp.footer.syncedLabel": "סונכרן ·", "SyncApp.footer.notSignedIn": "לא מחובר", "SyncApp.footer.settings": "הגדרות", "SyncApp.state.needsAdmin.title": "רשות אחת מהירה בבקשה", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker יפעיל מחדש את %{launcher} כך שיוכל לקרוא את המלאי ARC Raiders שלכם בזמן משחק. משחקי %{launcher}, הורדות והתחברויות שלכם לא יושפעו.", "SyncApp.state.preparingLauncher.title": "הכנת %{launcher}…", "SyncApp.state.preparingLauncher.body": "סגירה ופתיחה מחדש של %{launcher}. זה לוקח כמה שניות.", + "SyncApp.state.preparingLauncher.waiting": "הכנת %{launcher}…", "SyncApp.state.closeLauncher.title": "סגרו את %{launcher} כדי להמשיך", "SyncApp.state.closeLauncher.body": "%{launcher} צריך להיסגר כדי שARCTracker יוכל להכין אותו. שמרו כל דבר בעיצומו, ואז סגרו אותו.", "SyncApp.state.launcherReady.title": "%{launcher} מוכן. בואו תשחקו.", "SyncApp.state.launcherReady.body": "התחילו את ARC Raiders מ-%{launcher} בכל זמן שתרצו. המלאי שלכם יסונכרן באופן אוטומטי בזמן משחק.", "SyncApp.state.connecting.title": "חיפוש חשבון ARC Raiders שלכם…", "SyncApp.state.connecting.body": "שמרו את ARC Raiders פתוח. בדרך כלל זה מתחבר כמה שניות אחרי שתגיעו לתפריט הראשי.", + "SyncApp.state.connecting.waiting": "ממתינים ל-ARC Raiders…", "SyncApp.state.updating.title": "עדכון ARCTracker…", "SyncApp.state.updating.body": "כמעט סיימנו. שמירת החשבון שלכם.", + "SyncApp.state.updating.waiting": "שמירת המלאי שלכם…", "SyncApp.state.synced.title": "אתם סונכרנים", "SyncApp.state.synced.body": "משחק כ-%{account}. המלאי של ARC Raiders שלכם עדכני ב-ARCTracker.", "SyncApp.state.synced.session": "המלאי שלכם יישאר סונכרן עד %{time}.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} הופעל מחדש מעצמו, כך שARCTracker לא יכול לקרוא את המלאי שלכם כעת. הכינו אותו שוב כדי להמשיך בסנכרון.", "SyncApp.state.needsAttention.title": "סנכרון זקוק לתשומת לב", "SyncApp.state.needsAttention.body": "ARCTracker Sync נתקל בבעיה בהתחברות. פתחו פתרון בעיות לפרטים נוספים.", + "SyncApp.state.needsAttention.npcapBody": "שיטת הלכידה מוגדרת ל-Npcap, אבל Npcap לא מותקן במחשב הזה. התקינו אותו מ-npcap.com, או חזרו ל-raw sockets בהגדרות.", "SyncApp.action.signIn": "היכנסו ל-ARCTracker", "SyncApp.action.cancel": "ביטול", "SyncApp.action.chooseGame": "בחרו ARC Raiders", "SyncApp.action.prepareLauncher": "הכנת %{launcher}", "SyncApp.action.whatDoesThisDo": "מה זה עושה?", "SyncApp.action.closeLauncher": "סגור את %{launcher}", + "SyncApp.action.viewStash": "צפה במלאי שלך", "SyncApp.action.hideToTray": "הסתר לשרייה", "SyncApp.action.getHelp": "קבל עזרה", "SyncApp.action.tryAgain": "נסה שוב", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "שפה", "SyncApp.settings.displayLanguage": "שפת תצוגה", "SyncApp.settings.matchesWindows": "תואם ל-Windows כברירת מחדל", + "SyncApp.settings.matchWindows": "תאם ל-Windows", "SyncApp.settings.network": "רשת", "SyncApp.settings.networkAdapter": "מתאם רשת", "SyncApp.settings.networkAdapterSub": "נבחר באופן אוטומטי. שנה רק אם סנכרון לא מתחבר.", "SyncApp.settings.refresh": "רענן", + "SyncApp.settings.captureMethod": "שיטת לכידה", + "SyncApp.settings.captureMethodSub": "כיצד Sync קורא את תעבורת המשחק של המחשב שלך. עבור ל-Npcap אם תוכנת אנטי-וירוס חוסמת את השיטה המובנית — זה גם עשוי לעבוד טוב יותר אם אתה משתמש ב-VPN או פרוקסי.", + "SyncApp.settings.captureRawSockets": "Windows raw sockets (מובנה)", + "SyncApp.settings.captureNpcap": "Npcap (מותקן בנפרד)", + "SyncApp.settings.npcapMissing": "Npcap לא מותקן, ולכן הסנכרון לא יכול ללכוד תעבורה. התקן אותו, ואז השתמש ב\"נסה שוב\" במסך הראשי.", + "SyncApp.settings.npcapLink": "קבל את Npcap (בחינם) ב-npcap.com", "SyncApp.settings.troubleshooting": "פתרון בעיות", "SyncApp.settings.activityLog": "רישום פעילות", "SyncApp.settings.activityLogSub": "אירועים עדכניים, לתמיכה", "SyncApp.settings.view": "צפה", + "SyncApp.settings.hide": "הסתר", "SyncApp.settings.copyDiagnostics": "העתק אבחון", "SyncApp.settings.copyDiagnosticsSub": "שתף עם תמיכת ARCTracker", "SyncApp.settings.copy": "העתק", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "חפש עדכונים", + "SyncApp.settings.whatIsSync": "מה עושה סנכרון?", + "SyncApp.settings.quit": "צא מ-ARCTracker Sync", "SyncApp.tray.open": "פתח ARCTracker Sync", "SyncApp.tray.pause": "השהה סנכרון", "SyncApp.tray.resume": "חזור סנכרון", diff --git a/locales/hr.json b/locales/hr.json index 9f94540..9170c1b 100644 --- a/locales/hr.json +++ b/locales/hr.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "Pokretač je spreman", "SyncApp.progress.playing": "Igraš", "SyncApp.progress.synced": "Sinhroniziran", + "SyncApp.phase.account.label": "Račun", + "SyncApp.phase.account.sub": "Povežite ARCTracker", + "SyncApp.phase.launcher.label": "Pokretač", + "SyncApp.phase.launcher.sub": "Pripremite %{launcher}", + "SyncApp.phase.play.label": "Igraj", + "SyncApp.phase.play.sub": "Pokrenite ARC Raiders", + "SyncApp.phase.sync.label": "Sinhronizacija", + "SyncApp.phase.sync.sub": "Održavajte inventar ažurnim", + "SyncApp.hero.step": "Korak %{n} od 4", "SyncApp.footer.signedInAs": "Prijavljen kao %{account}", + "SyncApp.footer.synced": "Sinhroniziran · %{account}", + "SyncApp.footer.syncedLabel": "Sinhroniziran ·", "SyncApp.footer.notSignedIn": "Niste prijavljeni", "SyncApp.footer.settings": "Postavke", "SyncApp.state.needsAdmin.title": "Prvo je potrebna dozvola", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker restartuje %{launcher} kako bi mogao čitati vaš ARC Raiders inventar tijekom igranja. Vaši %{launcher} igre, preuzimanja i prijave nisu dodirnuti.", "SyncApp.state.preparingLauncher.title": "Priprema %{launcher}…", "SyncApp.state.preparingLauncher.body": "Zatvaranje i ponovno otvaranje %{launcher}. Ovo traje nekoliko sekundi.", + "SyncApp.state.preparingLauncher.waiting": "Priprema %{launcher}…", "SyncApp.state.closeLauncher.title": "Zatvorite %{launcher} da biste nastavili", "SyncApp.state.closeLauncher.body": "%{launcher} se mora zatvoriti kako bi ARCTracker mogao to pripremiti. Spremi sve što je u tijeku, zatim ga zatvorite.", "SyncApp.state.launcherReady.title": "%{launcher} je spreman. Hajde da igraš.", "SyncApp.state.launcherReady.body": "Pokrenite ARC Raiders iz %{launcher} kada god želite. Vaš inventar se automatski sinhronizira tijekom igranja.", "SyncApp.state.connecting.title": "Tražim vaš ARC Raiders račun…", "SyncApp.state.connecting.body": "Održavajte ARC Raiders otvorenim. Obično se povezuje nekoliko sekundi nakon što dosegnete glavnib meni.", + "SyncApp.state.connecting.waiting": "Čekam ARC Raiders…", "SyncApp.state.updating.title": "Ažuriranje ARCTracker…", "SyncApp.state.updating.body": "Gotovo je. Spremam vaš račun.", + "SyncApp.state.updating.waiting": "Čuvanje vašeg inventara…", "SyncApp.state.synced.title": "Sinhroniziran ste", "SyncApp.state.synced.body": "Igrate kao %{account}. Vaš ARC Raiders inventar je ažuran na ARCTracker-u.", "SyncApp.state.synced.session": "Vaš inventar ostaje sinhroniziran do %{time}.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} je samostalno restartovan, pa ARCTracker sada ne može čitati vaš inventar. Pripremite ga ponovno da biste nastavili sinhronizaciju.", "SyncApp.state.needsAttention.title": "Sinhronizacija trebanja pažnje", "SyncApp.state.needsAttention.body": "ARCTracker Sync je naišao na problem pri povezivanju. Otvorite rješavanje problema za detalje.", + "SyncApp.state.needsAttention.npcapBody": "Metoda hvatanja postavljena je na Npcap, ali Npcap nije instaliran na ovom PC-u. Instalirajte ga s npcap.com ili se vratite na sirove sockete u Postavkama.", "SyncApp.action.signIn": "Prijavite se na ARCTracker", "SyncApp.action.cancel": "Otkaži", "SyncApp.action.chooseGame": "Odaberite ARC Raiders", "SyncApp.action.prepareLauncher": "Pripremite %{launcher}", "SyncApp.action.whatDoesThisDo": "Što to radi?", "SyncApp.action.closeLauncher": "Zatvorite %{launcher}", + "SyncApp.action.viewStash": "Pogledajte svoj inventar", "SyncApp.action.hideToTray": "Sakrij u trac", "SyncApp.action.getHelp": "Potražite pomoć", "SyncApp.action.tryAgain": "Pokušajte ponovno", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Jezik", "SyncApp.settings.displayLanguage": "Jezik prikaza", "SyncApp.settings.matchesWindows": "Poklapa se sa Windows-om prema zadanom", + "SyncApp.settings.matchWindows": "Uskladi sa Windows-om", "SyncApp.settings.network": "Mreža", "SyncApp.settings.networkAdapter": "Mrežni adapter", "SyncApp.settings.networkAdapterSub": "Automatski odabran. Mijenjajte samo ako sinhronizacija neće biti povezana.", "SyncApp.settings.refresh": "Osvježi", + "SyncApp.settings.captureMethod": "Metoda hvatanja", + "SyncApp.settings.captureMethodSub": "Kako Sync čita vlastiti promet igre vašeg PC-a. Prebacite se na Npcap ako antivirusni softver blokira ugrađenu metodu — može i bolje raditi ako koristite VPN ili proxy.", + "SyncApp.settings.captureRawSockets": "Windows sirovi socketi (ugrađeno)", + "SyncApp.settings.captureNpcap": "Npcap (instalira se zasebno)", + "SyncApp.settings.npcapMissing": "Npcap nije instaliran, pa sinhronizacija ne može hvatati promet. Instalirajte ga, a zatim upotrijebite Pokušajte ponovno na glavnom zaslonu.", + "SyncApp.settings.npcapLink": "Preuzmite Npcap (besplatno) na npcap.com", "SyncApp.settings.troubleshooting": "Rješavanje problema", "SyncApp.settings.activityLog": "Dnevnik aktivnosti", "SyncApp.settings.activityLogSub": "Nedavni događaji za podršku", "SyncApp.settings.view": "Prikazi", + "SyncApp.settings.hide": "Sakrij", "SyncApp.settings.copyDiagnostics": "Kopirajte dijagnostiku", "SyncApp.settings.copyDiagnosticsSub": "Podijelite sa ARCTracker podrškom", "SyncApp.settings.copy": "Kopiraj", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Provjeri ažuriranja", + "SyncApp.settings.whatIsSync": "Što Sync radi?", + "SyncApp.settings.quit": "Izlaz iz ARCTracker Sync", "SyncApp.tray.open": "Otvorite ARCTracker Sync", "SyncApp.tray.pause": "Pauzira sinhronizaciju", "SyncApp.tray.resume": "Nastavi sinhronizaciju", diff --git a/locales/it.json b/locales/it.json index 1ba516e..0b6aad3 100644 --- a/locales/it.json +++ b/locales/it.json @@ -6,6 +6,17 @@ "SyncApp.progress.signedIn": "Acceduto", "SyncApp.progress.launcherReady": "Launcher pronto", "SyncApp.progress.playing": "In gioco", + "SyncApp.phase.account.label": "Account", + "SyncApp.phase.account.sub": "Connetti ARCTracker", + "SyncApp.phase.launcher.label": "Launcher", + "SyncApp.phase.launcher.sub": "Prepara %{launcher}", + "SyncApp.phase.play.label": "Gioca", + "SyncApp.phase.play.sub": "Avvia ARC Raiders", + "SyncApp.phase.sync.label": "Sincronizzazione", + "SyncApp.phase.sync.sub": "Mantieni l'inventario aggiornato", + "SyncApp.hero.step": "Passaggio %{n} di 4", + "SyncApp.footer.synced": "Sincronizzato · %{account}", + "SyncApp.footer.syncedLabel": "Sincronizzato ·", "SyncApp.progress.synced": "Sincronizzato", "SyncApp.footer.signedInAs": "Acceduto come %{account}", "SyncApp.footer.notSignedIn": "Non acceduto", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker riavvia %{launcher} per leggere il tuo inventario di ARC Raiders mentre giochi. I tuoi giochi, download e accessi su %{launcher} non vengono toccati.", "SyncApp.state.preparingLauncher.title": "Preparazione di %{launcher}…", "SyncApp.state.preparingLauncher.body": "Chiusura e riapertura di %{launcher}. Questo richiede pochi secondi.", + "SyncApp.state.preparingLauncher.waiting": "Preparazione di %{launcher}…", "SyncApp.state.closeLauncher.title": "Chiudi %{launcher} per continuare", "SyncApp.state.closeLauncher.body": "%{launcher} deve chiudersi in modo che ARCTracker possa prepararlo. Salva tutto quello che hai in corso, quindi chiudilo.", "SyncApp.state.launcherReady.title": "%{launcher} è pronto. Vai a giocare.", "SyncApp.state.launcherReady.body": "Avvia ARC Raiders da %{launcher} quando vuoi. L'inventario si sincronizza automaticamente mentre giochi.", "SyncApp.state.connecting.title": "Ricerca del tuo account ARC Raiders…", "SyncApp.state.connecting.body": "Mantieni ARC Raiders aperto. Di solito si connette pochi secondi dopo aver raggiunto il menu principale.", + "SyncApp.state.connecting.waiting": "In attesa di ARC Raiders…", "SyncApp.state.updating.title": "Aggiornamento di ARCTracker…", "SyncApp.state.updating.body": "Quasi fatto. Salvataggio del tuo account.", + "SyncApp.state.updating.waiting": "Salvataggio del tuo inventario…", "SyncApp.state.synced.title": "Sei sincronizzato", "SyncApp.state.synced.body": "Giocando come %{account}. L'inventario di ARC Raiders è aggiornato su ARCTracker.", "SyncApp.state.synced.session": "L'inventario rimane sincronizzato fino a %{time}.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} è stato riavviato autonomamente, quindi ARCTracker non riesce a leggere l'inventario in questo momento. Preparalo di nuovo per continuare la sincronizzazione.", "SyncApp.state.needsAttention.title": "La sincronizzazione necessita attenzione", "SyncApp.state.needsAttention.body": "ARCTracker Sync ha riscontrato un problema durante la connessione. Apri la risoluzione dei problemi per i dettagli.", + "SyncApp.state.needsAttention.npcapBody": "Il metodo di acquisizione è impostato su Npcap, ma Npcap non è installato su questo PC. Installalo da npcap.com, oppure torna ai socket raw nelle Impostazioni.", "SyncApp.action.signIn": "Accedi a ARCTracker", "SyncApp.action.cancel": "Annulla", "SyncApp.action.chooseGame": "Scegli ARC Raiders", "SyncApp.action.prepareLauncher": "Prepara %{launcher}", "SyncApp.action.whatDoesThisDo": "Che cosa fa questo?", "SyncApp.action.closeLauncher": "Chiudi %{launcher}", + "SyncApp.action.viewStash": "Visualizza il tuo inventario", "SyncApp.action.hideToTray": "Nascondi nel vassoio", "SyncApp.action.getHelp": "Ottieni aiuto", "SyncApp.action.tryAgain": "Riprova", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Lingua", "SyncApp.settings.displayLanguage": "Lingua di visualizzazione", "SyncApp.settings.matchesWindows": "Corrisponde a Windows per impostazione predefinita", + "SyncApp.settings.matchWindows": "Abbina a Windows", "SyncApp.settings.network": "Rete", "SyncApp.settings.networkAdapter": "Adattatore di rete", "SyncApp.settings.networkAdapterSub": "Auto-selezionato. Modifica solo se la sincronizzazione non si connette.", "SyncApp.settings.refresh": "Aggiorna", + "SyncApp.settings.captureMethod": "Metodo di acquisizione", + "SyncApp.settings.captureMethodSub": "Come Sync legge il traffico di gioco del tuo PC. Passa a Npcap se il software antivirus blocca il metodo integrato — potrebbe funzionare meglio anche se utilizzi una VPN o un proxy.", + "SyncApp.settings.captureRawSockets": "Socket raw di Windows (integrati)", + "SyncApp.settings.captureNpcap": "Npcap (installato separatamente)", + "SyncApp.settings.npcapMissing": "Npcap non è installato, quindi la sincronizzazione non può acquisire il traffico. Installalo, poi usa Riprova nella schermata principale.", + "SyncApp.settings.npcapLink": "Ottieni Npcap (gratuito) su npcap.com", "SyncApp.settings.troubleshooting": "Risoluzione dei problemi", "SyncApp.settings.activityLog": "Registro attività", "SyncApp.settings.activityLogSub": "Eventi recenti, per il supporto", "SyncApp.settings.view": "Visualizza", + "SyncApp.settings.hide": "Nascondi", "SyncApp.settings.copyDiagnostics": "Copia diagnostica", "SyncApp.settings.copyDiagnosticsSub": "Condividi con il supporto ARCTracker", "SyncApp.settings.copy": "Copia", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Verifica disponibilità aggiornamenti", + "SyncApp.settings.whatIsSync": "Cosa fa la Sincronizzazione?", + "SyncApp.settings.quit": "Esci da ARCTracker Sync", "SyncApp.tray.open": "Apri ARCTracker Sync", "SyncApp.tray.pause": "Sospendi sincronizzazione", "SyncApp.tray.resume": "Riprendi sincronizzazione", diff --git a/locales/ja.json b/locales/ja.json index bcb116b..a1adcae 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "ランチャー準備完了", "SyncApp.progress.playing": "プレイ中", "SyncApp.progress.synced": "同期完了", + "SyncApp.phase.account.label": "アカウント", + "SyncApp.phase.account.sub": "ARCTracker を接続", + "SyncApp.phase.launcher.label": "ランチャー", + "SyncApp.phase.launcher.sub": "%{launcher} を準備する", + "SyncApp.phase.play.label": "プレイ", + "SyncApp.phase.play.sub": "ARC Raiders を起動", + "SyncApp.phase.sync.label": "同期", + "SyncApp.phase.sync.sub": "インベントリを最新に保つ", + "SyncApp.hero.step": "ステップ %{n} / 4", "SyncApp.footer.signedInAs": "%{account} でサインイン中", + "SyncApp.footer.synced": "同期完了 · %{account}", + "SyncApp.footer.syncedLabel": "同期完了 ·", "SyncApp.footer.notSignedIn": "サインインしていません", "SyncApp.footer.settings": "設定", "SyncApp.state.needsAdmin.title": "クイック権限設定を確認してください", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker は %{launcher} を再起動して、プレイ中の ARC Raiders インベントリを読み込めるようにします。%{launcher} のゲーム、ダウンロード、ログインには影響しません。", "SyncApp.state.preparingLauncher.title": "%{launcher} を準備中…", "SyncApp.state.preparingLauncher.body": "%{launcher} を閉じて再起動しています。数秒かかります。", + "SyncApp.state.preparingLauncher.waiting": "%{launcher} を準備中…", "SyncApp.state.closeLauncher.title": "続行するには %{launcher} を閉じてください", "SyncApp.state.closeLauncher.body": "ARCTracker が %{launcher} を準備するために、%{launcher} を閉じる必要があります。進行中の作業を保存してから閉じてください。", "SyncApp.state.launcherReady.title": "%{launcher} の準備が完了しました。プレイ開始", "SyncApp.state.launcherReady.body": "%{launcher} から好きなときに ARC Raiders を起動してください。プレイ中にインベントリは自動的に同期されます。", "SyncApp.state.connecting.title": "ARC Raiders アカウントを検索中…", "SyncApp.state.connecting.body": "ARC Raiders を起動したままにしてください。通常、メインメニューに到達してから数秒で接続されます。", + "SyncApp.state.connecting.waiting": "ARC Raiders を待機中…", "SyncApp.state.updating.title": "ARCTracker を更新中…", "SyncApp.state.updating.body": "もうすぐです。アカウントを保存しています。", + "SyncApp.state.updating.waiting": "ストレージを保存中…", "SyncApp.state.synced.title": "同期完了", "SyncApp.state.synced.body": "%{account} でプレイ中です。ARCTracker はインベントリを最新に保っています。", "SyncApp.state.synced.session": "インベントリは %{time} まで同期が続きます。", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} が独自に再起動されたため、ARCTracker はインベントリを読み込めません。同期を続行するには再度準備してください。", "SyncApp.state.needsAttention.title": "同期に注意が必要です", "SyncApp.state.needsAttention.body": "ARCTracker Sync が接続時に問題が発生しました。トラブルシューティングを開いて詳細を確認してください。", + "SyncApp.state.needsAttention.npcapBody": "キャプチャ方式が Npcap に設定されていますが、この PC には Npcap がインストールされていません。npcap.com からインストールするか、設定で RAW ソケットに戻してください。", "SyncApp.action.signIn": "ARCTracker にサインイン", "SyncApp.action.cancel": "キャンセル", "SyncApp.action.chooseGame": "ARC Raiders を選択", "SyncApp.action.prepareLauncher": "%{launcher} を準備", "SyncApp.action.whatDoesThisDo": "これは何をするのですか?", "SyncApp.action.closeLauncher": "%{launcher} を閉じる", + "SyncApp.action.viewStash": "ストレージを表示", "SyncApp.action.hideToTray": "トレイに隠す", "SyncApp.action.getHelp": "ヘルプを表示", "SyncApp.action.tryAgain": "もう一度試す", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "言語", "SyncApp.settings.displayLanguage": "表示言語", "SyncApp.settings.matchesWindows": "デフォルトで Windows に合わせます", + "SyncApp.settings.matchWindows": "Windows に合わせる", "SyncApp.settings.network": "ネットワーク", "SyncApp.settings.networkAdapter": "ネットワークアダプター", "SyncApp.settings.networkAdapterSub": "自動選択。同期が接続されない場合のみ変更してください。", "SyncApp.settings.refresh": "更新", + "SyncApp.settings.captureMethod": "キャプチャ方式", + "SyncApp.settings.captureMethodSub": "Sync が PC 自身のゲームトラフィックを読み取る方法です。ウイルス対策ソフトが内蔵の方式をブロックする場合は Npcap に切り替えてください。VPN またはプロキシを使用している場合は、さらに動作が良くなる可能性があります。", + "SyncApp.settings.captureRawSockets": "Windows RAW ソケット(内蔵)", + "SyncApp.settings.captureNpcap": "Npcap(別途インストール)", + "SyncApp.settings.npcapMissing": "Npcap がインストールされていないため、同期はトラフィックをキャプチャできません。インストール後、メイン画面の「もう一度試す」を使用してください。", + "SyncApp.settings.npcapLink": "npcap.com で Npcap(無料)を入手", "SyncApp.settings.troubleshooting": "トラブルシューティング", "SyncApp.settings.activityLog": "アクティビティログ", "SyncApp.settings.activityLogSub": "最近のイベント(サポート用)", "SyncApp.settings.view": "表示", + "SyncApp.settings.hide": "非表示", "SyncApp.settings.copyDiagnostics": "診断情報をコピー", "SyncApp.settings.copyDiagnosticsSub": "ARCTracker サポートと共有する", "SyncApp.settings.copy": "コピー", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "アップデートを確認", + "SyncApp.settings.whatIsSync": "同期は何をするのですか?", + "SyncApp.settings.quit": "ARCTracker Sync を終了", "SyncApp.tray.open": "ARCTracker Sync を開く", "SyncApp.tray.pause": "同期を一時停止", "SyncApp.tray.resume": "同期を再開", diff --git a/locales/ko.json b/locales/ko.json index 32d0c0e..97d9c9d 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "런처 준비됨", "SyncApp.progress.playing": "플레이 중", "SyncApp.progress.synced": "동기화됨", + "SyncApp.phase.account.label": "계정", + "SyncApp.phase.account.sub": "ARCTracker 연결", + "SyncApp.phase.launcher.label": "런처", + "SyncApp.phase.launcher.sub": "%{launcher} 준비", + "SyncApp.phase.play.label": "플레이", + "SyncApp.phase.play.sub": "ARC Raiders 시작", + "SyncApp.phase.sync.label": "동기화", + "SyncApp.phase.sync.sub": "인벤토리 최신 상태 유지", + "SyncApp.hero.step": "%{n}단계 / 4", "SyncApp.footer.signedInAs": "%{account}으로 로그인됨", + "SyncApp.footer.synced": "동기화됨 · %{account}", + "SyncApp.footer.syncedLabel": "동기화됨 ·", "SyncApp.footer.notSignedIn": "로그인하지 않음", "SyncApp.footer.settings": "설정", "SyncApp.state.needsAdmin.title": "먼저 권한이 필요합니다", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker는 플레이 중 ARC Raiders 인벤토리를 읽을 수 있도록 %{launcher}를 재시작합니다. %{launcher} 게임, 다운로드 및 로그인은 영향을 받지 않습니다.", "SyncApp.state.preparingLauncher.title": "%{launcher} 준비 중…", "SyncApp.state.preparingLauncher.body": "%{launcher}을 닫고 다시 열고 있습니다. 이는 몇 초가 걸립니다.", + "SyncApp.state.preparingLauncher.waiting": "%{launcher} 준비 중…", "SyncApp.state.closeLauncher.title": "계속하려면 %{launcher}을 닫으세요", "SyncApp.state.closeLauncher.body": "ARCTracker가 %{launcher}를 준비할 수 있도록 %{launcher}을 닫아야 합니다. 진행 중인 작업을 저장한 후 닫으세요.", "SyncApp.state.launcherReady.title": "%{launcher}이 준비되었습니다. 플레이하세요.", "SyncApp.state.launcherReady.body": "언제든지 %{launcher}에서 ARC Raiders를 시작하세요. 플레이 중에 인벤토리가 자동으로 동기화됩니다.", "SyncApp.state.connecting.title": "ARC Raiders 계정을 찾는 중…", "SyncApp.state.connecting.body": "ARC Raiders를 열어 두세요. 보통 메인 메뉴에 도달한 후 몇 초 후에 연결됩니다.", + "SyncApp.state.connecting.waiting": "ARC Raiders를 기다리는 중…", "SyncApp.state.updating.title": "ARCTracker 업데이트 중…", "SyncApp.state.updating.body": "거의 다 왔습니다. 계정을 저장하는 중입니다.", + "SyncApp.state.updating.waiting": "보관함을 저장하는 중…", "SyncApp.state.synced.title": "동기화되었습니다", "SyncApp.state.synced.body": "%{account}(으)로 플레이 중입니다. ARC Raiders 인벤토리가 ARCTracker에서 최신 상태입니다.", "SyncApp.state.synced.session": "인벤토리는 %{time}까지 동기화된 상태를 유지합니다.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher}이 자체적으로 재시작되었기 때문에 ARCTracker가 지금 인벤토리를 읽을 수 없습니다. 동기화를 계속하려면 다시 준비하세요.", "SyncApp.state.needsAttention.title": "동기화에 주의가 필요합니다", "SyncApp.state.needsAttention.body": "ARCTracker Sync에서 연결 문제가 발생했습니다. 문제 해결을 열어 세부 정보를 확인하세요.", + "SyncApp.state.needsAttention.npcapBody": "캡처 방식이 Npcap으로 설정되어 있지만 이 PC에는 Npcap이 설치되어 있지 않습니다. npcap.com에서 설치하거나 설정에서 원시 소켓으로 다시 전환하세요.", "SyncApp.action.signIn": "ARCTracker에 로그인", "SyncApp.action.cancel": "취소", "SyncApp.action.chooseGame": "ARC Raiders 선택", "SyncApp.action.prepareLauncher": "%{launcher} 준비", "SyncApp.action.whatDoesThisDo": "이것이 무엇을 하나요?", "SyncApp.action.closeLauncher": "%{launcher} 닫기", + "SyncApp.action.viewStash": "보관함 보기", "SyncApp.action.hideToTray": "트레이로 숨기기", "SyncApp.action.getHelp": "도움말 보기", "SyncApp.action.tryAgain": "다시 시도", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "언어", "SyncApp.settings.displayLanguage": "표시 언어", "SyncApp.settings.matchesWindows": "기본적으로 Windows와 일치", + "SyncApp.settings.matchWindows": "Windows와 일치", "SyncApp.settings.network": "네트워크", "SyncApp.settings.networkAdapter": "네트워크 어댑터", "SyncApp.settings.networkAdapterSub": "자동 선택. 동기화가 연결되지 않으면 변경하세요.", "SyncApp.settings.refresh": "새로 고침", + "SyncApp.settings.captureMethod": "캡처 방식", + "SyncApp.settings.captureMethodSub": "Sync가 PC 자체의 게임 트래픽을 읽는 방식입니다. 바이러스 백신 소프트웨어가 기본 제공 방식을 차단하는 경우 Npcap으로 전환하세요. VPN 또는 프록시를 사용하는 경우 더 잘 작동할 수 있습니다.", + "SyncApp.settings.captureRawSockets": "Windows 원시 소켓(기본 제공)", + "SyncApp.settings.captureNpcap": "Npcap(별도 설치)", + "SyncApp.settings.npcapMissing": "Npcap이 설치되어 있지 않아 동기화가 트래픽을 캡처할 수 없습니다. 설치한 후 메인 화면에서 '다시 시도'를 사용하세요.", + "SyncApp.settings.npcapLink": "npcap.com에서 Npcap(무료) 받기", "SyncApp.settings.troubleshooting": "문제 해결", "SyncApp.settings.activityLog": "활동 로그", "SyncApp.settings.activityLogSub": "최근 이벤트, 지원용", "SyncApp.settings.view": "보기", + "SyncApp.settings.hide": "숨기기", "SyncApp.settings.copyDiagnostics": "진단 복사", "SyncApp.settings.copyDiagnosticsSub": "ARCTracker 지원팀과 공유", "SyncApp.settings.copy": "복사", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "업데이트 확인", + "SyncApp.settings.whatIsSync": "동기화는 무엇을 하나요?", + "SyncApp.settings.quit": "ARCTracker Sync 종료", "SyncApp.tray.open": "ARCTracker Sync 열기", "SyncApp.tray.pause": "동기화 일시 중지", "SyncApp.tray.resume": "동기화 재개", diff --git a/locales/no.json b/locales/no.json index af77bbf..8f58d48 100644 --- a/locales/no.json +++ b/locales/no.json @@ -6,6 +6,17 @@ "SyncApp.progress.signedIn": "Logget inn", "SyncApp.progress.launcherReady": "Launcher klar", "SyncApp.progress.playing": "Spiller", + "SyncApp.phase.account.label": "Konto", + "SyncApp.phase.account.sub": "Koble til ARCTracker", + "SyncApp.phase.launcher.label": "Launcher", + "SyncApp.phase.launcher.sub": "Forbered %{launcher}", + "SyncApp.phase.play.label": "Spill", + "SyncApp.phase.play.sub": "Start ARC Raiders", + "SyncApp.phase.sync.label": "Synk", + "SyncApp.phase.sync.sub": "Hold inventaret oppdatert", + "SyncApp.hero.step": "Trinn %{n} av 4", + "SyncApp.footer.synced": "Synkronisert · %{account}", + "SyncApp.footer.syncedLabel": "Synkronisert ·", "SyncApp.progress.synced": "Synkronisert", "SyncApp.footer.signedInAs": "Logget inn som %{account}", "SyncApp.footer.notSignedIn": "Ikke logget inn", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker starter %{launcher} på nytt slik at det kan lese ARC Raiders-inventaret ditt mens du spiller. %{launcher}-spillene dine, nedlastingene og påloggingene berøres ikke.", "SyncApp.state.preparingLauncher.title": "Forbereder %{launcher}…", "SyncApp.state.preparingLauncher.body": "Lukker og åpner %{launcher} på nytt. Dette tar et par sekunder.", + "SyncApp.state.preparingLauncher.waiting": "Forbereder %{launcher}…", "SyncApp.state.closeLauncher.title": "Lukk %{launcher} for å fortsette", "SyncApp.state.closeLauncher.body": "%{launcher} må lukkes slik at ARCTracker kan forberede det. Lagre alt som er i gang, og lukk det deretter.", "SyncApp.state.launcherReady.title": "%{launcher} er klar. Gå og spill.", "SyncApp.state.launcherReady.body": "Start ARC Raiders fra %{launcher} når som helst. Inventaret ditt synkroniseres automatisk mens du spiller.", "SyncApp.state.connecting.title": "Søker etter ARC Raiders-kontoen din…", "SyncApp.state.connecting.body": "Hold ARC Raiders åpen. Dette kobles vanligvis til et par sekunder etter at du når hovedmenyen.", + "SyncApp.state.connecting.waiting": "Venter på ARC Raiders…", "SyncApp.state.updating.title": "Oppdaterer ARCTracker…", "SyncApp.state.updating.body": "Nesten ferdig. Lagrer kontoen din.", + "SyncApp.state.updating.waiting": "Lagrer inventaret ditt…", "SyncApp.state.synced.title": "Du er synkronisert", "SyncApp.state.synced.body": "Spiller som %{account}. ARC Raiders-inventaret ditt er oppdatert på ARCTracker.", "SyncApp.state.synced.session": "Inventaret ditt forblir synkronisert til %{time}.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} ble startet på nytt av seg selv, så ARCTracker kan ikke lese inventaret ditt nå. Forbered det igjen for å fortsette synkroniseringen.", "SyncApp.state.needsAttention.title": "Synkronisering trenger oppmerksomhet", "SyncApp.state.needsAttention.body": "ARCTracker Sync fikk et problem med tilkobling. Åpne feilsøking for detaljer.", + "SyncApp.state.needsAttention.npcapBody": "Fangstmetoden er satt til Npcap, men Npcap er ikke installert på denne PC-en. Installer det fra npcap.com, eller bytt tilbake til raw sockets i Innstillinger.", "SyncApp.action.signIn": "Logg inn på ARCTracker", "SyncApp.action.cancel": "Avbryt", "SyncApp.action.chooseGame": "Velg ARC Raiders", "SyncApp.action.prepareLauncher": "Forbered %{launcher}", "SyncApp.action.whatDoesThisDo": "Hva gjør dette?", "SyncApp.action.closeLauncher": "Lukk %{launcher}", + "SyncApp.action.viewStash": "Vis inventaret ditt", "SyncApp.action.hideToTray": "Skjul i systemkurv", "SyncApp.action.getHelp": "Få hjelp", "SyncApp.action.tryAgain": "Prøv igjen", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Språk", "SyncApp.settings.displayLanguage": "Visningsspråk", "SyncApp.settings.matchesWindows": "Samsvarer med Windows som standard", + "SyncApp.settings.matchWindows": "Samsvarer med Windows", "SyncApp.settings.network": "Nettverk", "SyncApp.settings.networkAdapter": "Nettverkskort", "SyncApp.settings.networkAdapterSub": "Automatisk valgt. Endre bare hvis synkronisering ikke kobles til.", "SyncApp.settings.refresh": "Oppdater", + "SyncApp.settings.captureMethod": "Fangstmetode", + "SyncApp.settings.captureMethodSub": "Hvordan Sync leser PC-ens egen spilltrafikk. Bytt til Npcap hvis antivirusprogramvare blokkerer den innebygde metoden — det kan også fungere bedre hvis du bruker en VPN eller proxy.", + "SyncApp.settings.captureRawSockets": "Windows raw sockets (innebygd)", + "SyncApp.settings.captureNpcap": "Npcap (installeres separat)", + "SyncApp.settings.npcapMissing": "Npcap er ikke installert, så synkronisering kan ikke fange opp trafikk. Installer det, og bruk deretter Prøv igjen på hovedskjermen.", + "SyncApp.settings.npcapLink": "Hent Npcap (gratis) på npcap.com", "SyncApp.settings.troubleshooting": "Feilsøking", "SyncApp.settings.activityLog": "Aktivitetslogg", "SyncApp.settings.activityLogSub": "Nylige hendelser, for kundestøtte", "SyncApp.settings.view": "Vis", + "SyncApp.settings.hide": "Skjul", "SyncApp.settings.copyDiagnostics": "Kopier diagnostikk", "SyncApp.settings.copyDiagnosticsSub": "Del med ARCTracker-kundestøtte", "SyncApp.settings.copy": "Kopier", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Se etter oppdateringer", + "SyncApp.settings.whatIsSync": "Hva gjør Synk?", + "SyncApp.settings.quit": "Avslutt ARCTracker Sync", "SyncApp.tray.open": "Åpne ARCTracker Sync", "SyncApp.tray.pause": "Pause synkronisering", "SyncApp.tray.resume": "Gjenoppta synkronisering", diff --git a/locales/pl.json b/locales/pl.json index 7d750d1..eb01bf7 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -6,6 +6,17 @@ "SyncApp.progress.signedIn": "Zalogowany", "SyncApp.progress.launcherReady": "Launcher gotowy", "SyncApp.progress.playing": "Grając", + "SyncApp.phase.account.label": "Konto", + "SyncApp.phase.account.sub": "Połącz ARCTracker", + "SyncApp.phase.launcher.label": "Launcher", + "SyncApp.phase.launcher.sub": "Przygotuj %{launcher}", + "SyncApp.phase.play.label": "Graj", + "SyncApp.phase.play.sub": "Uruchom ARC Raiders", + "SyncApp.phase.sync.label": "Synchronizacja", + "SyncApp.phase.sync.sub": "Utrzymuj ekwipunek aktualny", + "SyncApp.hero.step": "Krok %{n} z 4", + "SyncApp.footer.synced": "Zsynchronizowany · %{account}", + "SyncApp.footer.syncedLabel": "Zsynchronizowany ·", "SyncApp.progress.synced": "Zsynchronizowany", "SyncApp.footer.signedInAs": "Zalogowany jako %{account}", "SyncApp.footer.notSignedIn": "Niezalogowany", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker uruchamia %{launcher} ponownie, aby mógł czytać twój ekwipunek ARC Raiders podczas gry. Twoje gry %{launcher}, pobierania i logowania nie będą dotknięte.", "SyncApp.state.preparingLauncher.title": "Przygotowywanie %{launcher}…", "SyncApp.state.preparingLauncher.body": "Zamykanie i ponowne otwieranie %{launcher}. To zajmuje kilka sekund.", + "SyncApp.state.preparingLauncher.waiting": "Przygotowywanie %{launcher}…", "SyncApp.state.closeLauncher.title": "Zamknij %{launcher}, aby kontynuować", "SyncApp.state.closeLauncher.body": "%{launcher} musi się zamknąć, aby ARCTracker mógł go przygotować. Zapisz wszystko w toku, a następnie zamknij.", "SyncApp.state.launcherReady.title": "%{launcher} jest gotowy. Czas grać.", "SyncApp.state.launcherReady.body": "Uruchom ARC Raiders z %{launcher} kiedy chcesz. Twój ekwipunek synchronizuje się automatycznie podczas gry.", "SyncApp.state.connecting.title": "Szukanie twojego konta ARC Raiders…", "SyncApp.state.connecting.body": "Trzymaj ARC Raiders otwarte. Zwykle łączy się kilka sekund po dotarciu do głównego menu.", + "SyncApp.state.connecting.waiting": "Oczekiwanie na ARC Raiders…", "SyncApp.state.updating.title": "Aktualizowanie ARCTracker…", "SyncApp.state.updating.body": "Prawie gotowe. Zapisywanie twojego konta.", + "SyncApp.state.updating.waiting": "Zapisywanie twojego ekwipunku…", "SyncApp.state.synced.title": "Jesteś zsynchronizowany", "SyncApp.state.synced.body": "Grasz jako %{account}. Twój ekwipunek ARC Raiders jest aktualny w ARCTracker.", "SyncApp.state.synced.session": "Twój ekwipunek pozostaje zsynchronizowany do %{time}.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} został uruchomiony ponownie samodzielnie, więc ARCTracker nie może w tej chwili czytać twojego ekwipunku. Przygotuj go ponownie, aby kontynuować synchronizowanie.", "SyncApp.state.needsAttention.title": "Synchronizowanie wymaga uwagi", "SyncApp.state.needsAttention.body": "ARCTracker Sync napotkał problem przy łączeniu. Otwórz rozwiązywanie problemów, aby uzyskać szczegóły.", + "SyncApp.state.needsAttention.npcapBody": "Metoda przechwytywania jest ustawiona na Npcap, ale Npcap nie jest zainstalowany na tym komputerze. Zainstaluj go ze strony npcap.com lub przełącz z powrotem na surowe gniazda w Ustawieniach.", "SyncApp.action.signIn": "Zaloguj się do ARCTracker", "SyncApp.action.cancel": "Anuluj", "SyncApp.action.chooseGame": "Wybierz ARC Raiders", "SyncApp.action.prepareLauncher": "Przygotuj %{launcher}", "SyncApp.action.whatDoesThisDo": "Co to robi?", "SyncApp.action.closeLauncher": "Zamknij %{launcher}", + "SyncApp.action.viewStash": "Wyświetl swój ekwipunek", "SyncApp.action.hideToTray": "Ukryj w zasobniku", "SyncApp.action.getHelp": "Uzyskaj pomoc", "SyncApp.action.tryAgain": "Spróbuj ponownie", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Język", "SyncApp.settings.displayLanguage": "Język wyświetlania", "SyncApp.settings.matchesWindows": "Domyślnie dopasowuje się do Windows", + "SyncApp.settings.matchWindows": "Dopasuj do Windows", "SyncApp.settings.network": "Sieć", "SyncApp.settings.networkAdapter": "Adapter sieciowy", "SyncApp.settings.networkAdapterSub": "Auto-wybrany. Zmień tylko jeśli synchronizowanie się nie łączy.", "SyncApp.settings.refresh": "Odśwież", + "SyncApp.settings.captureMethod": "Metoda przechwytywania", + "SyncApp.settings.captureMethodSub": "Sposób, w jaki Sync odczytuje ruch gry z twojego komputera. Przełącz na Npcap, jeśli oprogramowanie antywirusowe blokuje wbudowaną metodę — może działać też lepiej, jeśli używasz VPN lub proxy.", + "SyncApp.settings.captureRawSockets": "Surowe gniazda Windows (wbudowane)", + "SyncApp.settings.captureNpcap": "Npcap (instalowany osobno)", + "SyncApp.settings.npcapMissing": "Npcap nie jest zainstalowany, więc synchronizowanie nie może przechwytywać ruchu. Zainstaluj go, a następnie użyj Spróbuj ponownie na głównym ekranie.", + "SyncApp.settings.npcapLink": "Pobierz Npcap (bezpłatnie) ze strony npcap.com", "SyncApp.settings.troubleshooting": "Rozwiązywanie problemów", "SyncApp.settings.activityLog": "Dziennik aktywności", "SyncApp.settings.activityLogSub": "Ostatnie zdarzenia dla wsparcia", "SyncApp.settings.view": "Wyświetl", + "SyncApp.settings.hide": "Ukryj", "SyncApp.settings.copyDiagnostics": "Skopiuj diagnostykę", "SyncApp.settings.copyDiagnosticsSub": "Udostępnij wsparciu ARCTracker", "SyncApp.settings.copy": "Skopiuj", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Sprawdź aktualizacje", + "SyncApp.settings.whatIsSync": "Co robi Synchronizacja?", + "SyncApp.settings.quit": "Wyjdź z ARCTracker Sync", "SyncApp.tray.open": "Otwórz ARCTracker Sync", "SyncApp.tray.pause": "Wstrzymaj synchronizowanie", "SyncApp.tray.resume": "Wznów synchronizowanie", diff --git a/locales/pt-BR.json b/locales/pt-BR.json index 5970c9c..66434c9 100644 --- a/locales/pt-BR.json +++ b/locales/pt-BR.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "Inicializador pronto", "SyncApp.progress.playing": "Jogando", "SyncApp.progress.synced": "Sincronizado", + "SyncApp.phase.account.label": "Conta", + "SyncApp.phase.account.sub": "Conectar ARCTracker", + "SyncApp.phase.launcher.label": "Inicializador", + "SyncApp.phase.launcher.sub": "Preparar %{launcher}", + "SyncApp.phase.play.label": "Jogar", + "SyncApp.phase.play.sub": "Inicie o ARC Raiders", + "SyncApp.phase.sync.label": "Sincronizar", + "SyncApp.phase.sync.sub": "Manter inventário atualizado", + "SyncApp.hero.step": "Passo %{n} de 4", "SyncApp.footer.signedInAs": "Conectado como %{account}", + "SyncApp.footer.synced": "Sincronizado · %{account}", + "SyncApp.footer.syncedLabel": "Sincronizado ·", "SyncApp.footer.notSignedIn": "Não conectado", "SyncApp.footer.settings": "Configurações", "SyncApp.state.needsAdmin.title": "Uma permissão rápida primeiro", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker reinicia %{launcher} para que possa ler seu inventário do ARC Raiders enquanto você joga. Seus jogos, downloads e logins do %{launcher} não serão alterados.", "SyncApp.state.preparingLauncher.title": "Preparando %{launcher}…", "SyncApp.state.preparingLauncher.body": "Fechando e reabrindo %{launcher}. Isso leva alguns segundos.", + "SyncApp.state.preparingLauncher.waiting": "Preparando %{launcher}…", "SyncApp.state.closeLauncher.title": "Feche %{launcher} para continuar", "SyncApp.state.closeLauncher.body": "%{launcher} precisa fechar para que ARCTracker possa prepará-lo. Salve qualquer progresso em andamento e feche-o.", "SyncApp.state.launcherReady.title": "%{launcher} está pronto. Bora jogar.", "SyncApp.state.launcherReady.body": "Inicie o ARC Raiders a partir de %{launcher} quando quiser. Seu inventário é sincronizado automaticamente enquanto você joga.", "SyncApp.state.connecting.title": "Procurando sua conta do ARC Raiders…", "SyncApp.state.connecting.body": "Mantenha o ARC Raiders aberto. Geralmente conecta alguns segundos depois que você alcança o menu principal.", + "SyncApp.state.connecting.waiting": "Aguardando ARC Raiders…", "SyncApp.state.updating.title": "Atualizando ARCTracker…", "SyncApp.state.updating.body": "Já está quase pronto. Salvando sua conta.", + "SyncApp.state.updating.waiting": "Salvando seu inventário…", "SyncApp.state.synced.title": "Você está sincronizado", "SyncApp.state.synced.body": "Jogando como %{account}. Seu inventário do ARC Raiders está atualizado no ARCTracker.", "SyncApp.state.synced.session": "Seu inventário fica sincronizado até %{time}.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} foi reiniciado sozinho, então ARCTracker não consegue ler seu inventário agora. Prepare-o novamente para continuar sincronizando.", "SyncApp.state.needsAttention.title": "Sincronização precisa de atenção", "SyncApp.state.needsAttention.body": "ARCTracker Sync encontrou um problema ao conectar. Abra a solução de problemas para obter detalhes.", + "SyncApp.state.needsAttention.npcapBody": "O método de captura está definido como Npcap, mas o Npcap não está instalado neste PC. Instale-o em npcap.com ou volte para os sockets brutos nas Configurações.", "SyncApp.action.signIn": "Conectar ao ARCTracker", "SyncApp.action.cancel": "Cancelar", "SyncApp.action.chooseGame": "Escolher ARC Raiders", "SyncApp.action.prepareLauncher": "Preparar %{launcher}", "SyncApp.action.whatDoesThisDo": "O que faz isso?", "SyncApp.action.closeLauncher": "Fechar %{launcher}", + "SyncApp.action.viewStash": "Ver seu inventário", "SyncApp.action.hideToTray": "Ocultar na bandeja", "SyncApp.action.getHelp": "Obter ajuda", "SyncApp.action.tryAgain": "Tentar novamente", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Idioma", "SyncApp.settings.displayLanguage": "Idioma de exibição", "SyncApp.settings.matchesWindows": "Corresponde ao Windows por padrão", + "SyncApp.settings.matchWindows": "Corresponder ao Windows", "SyncApp.settings.network": "Rede", "SyncApp.settings.networkAdapter": "Adaptador de rede", "SyncApp.settings.networkAdapterSub": "Auto-selecionado. Mude apenas se a sincronização não conectar.", "SyncApp.settings.refresh": "Atualizar", + "SyncApp.settings.captureMethod": "Método de captura", + "SyncApp.settings.captureMethodSub": "Como o Sync lê o tráfego de jogo do seu próprio PC. Mude para o Npcap se um antivírus bloquear o método integrado — também pode funcionar melhor se você usar um VPN ou proxy.", + "SyncApp.settings.captureRawSockets": "Sockets brutos do Windows (integrado)", + "SyncApp.settings.captureNpcap": "Npcap (instalado separadamente)", + "SyncApp.settings.npcapMissing": "O Npcap não está instalado, então a sincronização não consegue capturar o tráfego. Instale-o e depois use Tentar novamente na tela principal.", + "SyncApp.settings.npcapLink": "Baixe o Npcap (grátis) em npcap.com", "SyncApp.settings.troubleshooting": "Solução de problemas", "SyncApp.settings.activityLog": "Registro de atividades", "SyncApp.settings.activityLogSub": "Eventos recentes, para suporte", "SyncApp.settings.view": "Visualizar", + "SyncApp.settings.hide": "Ocultar", "SyncApp.settings.copyDiagnostics": "Copiar diagnóstico", "SyncApp.settings.copyDiagnosticsSub": "Compartilhe com o suporte ARCTracker", "SyncApp.settings.copy": "Copiar", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Verificar atualizações", + "SyncApp.settings.whatIsSync": "O que Sync faz?", + "SyncApp.settings.quit": "Sair do ARCTracker Sync", "SyncApp.tray.open": "Abrir ARCTracker Sync", "SyncApp.tray.pause": "Pausar sincronização", "SyncApp.tray.resume": "Retomar sincronização", diff --git a/locales/pt.json b/locales/pt.json index 76970d6..b06f1b0 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "Iniciador pronto", "SyncApp.progress.playing": "A jogar", "SyncApp.progress.synced": "Sincronizado", + "SyncApp.phase.account.label": "Conta", + "SyncApp.phase.account.sub": "Conectar ARCTracker", + "SyncApp.phase.launcher.label": "Iniciador", + "SyncApp.phase.launcher.sub": "Preparar %{launcher}", + "SyncApp.phase.play.label": "Jogar", + "SyncApp.phase.play.sub": "Inicia ARC Raiders", + "SyncApp.phase.sync.label": "Sincronizar", + "SyncApp.phase.sync.sub": "Manter inventário atualizado", + "SyncApp.hero.step": "Passo %{n} de 4", "SyncApp.footer.signedInAs": "Sessão iniciada como %{account}", + "SyncApp.footer.synced": "Sincronizado · %{account}", + "SyncApp.footer.syncedLabel": "Sincronizado ·", "SyncApp.footer.notSignedIn": "Sem sessão iniciada", "SyncApp.footer.settings": "Definições", "SyncApp.state.needsAdmin.title": "Uma permissão rápida primeiro", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker reinicia %{launcher} para que possa ler o teu inventário de ARC Raiders enquanto jogas. Os teus jogos, transferências e sessões %{launcher} não são afetados.", "SyncApp.state.preparingLauncher.title": "A preparar %{launcher}…", "SyncApp.state.preparingLauncher.body": "A fechar e reabrir %{launcher}. Isto demora alguns segundos.", + "SyncApp.state.preparingLauncher.waiting": "A preparar %{launcher}…", "SyncApp.state.closeLauncher.title": "Fecha %{launcher} para continuar", "SyncApp.state.closeLauncher.body": "%{launcher} precisa de fechar para que ARCTracker o possa preparar. Guarda o teu progresso e fecha-o.", "SyncApp.state.launcherReady.title": "%{launcher} está pronto. Vai jogar.", "SyncApp.state.launcherReady.body": "Inicia ARC Raiders a partir de %{launcher} sempre que quiseres. O teu inventário sincroniza-se automaticamente enquanto jogas.", "SyncApp.state.connecting.title": "À procura da tua conta ARC Raiders…", "SyncApp.state.connecting.body": "Mantém ARC Raiders aberto. Isto normalmente conecta alguns segundos depois de atingires o menu principal.", + "SyncApp.state.connecting.waiting": "À espera de ARC Raiders…", "SyncApp.state.updating.title": "A atualizar ARCTracker…", "SyncApp.state.updating.body": "Quase lá. A guardar a tua conta.", + "SyncApp.state.updating.waiting": "A guardar o teu inventário…", "SyncApp.state.synced.title": "Estás sincronizado", "SyncApp.state.synced.body": "A jogar como %{account}. O teu inventário de ARC Raiders está atualizado no ARCTracker.", "SyncApp.state.synced.session": "O teu inventário mantém-se sincronizado até %{time}.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} foi reiniciado por conta própria, por isso ARCTracker não consegue ler o teu inventário neste momento. Prepara-o novamente para continuar a sincronizar.", "SyncApp.state.needsAttention.title": "A sincronização precisa de atenção", "SyncApp.state.needsAttention.body": "ARCTracker Sync encontrou um problema ao conectar. Abre a resolução de problemas para mais detalhes.", + "SyncApp.state.needsAttention.npcapBody": "O método de captura está definido como Npcap, mas o Npcap não está instalado neste PC. Instala-o a partir de npcap.com ou volta aos sockets em bruto nas Definições.", "SyncApp.action.signIn": "Inicia sessão no ARCTracker", "SyncApp.action.cancel": "Cancelar", "SyncApp.action.chooseGame": "Escolhe ARC Raiders", "SyncApp.action.prepareLauncher": "Prepara %{launcher}", "SyncApp.action.whatDoesThisDo": "O que é que isto faz?", "SyncApp.action.closeLauncher": "Fecha %{launcher}", + "SyncApp.action.viewStash": "Ver o teu inventário", "SyncApp.action.hideToTray": "Oculta para a bandeja", "SyncApp.action.getHelp": "Obter ajuda", "SyncApp.action.tryAgain": "Tenta novamente", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Idioma", "SyncApp.settings.displayLanguage": "Idioma de apresentação", "SyncApp.settings.matchesWindows": "Corresponde a Windows por predefinição", + "SyncApp.settings.matchWindows": "Correspondência Windows", "SyncApp.settings.network": "Rede", "SyncApp.settings.networkAdapter": "Adaptador de rede", "SyncApp.settings.networkAdapterSub": "Auto-selecionado. Altera apenas se sync não conectar.", "SyncApp.settings.refresh": "Atualizar", + "SyncApp.settings.captureMethod": "Método de captura", + "SyncApp.settings.captureMethodSub": "Como Sync lê o tráfego de jogo do teu próprio PC. Muda para Npcap se um antivírus bloquear o método integrado — também pode funcionar melhor se usares um VPN ou proxy.", + "SyncApp.settings.captureRawSockets": "Sockets em bruto do Windows (integrado)", + "SyncApp.settings.captureNpcap": "Npcap (instalado separadamente)", + "SyncApp.settings.npcapMissing": "Npcap não está instalado, por isso a sincronização não consegue capturar tráfego. Instala-o e depois usa Tenta novamente no ecrã principal.", + "SyncApp.settings.npcapLink": "Obtém Npcap (gratuito) em npcap.com", "SyncApp.settings.troubleshooting": "Resolução de problemas", "SyncApp.settings.activityLog": "Registo de atividade", "SyncApp.settings.activityLogSub": "Eventos recentes, para suporte", "SyncApp.settings.view": "Ver", + "SyncApp.settings.hide": "Ocultar", "SyncApp.settings.copyDiagnostics": "Copia diagnósticos", "SyncApp.settings.copyDiagnosticsSub": "Partilha com suporte ARCTracker", "SyncApp.settings.copy": "Copiar", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Verifica atualizações", + "SyncApp.settings.whatIsSync": "O que faz Sync?", + "SyncApp.settings.quit": "Sair do ARCTracker Sync", "SyncApp.tray.open": "Abre ARCTracker Sync", "SyncApp.tray.pause": "Pausa sincronização", "SyncApp.tray.resume": "Retoma sincronização", diff --git a/locales/ru.json b/locales/ru.json index f0bb69b..e0e3111 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "Лаунчер готов", "SyncApp.progress.playing": "Играет", "SyncApp.progress.synced": "Синхронизировано", + "SyncApp.phase.account.label": "Учётная запись", + "SyncApp.phase.account.sub": "Подключить ARCTracker", + "SyncApp.phase.launcher.label": "Лаунчер", + "SyncApp.phase.launcher.sub": "Подготовить %{launcher}", + "SyncApp.phase.play.label": "Играть", + "SyncApp.phase.play.sub": "Запустить ARC Raiders", + "SyncApp.phase.sync.label": "Синхронизация", + "SyncApp.phase.sync.sub": "Поддерживать инвентарь в актуальном состоянии", + "SyncApp.hero.step": "Шаг %{n} из 4", "SyncApp.footer.signedInAs": "Вход как %{account}", + "SyncApp.footer.synced": "Синхронизировано · %{account}", + "SyncApp.footer.syncedLabel": "Синхронизировано ·", "SyncApp.footer.notSignedIn": "Не вошли", "SyncApp.footer.settings": "Настройки", "SyncApp.state.needsAdmin.title": "Сначала нужно разрешение", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker перезагружает %{launcher}, чтобы иметь возможность читать ваш инвентарь ARC Raiders во время игры. Ваши игры в %{launcher}, загрузки и входы не будут затронуты.", "SyncApp.state.preparingLauncher.title": "Подготовка %{launcher}…", "SyncApp.state.preparingLauncher.body": "Закрытие и перезагрузка %{launcher}. Это займёт несколько секунд.", + "SyncApp.state.preparingLauncher.waiting": "Подготовка %{launcher}…", "SyncApp.state.closeLauncher.title": "Закройте %{launcher}, чтобы продолжить", "SyncApp.state.closeLauncher.body": "%{launcher} нужно закрыть, чтобы ARCTracker мог его подготовить. Сохраните любые текущие работы, а затем закройте его.", "SyncApp.state.launcherReady.title": "%{launcher} готов. Идите играть.", "SyncApp.state.launcherReady.body": "Запустите ARC Raiders из %{launcher} в любое время. Ваш инвентарь синхронизируется автоматически во время игры.", "SyncApp.state.connecting.title": "Поиск вашей учётной записи ARC Raiders…", "SyncApp.state.connecting.body": "Держите ARC Raiders открытым. Обычно подключение происходит через несколько секунд после того, как вы достигнете главного меню.", + "SyncApp.state.connecting.waiting": "Ожидание ARC Raiders…", "SyncApp.state.updating.title": "Обновление ARCTracker…", "SyncApp.state.updating.body": "Почти готово. Сохранение вашей учётной записи.", + "SyncApp.state.updating.waiting": "Сохранение вашего инвентаря…", "SyncApp.state.synced.title": "Вы синхронизированы", "SyncApp.state.synced.body": "Играете как %{account}. Ваш инвентарь ARC Raiders актуален на ARCTracker.", "SyncApp.state.synced.session": "Ваш инвентарь остаётся синхронизированным до %{time}.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} был перезагружен самостоятельно, поэтому ARCTracker не может прочитать ваш инвентарь прямо сейчас. Подготовьте его снова, чтобы продолжить синхронизацию.", "SyncApp.state.needsAttention.title": "Синхронизация требует внимания", "SyncApp.state.needsAttention.body": "ARCTracker Sync столкнулся с проблемой при подключении. Откройте устранение неполадок для получения деталей.", + "SyncApp.state.needsAttention.npcapBody": "Метод захвата установлен на Npcap, но Npcap не установлен на этом ПК. Установите его с npcap.com или переключитесь обратно на сырые сокеты в настройках.", "SyncApp.action.signIn": "Войти в ARCTracker", "SyncApp.action.cancel": "Отмена", "SyncApp.action.chooseGame": "Выбрать ARC Raiders", "SyncApp.action.prepareLauncher": "Подготовить %{launcher}", "SyncApp.action.whatDoesThisDo": "Что это делает?", "SyncApp.action.closeLauncher": "Закрыть %{launcher}", + "SyncApp.action.viewStash": "Посмотреть ваш инвентарь", "SyncApp.action.hideToTray": "Скрыть в трей", "SyncApp.action.getHelp": "Получить помощь", "SyncApp.action.tryAgain": "Попробовать снова", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Язык", "SyncApp.settings.displayLanguage": "Язык интерфейса", "SyncApp.settings.matchesWindows": "По умолчанию совпадает с Windows", + "SyncApp.settings.matchWindows": "Совпадать с Windows", "SyncApp.settings.network": "Сеть", "SyncApp.settings.networkAdapter": "Сетевой адаптер", "SyncApp.settings.networkAdapterSub": "Выбран автоматически. Измените только если синхронизация не подключается.", "SyncApp.settings.refresh": "Обновить", + "SyncApp.settings.captureMethod": "Метод захвата", + "SyncApp.settings.captureMethodSub": "Как Sync читает собственный игровой трафик вашего ПК. Переключайтесь на Npcap, если антивирус блокирует встроенный метод — это также может работать лучше, если вы используете VPN или прокси.", + "SyncApp.settings.captureRawSockets": "Сырые сокеты Windows (встроено)", + "SyncApp.settings.captureNpcap": "Npcap (устанавливается отдельно)", + "SyncApp.settings.npcapMissing": "Npcap не установлен, поэтому синхронизация не может захватывать трафик. Установите его, а затем нажмите «Попробовать снова» на главном экране.", + "SyncApp.settings.npcapLink": "Получить Npcap (бесплатно) на npcap.com", "SyncApp.settings.troubleshooting": "Устранение неполадок", "SyncApp.settings.activityLog": "Журнал активности", "SyncApp.settings.activityLogSub": "Последние события для поддержки", "SyncApp.settings.view": "Просмотр", + "SyncApp.settings.hide": "Скрыть", "SyncApp.settings.copyDiagnostics": "Копировать диагностику", "SyncApp.settings.copyDiagnosticsSub": "Поделитесь с поддержкой ARCTracker", "SyncApp.settings.copy": "Копировать", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Проверить обновления", + "SyncApp.settings.whatIsSync": "Что делает синхронизация?", + "SyncApp.settings.quit": "Выход из ARCTracker Sync", "SyncApp.tray.open": "Открыть ARCTracker Sync", "SyncApp.tray.pause": "Паузировать синхронизацию", "SyncApp.tray.resume": "Возобновить синхронизацию", diff --git a/locales/sr.json b/locales/sr.json index 72f3c07..334dae2 100644 --- a/locales/sr.json +++ b/locales/sr.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "Pokretač je spreman", "SyncApp.progress.playing": "Igranje", "SyncApp.progress.synced": "Sinhronizovano", + "SyncApp.phase.account.label": "Nalog", + "SyncApp.phase.account.sub": "Povežite ARCTracker", + "SyncApp.phase.launcher.label": "Pokretač", + "SyncApp.phase.launcher.sub": "Pripremite %{launcher}", + "SyncApp.phase.play.label": "Igraj", + "SyncApp.phase.play.sub": "Pokrenite ARC Raiders", + "SyncApp.phase.sync.label": "Sinhronizacija", + "SyncApp.phase.sync.sub": "Održavajte inventar ažurnim", + "SyncApp.hero.step": "Korak %{n} od 4", "SyncApp.footer.signedInAs": "Prijavljeni kao %{account}", + "SyncApp.footer.synced": "Sinhronizovano · %{account}", + "SyncApp.footer.syncedLabel": "Sinhronizovano ·", "SyncApp.footer.notSignedIn": "Niste prijavljeni", "SyncApp.footer.settings": "Postavke", "SyncApp.state.needsAdmin.title": "Prvo trebate dozvolu", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker restartuje %{launcher} kako bi mogao čitati vašu ARC Raiders inventaru dok igrate. Vaši %{launcher} igre, preuzimanja i prijave nisu dodirivane.", "SyncApp.state.preparingLauncher.title": "Pripremanje %{launcher}…", "SyncApp.state.preparingLauncher.body": "Zatvaranje i ponovno otvaranje %{launcher}. Ovo traje nekoliko sekundi.", + "SyncApp.state.preparingLauncher.waiting": "Pripremanje %{launcher}…", "SyncApp.state.closeLauncher.title": "Zatvorite %{launcher} da nastavite", "SyncApp.state.closeLauncher.body": "%{launcher} se mora zatvoriti kako bi ARCTracker mogao to da pripremi. Sačuvajte sve što je u toku, zatim ga zatvorite.", "SyncApp.state.launcherReady.title": "%{launcher} je spreman. Idite da igrate.", "SyncApp.state.launcherReady.body": "Pokrenite ARC Raiders iz %{launcher} kada god želite. Vaša inventara se automatski sinhronizuje dok igrate.", "SyncApp.state.connecting.title": "Tražim vaš ARC Raiders nalog…", "SyncApp.state.connecting.body": "Čuvajte ARC Raiders otvoren. Ovo se obično povezuje nekoliko sekundi nakon što dosegnete glavni meni.", + "SyncApp.state.connecting.waiting": "Čekam ARC Raiders…", "SyncApp.state.updating.title": "Ažuriranje ARCTrackera…", "SyncApp.state.updating.body": "Skoro gotovo. Čuvanje vašeg naloga.", + "SyncApp.state.updating.waiting": "Čuvanje vašeg inventara…", "SyncApp.state.synced.title": "Sinhronizovani ste", "SyncApp.state.synced.body": "Igranje kao %{account}. Vaša ARC Raiders inventara je ažurna na ARCTracker-u.", "SyncApp.state.synced.session": "Vaša inventara ostaje sinhronizovana do %{time}.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} je sâm restartuovan, tako da ARCTracker trenutno ne može čitati vašu inventaru. Pripremite ponovo da nastavite sa sinhronizacijom.", "SyncApp.state.needsAttention.title": "Sinhronizacija trebate pažnju", "SyncApp.state.needsAttention.body": "ARCTracker Sync je nailazio na problem pri povezivanju. Otvorite rešavanje problema za više detalja.", + "SyncApp.state.needsAttention.npcapBody": "Metoda hvatanja je postavljena na Npcap, ali Npcap nije instaliran na ovom PC-u. Instalirajte ga sa npcap.com ili se vratite na sirove sokete u Postavkama.", "SyncApp.action.signIn": "Prijavite se na ARCTracker", "SyncApp.action.cancel": "Otkaži", "SyncApp.action.chooseGame": "Odaberite ARC Raiders", "SyncApp.action.prepareLauncher": "Pripremite %{launcher}", "SyncApp.action.whatDoesThisDo": "Šta ovo radi?", "SyncApp.action.closeLauncher": "Zatvorite %{launcher}", + "SyncApp.action.viewStash": "Pogledajte svoj inventar", "SyncApp.action.hideToTray": "Sakrijte u paletu", "SyncApp.action.getHelp": "Zatražite pomoć", "SyncApp.action.tryAgain": "Pokušajte ponovo", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Jezik", "SyncApp.settings.displayLanguage": "Prikazi jezik", "SyncApp.settings.matchesWindows": "Odgovara Windows po zadanom", + "SyncApp.settings.matchWindows": "Uskladi sa Windows-om", "SyncApp.settings.network": "Mreža", "SyncApp.settings.networkAdapter": "Mrežni adapter", "SyncApp.settings.networkAdapterSub": "Automatski izabran. Samo promenite ako sinhronizacija se ne povezuje.", "SyncApp.settings.refresh": "Osvežite", + "SyncApp.settings.captureMethod": "Metoda hvatanja", + "SyncApp.settings.captureMethodSub": "Kako Sync čita sopstveni promet igre vašeg PC-a. Pređite na Npcap ako antivirusni softver blokira ugrađenu metodu — može i bolje raditi ako koristite VPN ili proxy.", + "SyncApp.settings.captureRawSockets": "Windows sirovi soketi (ugrađeno)", + "SyncApp.settings.captureNpcap": "Npcap (instalira se zasebno)", + "SyncApp.settings.npcapMissing": "Npcap nije instaliran, pa sinhronizacija ne može da hvata promet. Instalirajte ga, a zatim upotrebite Pokušajte ponovo na glavnom ekranu.", + "SyncApp.settings.npcapLink": "Preuzmite Npcap (besplatno) na npcap.com", "SyncApp.settings.troubleshooting": "Rešavanje problema", "SyncApp.settings.activityLog": "Zapisnik aktivnosti", "SyncApp.settings.activityLogSub": "Skorašnji događaji, za podršku", "SyncApp.settings.view": "Pogledajte", + "SyncApp.settings.hide": "Sakrijte", "SyncApp.settings.copyDiagnostics": "Kopirajte dijagnostiku", "SyncApp.settings.copyDiagnosticsSub": "Delite sa ARCTracker podrškom", "SyncApp.settings.copy": "Kopiraj", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Proverite ažuriranja", + "SyncApp.settings.whatIsSync": "Šta Sync radi?", + "SyncApp.settings.quit": "Izlaz iz ARCTracker Sync", "SyncApp.tray.open": "Otvorite ARCTracker Sync", "SyncApp.tray.pause": "Pauziranje sinhronizacije", "SyncApp.tray.resume": "Nastavite sinhronizaciju", diff --git a/locales/tr.json b/locales/tr.json index 3356505..d31d8d1 100644 --- a/locales/tr.json +++ b/locales/tr.json @@ -6,6 +6,17 @@ "SyncApp.progress.signedIn": "Oturum açıldı", "SyncApp.progress.launcherReady": "Başlatıcı hazır", "SyncApp.progress.playing": "Oynanıyor", + "SyncApp.phase.account.label": "Hesap", + "SyncApp.phase.account.sub": "ARCTracker'ı bağlayın", + "SyncApp.phase.launcher.label": "Başlatıcı", + "SyncApp.phase.launcher.sub": "%{launcher}'ı hazırlayın", + "SyncApp.phase.play.label": "Oyna", + "SyncApp.phase.play.sub": "ARC Raiders'ı başlatın", + "SyncApp.phase.sync.label": "Senkronizasyon", + "SyncApp.phase.sync.sub": "Envanteri canlı tutun", + "SyncApp.hero.step": "%{n}. adım / 4", + "SyncApp.footer.synced": "Senkronize edildi · %{account}", + "SyncApp.footer.syncedLabel": "Senkronize edildi ·", "SyncApp.progress.synced": "Senkronize edildi", "SyncApp.footer.signedInAs": "%{account} olarak oturum açıldı", "SyncApp.footer.notSignedIn": "Oturum açılmamış", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker, oynarken ARC Raiders envanterinizi okuyabilmesi için %{launcher}'ı yeniden başlatır. %{launcher} oyunlarınız, indirmeleriniz ve oturum açışlarınız etkilenmez.", "SyncApp.state.preparingLauncher.title": "%{launcher} hazırlanıyor…", "SyncApp.state.preparingLauncher.body": "%{launcher} kapatılıp yeniden açılıyor. Bu birkaç saniye sürer.", + "SyncApp.state.preparingLauncher.waiting": "%{launcher} hazırlanıyor…", "SyncApp.state.closeLauncher.title": "Devam etmek için %{launcher}'ı kapatın", "SyncApp.state.closeLauncher.body": "ARCTracker'ın %{launcher}'ı hazırlaması için kapatılması gerekiyor. Devam eden işleri kaydedin, ardından kapatın.", "SyncApp.state.launcherReady.title": "%{launcher} hazır. Oyna.", "SyncApp.state.launcherReady.body": "%{launcher}'dan ARC Raiders'ı her zaman olduğu gibi başlatın. Oynarken envanteriniz otomatik olarak senkronize olacak.", "SyncApp.state.connecting.title": "ARC Raiders hesabınız aranıyor…", "SyncApp.state.connecting.body": "ARC Raiders'ı açık tutun. Bu genellikle ana menüye ulaştıktan birkaç saniye sonra bağlanır.", + "SyncApp.state.connecting.waiting": "ARC Raiders bekleniyor…", "SyncApp.state.updating.title": "ARCTracker güncelleniyor…", "SyncApp.state.updating.body": "Neredeyse bitti. Hesabınız kaydediliyor.", + "SyncApp.state.updating.waiting": "Envanteriniz kaydediliyor…", "SyncApp.state.synced.title": "Senkronize oldunuz", "SyncApp.state.synced.body": "%{account} olarak oynanıyor. ARC Raiders envanteriniz ARCTracker'da güncel.", "SyncApp.state.synced.session": "Envanteriniz %{time} kadar senkronize kalacak.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} kendi başına yeniden başlatıldı, bu nedenle ARCTracker şu anda envanterinizi okuyamıyor. Senkronizasyonu devam ettirmek için yeniden hazırlayın.", "SyncApp.state.needsAttention.title": "Senkronizasyon dikkat gerektiriyor", "SyncApp.state.needsAttention.body": "ARCTracker Sync bağlanırken bir sorunla karşılaştı. Ayrıntılar için sorun gidermeyi açın.", + "SyncApp.state.needsAttention.npcapBody": "Yakalama yöntemi Npcap olarak ayarlanmış, ancak Npcap bu bilgisayarda yüklü değil. npcap.com'dan yükleyin veya Ayarlar'dan ham soketlere geri dönün.", "SyncApp.action.signIn": "ARCTracker'a oturum açın", "SyncApp.action.cancel": "İptal", "SyncApp.action.chooseGame": "ARC Raiders'ı seçin", "SyncApp.action.prepareLauncher": "%{launcher}'ı hazırlayın", "SyncApp.action.whatDoesThisDo": "Bu ne yapıyor?", "SyncApp.action.closeLauncher": "%{launcher}'ı kapatın", + "SyncApp.action.viewStash": "Envanterinizi görüntüleyin", "SyncApp.action.hideToTray": "Tray'e gizle", "SyncApp.action.getHelp": "Yardım alın", "SyncApp.action.tryAgain": "Tekrar deneyin", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Dil", "SyncApp.settings.displayLanguage": "Görüntüleme dili", "SyncApp.settings.matchesWindows": "Varsayılan olarak Windows ile eşleşir", + "SyncApp.settings.matchWindows": "Windows'la eşleştir", "SyncApp.settings.network": "Ağ", "SyncApp.settings.networkAdapter": "Ağ adaptörü", "SyncApp.settings.networkAdapterSub": "Otomatik seçilir. Senkronizasyon bağlanamıyorsa değiştirin.", "SyncApp.settings.refresh": "Yenile", + "SyncApp.settings.captureMethod": "Yakalama yöntemi", + "SyncApp.settings.captureMethodSub": "Sync'in bilgisayarınızın kendi oyun trafiğini nasıl okuduğu. Antivirüs yazılımı yerleşik yöntemi engelliyorsa Npcap'e geçin — VPN veya proxy kullanıyorsanız daha iyi çalışabilir.", + "SyncApp.settings.captureRawSockets": "Windows ham soketleri (yerleşik)", + "SyncApp.settings.captureNpcap": "Npcap (ayrı olarak yüklenir)", + "SyncApp.settings.npcapMissing": "Npcap yüklü değil, bu nedenle senkronizasyon trafiği yakalayamıyor. Yükleyin, ardından ana ekrandaki Tekrar deneyin düğmesini kullanın.", + "SyncApp.settings.npcapLink": "Npcap'i (ücretsiz) npcap.com adresinden edinin", "SyncApp.settings.troubleshooting": "Sorun giderme", "SyncApp.settings.activityLog": "Etkinlik günlüğü", "SyncApp.settings.activityLogSub": "Son olaylar, destek için", "SyncApp.settings.view": "Görüntüle", + "SyncApp.settings.hide": "Gizle", "SyncApp.settings.copyDiagnostics": "Tanılamaları kopyala", "SyncApp.settings.copyDiagnosticsSub": "ARCTracker desteği ile paylaş", "SyncApp.settings.copy": "Kopyala", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Güncellemeleri denetle", + "SyncApp.settings.whatIsSync": "Senkronizasyon ne yapar?", + "SyncApp.settings.quit": "ARCTracker Sync'ten çık", "SyncApp.tray.open": "ARCTracker Sync'i aç", "SyncApp.tray.pause": "Senkronizasyonu duraklat", "SyncApp.tray.resume": "Senkronizasyonu sürdür", diff --git a/locales/uk.json b/locales/uk.json index 060f00e..e514215 100644 --- a/locales/uk.json +++ b/locales/uk.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "Засіб запуску готовий", "SyncApp.progress.playing": "Грає", "SyncApp.progress.synced": "Синхронізовано", + "SyncApp.phase.account.label": "Акаунт", + "SyncApp.phase.account.sub": "Підключити ARCTracker", + "SyncApp.phase.launcher.label": "Засіб запуску", + "SyncApp.phase.launcher.sub": "Підготувати %{launcher}", + "SyncApp.phase.play.label": "Гра", + "SyncApp.phase.play.sub": "Запустити ARC Raiders", + "SyncApp.phase.sync.label": "Синхронізація", + "SyncApp.phase.sync.sub": "Тримати інвентар актуальним", + "SyncApp.hero.step": "Крок %{n} з 4", "SyncApp.footer.signedInAs": "Вхід як %{account}", + "SyncApp.footer.synced": "Синхронізовано · %{account}", + "SyncApp.footer.syncedLabel": "Синхронізовано ·", "SyncApp.footer.notSignedIn": "Не увійшли", "SyncApp.footer.settings": "Параметри", "SyncApp.state.needsAdmin.title": "Один важливий дозвіл спочатку", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker перезапускає %{launcher}, щоб він міг читати ваш інвентар ARC Raiders під час гри. Ваші ігри %{launcher}, завантаження та входи залишаються незміненими.", "SyncApp.state.preparingLauncher.title": "Підготовка %{launcher}…", "SyncApp.state.preparingLauncher.body": "Закриття та повторне відкриття %{launcher}. Це займе кілька секунд.", + "SyncApp.state.preparingLauncher.waiting": "Підготовка %{launcher}…", "SyncApp.state.closeLauncher.title": "Закрийте %{launcher}, щоб продовжити", "SyncApp.state.closeLauncher.body": "%{launcher} потребує закриття, щоб ARCTracker міг його підготувати. Збережіть все, що у вас в процесі, а потім закрийте його.", "SyncApp.state.launcherReady.title": "%{launcher} готовий. Йдіть грати.", "SyncApp.state.launcherReady.body": "Запускайте ARC Raiders з %{launcher} коли завгодно. Ваш інвентар синхронізуватиметься автоматично під час гри.", "SyncApp.state.connecting.title": "Пошук вашого акаунта ARC Raiders…", "SyncApp.state.connecting.body": "Тримайте ARC Raiders відкритим. Зазвичай підключення відбувається кілька секунд після того, як ви дійдете до головного меню.", + "SyncApp.state.connecting.waiting": "Очікування ARC Raiders…", "SyncApp.state.updating.title": "Оновлення ARCTracker…", "SyncApp.state.updating.body": "Майже готово. Збереження вашого акаунта.", + "SyncApp.state.updating.waiting": "Збереження вашого інвентаря…", "SyncApp.state.synced.title": "Ви синхронізовані", "SyncApp.state.synced.body": "Грає як %{account}. Ваш інвентар ARC Raiders актуальний на ARCTracker.", "SyncApp.state.synced.session": "Ваш інвентар залишається синхронізованим до %{time}.", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} був перезапущений самостійно, тому ARCTracker не може прочитати ваш інвентар прямо зараз. Підготуйте його знову, щоб продовжити синхронізацію.", "SyncApp.state.needsAttention.title": "Синхронізація потребує уваги", "SyncApp.state.needsAttention.body": "ARCTracker Sync зіткнувся з проблемою підключення. Відкрийте усунення несправностей для отримання подробиць.", + "SyncApp.state.needsAttention.npcapBody": "Метод захоплення встановлено на Npcap, але Npcap не встановлений на цьому ПК. Встановіть його з npcap.com або поверніться до сирих сокетів у параметрах.", "SyncApp.action.signIn": "Увійти до ARCTracker", "SyncApp.action.cancel": "Скасувати", "SyncApp.action.chooseGame": "Виберіть ARC Raiders", "SyncApp.action.prepareLauncher": "Підготувати %{launcher}", "SyncApp.action.whatDoesThisDo": "Що це робить?", "SyncApp.action.closeLauncher": "Закрити %{launcher}", + "SyncApp.action.viewStash": "Переглянути ваш інвентар", "SyncApp.action.hideToTray": "Сховати в трей", "SyncApp.action.getHelp": "Отримати допомогу", "SyncApp.action.tryAgain": "Спробуйте ще раз", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "Мова", "SyncApp.settings.displayLanguage": "Мова інтерфейсу", "SyncApp.settings.matchesWindows": "За замовчуванням відповідає Windows", + "SyncApp.settings.matchWindows": "Відповідати Windows", "SyncApp.settings.network": "Мережа", "SyncApp.settings.networkAdapter": "Мережевий адаптер", "SyncApp.settings.networkAdapterSub": "Автоматично вибирається. Змініть, тільки якщо синхронізація не підключається.", "SyncApp.settings.refresh": "Оновити", + "SyncApp.settings.captureMethod": "Метод захоплення", + "SyncApp.settings.captureMethodSub": "Як Sync читає власний ігровий трафік вашого ПК. Переходьте на Npcap, якщо антивірус блокує вбудований метод — це також може працювати краще, якщо ви використовуєте VPN або проксі.", + "SyncApp.settings.captureRawSockets": "Сирі сокети Windows (вбудовано)", + "SyncApp.settings.captureNpcap": "Npcap (встановлюється окремо)", + "SyncApp.settings.npcapMissing": "Npcap не встановлений, тому синхронізація не може захоплювати трафік. Встановіть його, а потім натисніть «Спробуйте ще раз» на головному екрані.", + "SyncApp.settings.npcapLink": "Отримати Npcap (безкоштовно) на npcap.com", "SyncApp.settings.troubleshooting": "Усунення несправностей", "SyncApp.settings.activityLog": "Журнал активності", "SyncApp.settings.activityLogSub": "Недавні події для підтримки", "SyncApp.settings.view": "Переглянути", + "SyncApp.settings.hide": "Сховати", "SyncApp.settings.copyDiagnostics": "Скопіювати діагностику", "SyncApp.settings.copyDiagnosticsSub": "Поділіться з підтримкою ARCTracker", "SyncApp.settings.copy": "Скопіювати", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "Перевірити наявність оновлень", + "SyncApp.settings.whatIsSync": "Що робить синхронізація?", + "SyncApp.settings.quit": "Завершити ARCTracker Sync", "SyncApp.tray.open": "Відкрити ARCTracker Sync", "SyncApp.tray.pause": "Призупинити синхронізацію", "SyncApp.tray.resume": "Відновити синхронізацію", diff --git a/locales/zh-CN.json b/locales/zh-CN.json index 8db26e3..24ccf61 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "启动器已准备好", "SyncApp.progress.playing": "游戏中", "SyncApp.progress.synced": "已同步", + "SyncApp.phase.account.label": "账户", + "SyncApp.phase.account.sub": "连接 ARCTracker", + "SyncApp.phase.launcher.label": "启动器", + "SyncApp.phase.launcher.sub": "准备 %{launcher}", + "SyncApp.phase.play.label": "玩", + "SyncApp.phase.play.sub": "启动 ARC Raiders", + "SyncApp.phase.sync.label": "同步", + "SyncApp.phase.sync.sub": "保持库存最新", + "SyncApp.hero.step": "第 %{n} 步,共 4 步", "SyncApp.footer.signedInAs": "已登录为 %{account}", + "SyncApp.footer.synced": "已同步 · %{account}", + "SyncApp.footer.syncedLabel": "已同步 ·", "SyncApp.footer.notSignedIn": "未登录", "SyncApp.footer.settings": "设置", "SyncApp.state.needsAdmin.title": "需要权限", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker 会重启 %{launcher},这样它就可以在你游戏时读取你的 ARC Raiders 物品栏。你的 %{launcher} 游戏、下载和登录状态都不会受影响。", "SyncApp.state.preparingLauncher.title": "正在准备 %{launcher}…", "SyncApp.state.preparingLauncher.body": "正在关闭并重新打开 %{launcher}。这需要几秒钟。", + "SyncApp.state.preparingLauncher.waiting": "正在准备 %{launcher}…", "SyncApp.state.closeLauncher.title": "关闭 %{launcher} 继续", "SyncApp.state.closeLauncher.body": "%{launcher} 需要关闭,这样 ARCTracker 才能对其进行准备。保存正在进行的任何内容,然后关闭它。", "SyncApp.state.launcherReady.title": "%{launcher}已准备好。去玩吧。", "SyncApp.state.launcherReady.body": "随时从%{launcher}启动ARC Raiders。你的物品栏在游戏时会自动同步。", "SyncApp.state.connecting.title": "正在查找你的 ARC Raiders 账户…", "SyncApp.state.connecting.body": "保持 ARC Raiders 打开。通常在你进入主菜单后的几秒钟内会连接。", + "SyncApp.state.connecting.waiting": "正在等待 ARC Raiders…", "SyncApp.state.updating.title": "正在更新 ARCTracker…", "SyncApp.state.updating.body": "快完成了。正在保存你的账户。", + "SyncApp.state.updating.waiting": "正在保存你的库存…", "SyncApp.state.synced.title": "你已同步", "SyncApp.state.synced.body": "正在以 %{account} 的身份游玩。ARCTracker 正在保持你的 ARC Raiders 物品栏最新。", "SyncApp.state.synced.session": "你的物品栏将一直保持同步到 %{time}。", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} 被自动重启了,所以 ARCTracker 目前无法读取你的物品栏。再次准备它以继续同步。", "SyncApp.state.needsAttention.title": "同步需要关注", "SyncApp.state.needsAttention.body": "ARCTracker Sync 在连接时遇到问题。打开故障排除以查看详细信息。", + "SyncApp.state.needsAttention.npcapBody": "捕获方式已设置为 Npcap,但这台电脑上没有安装 Npcap。请从 npcap.com 安装,或在设置中切换回原始套接字。", "SyncApp.action.signIn": "登录 ARCTracker", "SyncApp.action.cancel": "取消", "SyncApp.action.chooseGame": "选择 ARC Raiders", "SyncApp.action.prepareLauncher": "准备 %{launcher}", "SyncApp.action.whatDoesThisDo": "这是做什么的?", "SyncApp.action.closeLauncher": "关闭 %{launcher}", + "SyncApp.action.viewStash": "查看你的库存", "SyncApp.action.hideToTray": "隐藏到系统托盘", "SyncApp.action.getHelp": "获取帮助", "SyncApp.action.tryAgain": "重试", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "语言", "SyncApp.settings.displayLanguage": "显示语言", "SyncApp.settings.matchesWindows": "默认与 Windows 匹配", + "SyncApp.settings.matchWindows": "与 Windows 匹配", "SyncApp.settings.network": "网络", "SyncApp.settings.networkAdapter": "网络适配器", "SyncApp.settings.networkAdapterSub": "自动选择。仅在同步无法连接时更改。", "SyncApp.settings.refresh": "刷新", + "SyncApp.settings.captureMethod": "捕获方式", + "SyncApp.settings.captureMethodSub": "Sync 读取你电脑自身游戏流量的方式。如果杀毒软件拦截内置方式,切换到 Npcap — 使用 VPN 或代理时可能也会工作得更好。", + "SyncApp.settings.captureRawSockets": "Windows 原始套接字(内置)", + "SyncApp.settings.captureNpcap": "Npcap(需单独安装)", + "SyncApp.settings.npcapMissing": "Npcap 未安装,同步无法捕获流量。安装后,在主界面使用“重试”。", + "SyncApp.settings.npcapLink": "前往 npcap.com 获取 Npcap(免费)", "SyncApp.settings.troubleshooting": "故障排除", "SyncApp.settings.activityLog": "活动日志", "SyncApp.settings.activityLogSub": "最近的事件,用于支持", "SyncApp.settings.view": "查看", + "SyncApp.settings.hide": "隐藏", "SyncApp.settings.copyDiagnostics": "复制诊断信息", "SyncApp.settings.copyDiagnosticsSub": "与 ARCTracker 支持分享", "SyncApp.settings.copy": "复制", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "检查更新", + "SyncApp.settings.whatIsSync": "同步是做什么的?", + "SyncApp.settings.quit": "退出 ARCTracker Sync", "SyncApp.tray.open": "打开 ARCTracker Sync", "SyncApp.tray.pause": "暂停同步", "SyncApp.tray.resume": "恢复同步", diff --git a/locales/zh-TW.json b/locales/zh-TW.json index 75bbc89..e1594dc 100644 --- a/locales/zh-TW.json +++ b/locales/zh-TW.json @@ -7,7 +7,18 @@ "SyncApp.progress.launcherReady": "啟動器已準備好", "SyncApp.progress.playing": "正在遊玩", "SyncApp.progress.synced": "已同步", + "SyncApp.phase.account.label": "帳號", + "SyncApp.phase.account.sub": "連接 ARCTracker", + "SyncApp.phase.launcher.label": "啟動器", + "SyncApp.phase.launcher.sub": "準備 %{launcher}", + "SyncApp.phase.play.label": "遊玩", + "SyncApp.phase.play.sub": "啟動 ARC Raiders", + "SyncApp.phase.sync.label": "同步", + "SyncApp.phase.sync.sub": "保持物品欄最新", + "SyncApp.hero.step": "第 %{n} 步,共 4 步", "SyncApp.footer.signedInAs": "登入帳號:%{account}", + "SyncApp.footer.synced": "已同步 · %{account}", + "SyncApp.footer.syncedLabel": "已同步 ·", "SyncApp.footer.notSignedIn": "未登入", "SyncApp.footer.settings": "設定", "SyncApp.state.needsAdmin.title": "請先授予權限", @@ -22,14 +33,17 @@ "SyncApp.state.prepareLauncher.body": "ARCTracker 將重新啟動 %{launcher},以便在遊玩時讀取你的 ARC Raiders 物品欄。你的 %{launcher} 遊戲、下載和登入不會受影響。", "SyncApp.state.preparingLauncher.title": "正在準備 %{launcher}…", "SyncApp.state.preparingLauncher.body": "正在關閉並重新開啟 %{launcher}。這將花費幾秒鐘。", + "SyncApp.state.preparingLauncher.waiting": "正在準備 %{launcher}…", "SyncApp.state.closeLauncher.title": "關閉 %{launcher} 以繼續", "SyncApp.state.closeLauncher.body": "ARCTracker 需要關閉 %{launcher} 來進行準備。請儲存進度中的任何內容,然後關閉它。", "SyncApp.state.launcherReady.title": "%{launcher} 已準備好。開始遊玩。", "SyncApp.state.launcherReady.body": "隨時從 %{launcher} 啟動 ARC Raiders。你的物品欄將在遊玩時自動同步。", "SyncApp.state.connecting.title": "正在尋找你的 ARC Raiders 帳號…", "SyncApp.state.connecting.body": "保持 ARC Raiders 開啟。通常在你到達主選單後幾秒鐘內會連接。", + "SyncApp.state.connecting.waiting": "正在等待 ARC Raiders…", "SyncApp.state.updating.title": "正在更新 ARCTracker…", "SyncApp.state.updating.body": "快完成了。正在儲存你的帳號。", + "SyncApp.state.updating.waiting": "正在儲存你的物品欄…", "SyncApp.state.synced.title": "已同步", "SyncApp.state.synced.body": "以 %{account} 身分遊玩中。你的 ARC Raiders 物品欄在 ARCTracker 上已是最新狀態。", "SyncApp.state.synced.session": "你的物品欄將保持同步至 %{time}。", @@ -39,12 +53,14 @@ "SyncApp.state.needsLauncher.body": "%{launcher} 已自行重新啟動,所以 ARCTracker 現在無法讀取你的物品欄。再次準備它以繼續同步。", "SyncApp.state.needsAttention.title": "同步需要關注", "SyncApp.state.needsAttention.body": "ARCTracker Sync 在連接時遇到問題。開啟疑難排解以查看詳細信息。", + "SyncApp.state.needsAttention.npcapBody": "擷取方式已設定為 Npcap,但這台電腦尚未安裝 Npcap。請從 npcap.com 安裝,或在設定中切換回原始通訊端。", "SyncApp.action.signIn": "登入 ARCTracker", "SyncApp.action.cancel": "取消", "SyncApp.action.chooseGame": "選擇 ARC Raiders", "SyncApp.action.prepareLauncher": "準備 %{launcher}", "SyncApp.action.whatDoesThisDo": "這有什麼作用?", "SyncApp.action.closeLauncher": "關閉 %{launcher}", + "SyncApp.action.viewStash": "檢視你的物品欄", "SyncApp.action.hideToTray": "隱藏到系統匣", "SyncApp.action.getHelp": "取得幫助", "SyncApp.action.tryAgain": "重試", @@ -67,19 +83,29 @@ "SyncApp.settings.language": "語言", "SyncApp.settings.displayLanguage": "顯示語言", "SyncApp.settings.matchesWindows": "預設與 Windows 相符", + "SyncApp.settings.matchWindows": "與 Windows 相符", "SyncApp.settings.network": "網路", "SyncApp.settings.networkAdapter": "網路介面卡", "SyncApp.settings.networkAdapterSub": "自動選擇。僅在同步無法連接時變更。", "SyncApp.settings.refresh": "重新整理", + "SyncApp.settings.captureMethod": "擷取方式", + "SyncApp.settings.captureMethodSub": "Sync 讀取你電腦自身遊戲流量的方式。如果防毒軟體封鎖內建方式,切換到 Npcap — 使用 VPN 或代理時也可能運作得更好。", + "SyncApp.settings.captureRawSockets": "Windows 原始通訊端(內建)", + "SyncApp.settings.captureNpcap": "Npcap(需另外安裝)", + "SyncApp.settings.npcapMissing": "Npcap 尚未安裝,因此同步無法擷取流量。安裝後,請在主畫面使用「重試」。", + "SyncApp.settings.npcapLink": "前往 npcap.com 取得 Npcap(免費)", "SyncApp.settings.troubleshooting": "疑難排解", "SyncApp.settings.activityLog": "活動日誌", "SyncApp.settings.activityLogSub": "最近的事件,用於支援", "SyncApp.settings.view": "檢視", + "SyncApp.settings.hide": "隱藏", "SyncApp.settings.copyDiagnostics": "複製診斷資訊", "SyncApp.settings.copyDiagnosticsSub": "與 ARCTracker 支援小組分享", "SyncApp.settings.copy": "複製", "SyncApp.settings.version": "ARCTracker Sync v%{version}", "SyncApp.settings.checkForUpdates": "檢查更新", + "SyncApp.settings.whatIsSync": "同步有什麼作用?", + "SyncApp.settings.quit": "結束 ARCTracker Sync", "SyncApp.tray.open": "開啟 ARCTracker Sync", "SyncApp.tray.pause": "暫停同步", "SyncApp.tray.resume": "繼續同步", diff --git a/src/app.rs b/src/app.rs index 6bbbcb8..573ef27 100644 --- a/src/app.rs +++ b/src/app.rs @@ -12,12 +12,14 @@ use eframe::egui::{ use crate::auth_bridge; use crate::capture::{self, CaptureEvent, CaptureHandle, CaptureStats, InterfaceInfo}; +use crate::capture_backend::CaptureMethod; use crate::config::{self, AppConfig}; use crate::credential_store; use crate::elevation; use crate::fonts; use crate::i18n; use crate::launch::{self, LauncherPlatform, LauncherStatus}; +use crate::npcap::Npcap; use crate::single_instance; use crate::sync_client::{self, SubmitError, SubmitResponse, BASE_URL}; use crate::theme::{ @@ -47,6 +49,8 @@ const GAME_PROCESS_NAMES: &[&str] = &["PioneerGame.exe", "PioneerGame-e.exe", "P const HELP_URL: &str = "https://arctracker.io/help/sync"; /// Where a synced user goes to view their inventory on the web app. const STASH_URL: &str = "https://arctracker.io/stash"; +/// Where the user installs Npcap from; never bundled or downloaded by the app. +const NPCAP_URL: &str = "https://npcap.com/#download"; /// Refresh the bridge token when fewer than this many days remain. const REFRESH_THRESHOLD_DAYS: i64 = 7; const REFRESH_INTERVAL: Duration = Duration::from_secs(24 * 60 * 60); @@ -213,6 +217,10 @@ extern "system" { pub struct ArcTrackerSyncApp { config: AppConfig, locale: String, + /// True once the heavier all-CJK font stack has been loaded so the language + /// picker renders every native name. Loaded lazily the first time that + /// dropdown opens, then kept for the session so reopening never flickers. + picker_fonts_loaded: bool, screen: Screen, show_activity_log: bool, show_explainer: bool, @@ -260,6 +268,10 @@ pub struct ArcTrackerSyncApp { capture: Option, capture_blocked: bool, + /// TTL-cached `Npcap::is_installed()`; `None` until first probed. Only + /// maintained while the Npcap capture method is selected. + npcap_available: Option, + last_npcap_check: Instant, stats: CaptureStats, latest_token: Option, auth_token: Option, @@ -381,6 +393,7 @@ impl ArcTrackerSyncApp { let mut app = Self { config, locale, + picker_fonts_loaded: false, screen: Screen::Hub, show_activity_log: false, show_explainer: false, @@ -416,6 +429,11 @@ impl ArcTrackerSyncApp { .unwrap_or_else(Instant::now), capture: None, capture_blocked: false, + npcap_available: None, + // Backdated so the first frame probes immediately. + last_npcap_check: Instant::now() + .checked_sub(Duration::from_secs(10)) + .unwrap_or_else(Instant::now), stats: CaptureStats::default(), latest_token: None, auth_token, @@ -603,11 +621,34 @@ impl ArcTrackerSyncApp { self.save_config(); self.locale = resolved; i18n::set_active_locale(&self.locale); - fonts::apply_locale(ctx, &self.locale); + self.apply_locale_fonts(ctx); self.tray_tooltip = String::new(); self.update_tray_tooltip(); } + /// Rebuild the font stack for the active locale, preserving the all-CJK set + /// if the language picker has already pulled it in this session. + fn apply_locale_fonts(&self, ctx: &egui::Context) { + if self.picker_fonts_loaded { + fonts::apply_locale_with_all_cjk(ctx, &self.locale); + } else { + fonts::apply_locale(ctx, &self.locale); + } + } + + /// Load the all-CJK font stack the first time the language picker opens, so + /// the non-active CJK native names stop rendering as tofu. + fn ensure_picker_fonts(&mut self, ctx: &egui::Context) { + if self.picker_fonts_loaded { + return; + } + self.picker_fonts_loaded = true; + fonts::apply_locale_with_all_cjk(ctx, &self.locale); + // The new fonts apply next frame; repaint so the just-opened picker + // shows the native names without waiting for the next input event. + ctx.request_repaint(); + } + // ----- silent refresh ---------------------------------------------------------- fn maybe_refresh_auth_on_launch(&mut self) { @@ -644,6 +685,7 @@ impl ArcTrackerSyncApp { self.maybe_retry_token_submission(); self.poll_refresh(); self.refresh_launcher_readiness_if_needed(); + self.refresh_npcap_available_if_needed(); self.refresh_game_running_if_needed(); self.maybe_refresh_auth_on_timer(); self.maybe_check_for_update(); @@ -952,7 +994,11 @@ impl ArcTrackerSyncApp { ), HubState::NeedsAttention => ( tr!("SyncApp.state.needsAttention.title"), - tr!("SyncApp.state.needsAttention.body"), + if self.npcap_known_missing() { + tr!("SyncApp.state.needsAttention.npcapBody") + } else { + tr!("SyncApp.state.needsAttention.body") + }, ), } } @@ -1139,6 +1185,29 @@ impl ArcTrackerSyncApp { } } + /// TTL-gated `Npcap::is_installed()` probe; only runs while the Npcap + /// capture method is selected. The 2s re-check means the "Npcap missing" + /// warnings clear on their own shortly after the user installs it. + fn refresh_npcap_available_if_needed(&mut self) { + if self.config.capture_method != CaptureMethod::Npcap { + return; + } + if self.npcap_available.is_some() + && self.last_npcap_check.elapsed() < Duration::from_secs(2) + { + return; + } + self.npcap_available = Some(Npcap::is_installed()); + self.last_npcap_check = Instant::now(); + } + + /// True when the user selected Npcap but it is not installed — the one + /// capture-blocked cause the app can name precisely (detected by state, + /// never by parsing error strings). + fn npcap_known_missing(&self) -> bool { + self.config.capture_method == CaptureMethod::Npcap && self.npcap_available == Some(false) + } + fn refresh_game_running(&mut self) { self.game_running = GAME_PROCESS_NAMES.iter().any(|name| { crate::process_env::find_processes(name) @@ -1399,7 +1468,11 @@ impl ArcTrackerSyncApp { self.stats = CaptureStats::default(); self.latest_token = None; - self.capture = Some(capture::start_capture(interface_name, sync_key_path)); + self.capture = Some(capture::start_capture( + self.config.capture_method, + interface_name, + sync_key_path, + )); } fn capture_settings_changed(&mut self) { @@ -1692,6 +1765,14 @@ impl ArcTrackerSyncApp { format!("Launcher detail: {}", self.launcher_readiness.detail), format!("Game running: {}", self.game_running), format!("Capture ready: {}", self.capture_ready()), + format!("Capture method: {}", self.config.capture_method.label()), + format!( + "Npcap: {}", + match Npcap::load() { + Ok(npcap) => npcap.lib_version(), + Err(_) => "not installed".to_string(), + } + ), format!("Account synced: {}", self.token_submitted), format!("Inventory sync enabled: {}", self.sync_enabled), format!("Connection active: {}", self.capture.is_some()), @@ -2447,8 +2528,14 @@ impl ArcTrackerSyncApp { } } HubState::NeedsAttention => { + if self.npcap_known_missing() { + ui.hyperlink_to(tr!("SyncApp.settings.npcapLink"), NPCAP_URL); + ui.add_space(4.0); + } if primary_button(ui, &tr!("SyncApp.action.tryAgain")) { self.capture_blocked = false; + // Re-probe for Npcap in case the user just installed it. + self.npcap_available = None; // Resume submission if a prior episode hard-stopped, then // re-attempt with the token we already have. self.reset_submit_retry_state(); @@ -2737,7 +2824,7 @@ impl ArcTrackerSyncApp { }; let mut chosen: Option> = None; - egui::ComboBox::from_id_salt("settings_language_combo") + let combo = egui::ComboBox::from_id_salt("settings_language_combo") .selected_text(current_label) .show_ui(ui, |ui| { if ui @@ -2758,10 +2845,17 @@ impl ArcTrackerSyncApp { chosen = Some(Some(locale.to_string())); } } - }) + }); + combo .response .on_hover_cursor(egui::CursorIcon::PointingHand); + // The popup is open this frame (the menu closure ran), so + // pull in the CJK fonts the native-name list needs. + if combo.inner.is_some() { + self.ensure_picker_fonts(ctx); + } + if let Some(language) = chosen { self.change_language(ctx, language); } @@ -2825,6 +2919,63 @@ impl ArcTrackerSyncApp { if refresh { self.refresh_interfaces(); self.refresh_sync_key_source(); + self.npcap_available = None; + } + + hairline(ui); + + let mut chosen_method: Option = None; + settings_row( + ui, + &tr!("SyncApp.settings.captureMethod"), + &tr!("SyncApp.settings.captureMethodSub"), + |ui| { + ui.spacing_mut().interact_size.y = 30.0; + let current_label = match self.config.capture_method { + CaptureMethod::RawSocket => tr!("SyncApp.settings.captureRawSockets"), + CaptureMethod::Npcap => tr!("SyncApp.settings.captureNpcap"), + }; + egui::ComboBox::from_id_salt("settings_capture_method_combo") + .selected_text(current_label) + .show_ui(ui, |ui| { + for method in [CaptureMethod::RawSocket, CaptureMethod::Npcap] { + let label = match method { + CaptureMethod::RawSocket => { + tr!("SyncApp.settings.captureRawSockets") + } + CaptureMethod::Npcap => tr!("SyncApp.settings.captureNpcap"), + }; + if ui + .selectable_label(self.config.capture_method == method, label) + .clicked() + && self.config.capture_method != method + { + chosen_method = Some(method); + } + } + }) + .response + .on_hover_cursor(egui::CursorIcon::PointingHand); + }, + ); + + if let Some(method) = chosen_method { + self.config.capture_method = method; + self.save_config(); + self.npcap_available = None; + self.capture_settings_changed(); + } + + if self.npcap_known_missing() { + ui.label( + RichText::new(tr!("SyncApp.settings.npcapMissing")) + .size(theme::TEXT_CAPTION) + .color(arc_warning()), + ); + ui.hyperlink_to( + RichText::new(tr!("SyncApp.settings.npcapLink")).size(theme::TEXT_CAPTION), + NPCAP_URL, + ); } }); } diff --git a/src/capture.rs b/src/capture.rs index 332770d..e12c02c 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -19,6 +19,8 @@ use pcapsql_core::stream::{ use pcapsql_core::tls::KeyLog as SyncKeyData; use sha2::{Digest, Sha256}; +use crate::capture_backend::{CaptureMethod, Packet}; +use crate::npcap::Npcap; use crate::packet::{datalink_name, parse_tcp_segment, CapturedSegment}; use crate::rawsock::RawSock; use crate::token::{self, RawTokenHit, TokenObservation}; @@ -147,13 +149,69 @@ pub fn list_interfaces() -> Result> { .collect()) } -pub fn start_capture(interface_name: String, sync_key_path: PathBuf) -> CaptureHandle { +/// The open capture handle for whichever backend the user selected. Both +/// backends expose the same pcap-shaped surface, so `capture_loop` is +/// backend-agnostic past this point. +enum LiveCapture { + Raw(crate::rawsock::Capture), + Npcap(crate::npcap::Capture), +} + +impl LiveCapture { + fn next_packet(&mut self) -> Result> { + match self { + LiveCapture::Raw(capture) => capture.next_packet(), + LiveCapture::Npcap(capture) => capture.next_packet(), + } + } + + fn datalink(&self) -> Result { + match self { + LiveCapture::Raw(capture) => capture.datalink(), + LiveCapture::Npcap(capture) => capture.datalink(), + } + } + + fn set_filter(&mut self, expression: &str) -> Result<()> { + match self { + LiveCapture::Raw(capture) => capture.set_filter(expression), + LiveCapture::Npcap(capture) => capture.set_filter(expression), + } + } +} + +fn open_capture(method: CaptureMethod, interface_name: &str) -> Result { + match method { + CaptureMethod::RawSocket => Ok(LiveCapture::Raw( + RawSock::load()? + .open_live(interface_name) + .with_context(|| format!("opening raw-socket capture on {interface_name}"))?, + )), + CaptureMethod::Npcap => Ok(LiveCapture::Npcap( + Npcap::load()? + .open_adapter(interface_name) + .with_context(|| format!("opening Npcap capture on {interface_name}"))?, + )), + } +} + +pub fn start_capture( + method: CaptureMethod, + interface_name: String, + sync_key_path: PathBuf, +) -> CaptureHandle { let (tx, rx) = unbounded(); let stop = Arc::new(AtomicBool::new(false)); let thread_stop = Arc::clone(&stop); let worker = thread::spawn(move || { - if let Err(error) = capture_loop(interface_name, sync_key_path, thread_stop, tx.clone()) { + if let Err(error) = capture_loop( + method, + interface_name, + sync_key_path, + thread_stop, + tx.clone(), + ) { let _ = tx.send(CaptureEvent::Error(format!("{error:#}"))); } let _ = tx.send(CaptureEvent::Stopped); @@ -167,6 +225,7 @@ pub fn start_capture(interface_name: String, sync_key_path: PathBuf) -> CaptureH } fn capture_loop( + method: CaptureMethod, interface_name: String, sync_key_path: PathBuf, stop: Arc, @@ -195,18 +254,20 @@ fn capture_loop( let mut manager = build_manager(sync_keys); let _ = tx.send(CaptureEvent::Status(format!( - "Opening capture interface {interface_name}" + "Opening capture interface {interface_name} via {}", + method.label() ))); // Raw-socket inbound capture is blocked by the Windows Firewall; add an - // inbound allow rule for our exe first (best-effort). - if let Err(error) = crate::firewall::ensure_capture_allowed() { - let _ = tx.send(CaptureEvent::Status(format!( - "Could not add firewall allowance (inbound may be blocked): {error}" - ))); + // inbound allow rule for our exe first (best-effort). Npcap captures at + // the NDIS layer below the firewall, so no rule is needed there. + if method == CaptureMethod::RawSocket { + if let Err(error) = crate::firewall::ensure_capture_allowed() { + let _ = tx.send(CaptureEvent::Status(format!( + "Could not add firewall allowance (inbound may be blocked): {error}" + ))); + } } - let mut capture: crate::rawsock::Capture = RawSock::load()? - .open_live(&interface_name) - .with_context(|| format!("opening raw-socket capture on {interface_name}"))?; + let mut capture = open_capture(method, &interface_name)?; capture .set_filter(LIVE_BPF_FILTER) .with_context(|| format!("installing capture filter {LIVE_BPF_FILTER:?}"))?; diff --git a/src/capture_backend.rs b/src/capture_backend.rs index 4615be6..e780843 100644 --- a/src/capture_backend.rs +++ b/src/capture_backend.rs @@ -1,4 +1,28 @@ -//! Types the [`crate::rawsock`] backend produces for `capture.rs` to consume. +//! Types shared by the capture backends ([`crate::rawsock`] and +//! [`crate::npcap`]) and consumed by `capture.rs`. + +use serde::{Deserialize, Serialize}; + +/// Which packet-capture backend drives the live capture. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] +pub enum CaptureMethod { + /// Windows raw sockets (`SIO_RCVALL`). Built in, nothing extra to install. + #[default] + RawSocket, + /// Npcap (`wpcap.dll`), installed separately by the user from npcap.com. + Npcap, +} + +impl CaptureMethod { + /// English label for diagnostics and activity-log status lines (those are + /// intentionally not localized). + pub fn label(self) -> &'static str { + match self { + CaptureMethod::RawSocket => "raw sockets", + CaptureMethod::Npcap => "Npcap", + } + } +} /// A capture-able network interface, as shown in the adapter picker. #[derive(Debug, Clone, Default)] diff --git a/src/config.rs b/src/config.rs index e9d38b4..8c008bc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -5,6 +5,7 @@ use anyhow::{Context, Result}; use directories::ProjectDirs; use serde::{Deserialize, Serialize}; +use crate::capture_backend::CaptureMethod; use crate::launch::LauncherPlatform; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -20,6 +21,9 @@ pub struct AppConfig { /// Whether closing the window hides to tray instead of quitting (default on). #[serde(default = "default_keep_in_tray")] pub keep_in_tray: bool, + /// Packet-capture backend. Raw sockets unless the user opts into Npcap. + #[serde(default)] + pub capture_method: CaptureMethod, } fn default_keep_in_tray() -> bool { @@ -34,6 +38,7 @@ impl Default for AppConfig { platform: LauncherPlatform::default(), language: None, keep_in_tray: default_keep_in_tray(), + capture_method: CaptureMethod::default(), } } } @@ -289,6 +294,7 @@ mod tests { platform: LauncherPlatform::Steam, language: Some("de".to_string()), keep_in_tray: false, + capture_method: CaptureMethod::Npcap, }; let json = serde_json::to_string(&config).expect("serialize config"); @@ -301,6 +307,7 @@ mod tests { assert_eq!(decoded.platform, LauncherPlatform::Steam); assert_eq!(decoded.language.as_deref(), Some("de")); assert!(!decoded.keep_in_tray); + assert_eq!(decoded.capture_method, CaptureMethod::Npcap); } #[test] @@ -311,5 +318,6 @@ mod tests { let legacy: AppConfig = serde_json::from_str("{}").expect("deserialize legacy config"); assert!(legacy.keep_in_tray); assert!(legacy.language.is_none()); + assert_eq!(legacy.capture_method, CaptureMethod::RawSocket); } } diff --git a/src/fonts.rs b/src/fonts.rs index 75406d1..9ef130f 100644 --- a/src/fonts.rs +++ b/src/fonts.rs @@ -5,6 +5,12 @@ //! Windows UI font (Malgun Gothic / Microsoft YaHei / Microsoft JhengHei / Yu //! Gothic) and chain it behind Segoe UI (Latin + Cyrillic + Hebrew coverage). //! The chain is rebuilt whenever the active language changes. +//! +//! By default only the active locale's CJK font loads, keeping the footprint +//! small. The language picker, though, lists every locale's native name +//! (한국어, 简体中文, 繁體中文, 日本語), which needs all the CJK fonts at once; +//! those tens of megabytes load lazily, only once that dropdown is opened, via +//! [`apply_locale_with_all_cjk`]. use std::sync::Arc; @@ -22,6 +28,28 @@ const SEGOE_UI: FontCandidate = FontCandidate { files: &["segoeui.ttf"], }; +/// The CJK locales with their own fallback font, in language-picker order. +const CJK_LOCALES: [&str; 4] = ["ko", "zh-CN", "zh-TW", "ja"]; + +/// The CJK locales to load fonts for. The active locale (if CJK) always comes +/// first so its regional Han glyphs take priority in body text. When +/// `include_all` is set — for the language picker, which lists every locale's +/// native name — the remaining CJK locales follow so those names also render. +fn cjk_load_order(active: &str, include_all: bool) -> Vec<&'static str> { + let mut order: Vec<&'static str> = Vec::new(); + if let Some(found) = CJK_LOCALES.iter().copied().find(|locale| *locale == active) { + order.push(found); + } + if include_all { + for locale in CJK_LOCALES { + if locale != active { + order.push(locale); + } + } + } + order +} + /// Locale-specific CJK fallback fonts, in the order egui should consult them. fn locale_fallbacks(locale: &str) -> &'static [FontCandidate] { match locale { @@ -51,18 +79,34 @@ fn locale_fallbacks(locale: &str) -> &'static [FontCandidate] { } } -/// Build a [`FontDefinitions`] that starts with the locale's preferred fonts -/// and falls back through Segoe UI to egui's built-in fonts, so missing system -/// fonts never produce blank text. +/// Build a [`FontDefinitions`] for the active locale: Segoe UI plus the +/// locale's own CJK font, falling back to egui's built-in fonts so missing +/// system fonts never produce blank text. pub fn definitions_for_locale(locale: &str) -> FontDefinitions { + build_definitions(locale, false) +} + +/// Like [`definitions_for_locale`], but also loads every other CJK locale's +/// font so the language picker can render all of the native names. Heavier +/// (tens of MB), so it is applied lazily — only once the picker is opened. +pub fn definitions_for_locale_with_all_cjk(locale: &str) -> FontDefinitions { + build_definitions(locale, true) +} + +fn build_definitions(locale: &str, include_all_cjk: bool) -> FontDefinitions { let mut fonts = FontDefinitions::default(); let mut chain: Vec = Vec::new(); // Latin / Cyrillic / Hebrew base first so western text stays crisp. register_candidate(&mut fonts, &SEGOE_UI, &mut chain); - for candidate in locale_fallbacks(locale) { - register_candidate(&mut fonts, candidate, &mut chain); + // The active locale's CJK font first (for correct regional glyphs in body + // text); for the picker, the remaining CJK fonts follow so every native + // name renders. `register_candidate` dedupes. + for cjk_locale in cjk_load_order(locale, include_all_cjk) { + for candidate in locale_fallbacks(cjk_locale) { + register_candidate(&mut fonts, candidate, &mut chain); + } } if !chain.is_empty() { @@ -122,3 +166,44 @@ fn windows_fonts_dir() -> Option { pub fn apply_locale(ctx: &egui::Context, locale: &str) { ctx.set_fonts(definitions_for_locale(locale)); } + +/// Apply the active locale's fonts plus every CJK fallback, so the language +/// picker renders all native names. Call once the picker is opened. +pub fn apply_locale_with_all_cjk(ctx: &egui::Context, locale: &str) { + ctx.set_fonts(definitions_for_locale_with_all_cjk(locale)); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn default_load_order_is_active_locale_only() { + // The lazy default keeps the footprint small: a non-CJK locale loads no + // CJK font, and a CJK locale loads only its own. + assert!(cjk_load_order("en", false).is_empty()); + assert_eq!(cjk_load_order("ja", false), ["ja"]); + assert_eq!(cjk_load_order("zh-CN", false), ["zh-CN"]); + } + + #[test] + fn picker_load_order_is_all_cjk_with_active_first() { + // When the language picker opens it lists 한국어, 简体中文, 繁體中文, + // and 日本語, so every CJK font must load. + assert_eq!(cjk_load_order("en", true), ["ko", "zh-CN", "zh-TW", "ja"]); + + // The active CJK locale leads so its regional Han glyphs win in body + // text; the rest follow so the other native names still render. + assert_eq!( + cjk_load_order("zh-TW", true), + ["zh-TW", "ko", "zh-CN", "ja"] + ); + assert_eq!(cjk_load_order("ja", true), ["ja", "ko", "zh-CN", "zh-TW"]); + + // Every CJK locale is present exactly once regardless of the active one. + let mut deduped = cjk_load_order("ko", true); + deduped.sort_unstable(); + deduped.dedup(); + assert_eq!(deduped, ["ja", "ko", "zh-CN", "zh-TW"]); + } +} diff --git a/src/i18n.rs b/src/i18n.rs index ca28704..81a9c3d 100644 --- a/src/i18n.rs +++ b/src/i18n.rs @@ -238,5 +238,14 @@ mod tests { ), "Signed in as Matt" ); + // The capture-method settings keys must resolve to real text. + assert_eq!( + __translate("SyncApp.settings.captureMethod", &[]), + "Capture method" + ); + assert_ne!( + __translate("SyncApp.state.needsAttention.npcapBody", &[]), + "SyncApp.state.needsAttention.npcapBody" + ); } } diff --git a/src/lib.rs b/src/lib.rs index 4aea6f7..4556e26 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ pub mod firewall; pub mod fonts; pub mod i18n; pub mod launch; +pub mod npcap; pub mod packet; pub mod process_env; pub mod rawsock; diff --git a/src/npcap.rs b/src/npcap.rs new file mode 100644 index 0000000..849f312 --- /dev/null +++ b/src/npcap.rs @@ -0,0 +1,555 @@ +//! Optional packet-capture backend using Npcap's `wpcap.dll`, loaded +//! dynamically at runtime. Npcap is never bundled, downloaded, or installed by +//! this app — the user installs it themselves from . The +//! app must start and run normally when Npcap is absent, which is why there is +//! no import-table link against wpcap: every entry point is resolved with +//! `LoadLibraryExW`/`GetProcAddress` on first use. +//! +//! Exists as an alternative to [`crate::rawsock`] for users whose antivirus +//! interferes with raw-socket capture. Delivers link-layer frames (typically +//! `DLT_EN10MB` Ethernet), which `packet.rs` already parses. + +#[cfg(windows)] +pub use imp::{Capture, Npcap}; + +#[cfg(not(windows))] +pub use stub::{Capture, Npcap}; + +/// True when a pcap device name (e.g. `\Device\NPF_{GUID}`) refers to the +/// adapter with this GetAdaptersAddresses GUID string (e.g. `{GUID}`). +/// Case-insensitive; tolerates the GUID with or without braces. The Npcap +/// loopback device (`\Device\NPF_Loopback`) never matches because the match +/// requires the braced form. +pub fn npf_name_matches_adapter(pcap_name: &str, adapter_guid: &str) -> bool { + let bare = adapter_guid.trim_matches(|c| c == '{' || c == '}'); + if bare.is_empty() { + return false; + } + let needle = format!("{{{}}}", bare.to_ascii_lowercase()); + pcap_name.to_ascii_lowercase().contains(&needle) +} + +/// `pcap_pkthdr`'s timeval → unix microseconds. On 64-bit Windows `timeval` +/// is two 32-bit `long`s, hence the `i32` fields. +pub fn pkthdr_timestamp_us(ts_sec: i32, ts_usec: i32) -> i64 { + i64::from(ts_sec) * 1_000_000 + i64::from(ts_usec) +} + +#[cfg(windows)] +mod imp { + use std::ffi::CString; + use std::sync::OnceLock; + + use anyhow::{bail, Context, Result}; + + use crate::capture_backend::{Device, Packet}; + + const PCAP_ERRBUF_SIZE: usize = 256; + const PCAP_NETMASK_UNKNOWN: u32 = 0xffff_ffff; + // Matches rawsock's 256 KB RECV_BUF so LSO/GRO super-frames are not truncated. + const SNAPLEN: i32 = 262_144; + // Matches rawsock's 100 ms select() cadence; pcap_next_ex returns 0 on + // timeout, so the capture loop keeps honoring the stop flag. + const READ_TIMEOUT_MS: i32 = 100; + // Matches rawsock's 8 MB SO_RCVBUF to reduce drops (best-effort). + const KERNEL_BUFFER_BYTES: i32 = 8 * 1024 * 1024; + + const NOT_INSTALLED: &str = "Npcap is not installed (wpcap.dll could not be loaded). \ + Install Npcap from https://npcap.com, or switch the capture method back to \ + raw sockets in Settings."; + + // ---- LoadLibraryExW search flags ---- + // Lets wpcap.dll's dependency Packet.dll resolve from the directory the + // DLL itself was loaded from (System32\Npcap). + const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: u32 = 0x0000_0100; + const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: u32 = 0x0000_1000; + const LOAD_LIBRARY_SEARCH_SYSTEM32: u32 = 0x0000_0800; + + /// Opaque `pcap_t`. + type PcapT = core::ffi::c_void; + + /// `struct pcap_pkthdr` on 64-bit Windows: `timeval` is two 32-bit longs. + #[repr(C)] + struct PcapPkthdr { + ts_sec: i32, + ts_usec: i32, + caplen: u32, + len: u32, + } + + /// Prefix of `pcap_if_t` up to the fields we read. + #[repr(C)] + struct PcapIf { + next: *mut PcapIf, + name: *mut u8, // C string: \Device\NPF_{GUID} + description: *mut u8, // C string, may be null + addresses: *mut core::ffi::c_void, + flags: u32, + } + + /// `struct bpf_program`. + #[repr(C)] + struct BpfProgram { + bf_len: u32, + bf_insns: *mut core::ffi::c_void, + } + + // The wpcap.dll function signatures, named so the GetProcAddress + // transmutes below state exactly what they produce. + type FindAllDevsFn = unsafe extern "C" fn(*mut *mut PcapIf, *mut u8) -> i32; + type FreeAllDevsFn = unsafe extern "C" fn(*mut PcapIf); + type OpenLiveFn = unsafe extern "C" fn(*const u8, i32, i32, i32, *mut u8) -> *mut PcapT; + type CompileFn = unsafe extern "C" fn(*mut PcapT, *mut BpfProgram, *const u8, i32, u32) -> i32; + type SetFilterFn = unsafe extern "C" fn(*mut PcapT, *mut BpfProgram) -> i32; + type FreeCodeFn = unsafe extern "C" fn(*mut BpfProgram); + type NextExFn = unsafe extern "C" fn(*mut PcapT, *mut *mut PcapPkthdr, *mut *const u8) -> i32; + type DatalinkFn = unsafe extern "C" fn(*mut PcapT) -> i32; + type CloseFn = unsafe extern "C" fn(*mut PcapT); + type GetErrFn = unsafe extern "C" fn(*mut PcapT) -> *mut u8; + type LibVersionFn = unsafe extern "C" fn() -> *const u8; + type SetBuffFn = unsafe extern "C" fn(*mut PcapT, i32) -> i32; + + /// wpcap.dll entry points resolved via GetProcAddress. Plain `extern "C"` + /// function pointers are `Send + Sync`, so the `OnceLock` cache below is + /// shareable across threads without any unsafe impls. + struct Api { + findalldevs: FindAllDevsFn, + freealldevs: FreeAllDevsFn, + open_live: OpenLiveFn, + compile: CompileFn, + setfilter: SetFilterFn, + freecode: FreeCodeFn, + next_ex: NextExFn, + datalink: DatalinkFn, + close: CloseFn, + geterr: GetErrFn, + lib_version: LibVersionFn, + /// WinPcap/Npcap-specific kernel buffer resize; absent in some builds. + setbuff: Option, + } + + /// Set on successful load only — a failed probe is retried on the next + /// call, so installing Npcap while the app is running works without a + /// restart. The module stays loaded for the process lifetime. + static API: OnceLock = OnceLock::new(); + + // ---- Public surface: Npcap (loader) + Capture (live handle) ---- + + pub struct Npcap { + api: &'static Api, + } + + impl Npcap { + pub fn load() -> Result { + Ok(Npcap { api: load_api()? }) + } + + /// Cheap when Npcap is present (cached); a failed probe is a couple of + /// LoadLibraryExW calls. + pub fn is_installed() -> bool { + Self::load().is_ok() + } + + /// The `pcap_lib_version` banner, for diagnostics. + pub fn lib_version(&self) -> String { + c_to_string(unsafe { (self.api.lib_version)() }) + } + + /// Open a live capture on the adapter with this GetAdaptersAddresses + /// GUID by finding the matching `\Device\NPF_{GUID}` pcap device. + pub fn open_adapter(&self, adapter_guid: &str) -> Result { + let device = self + .list_devices()? + .into_iter() + .find(|device| super::npf_name_matches_adapter(&device.name, adapter_guid)) + .ok_or_else(|| { + anyhow::anyhow!( + "Npcap did not report a capture device for the selected network \ + adapter ({adapter_guid}). Press Refresh in Settings, reinstall \ + Npcap, or switch back to raw sockets." + ) + })?; + + let name = CString::new(device.name.clone()) + .with_context(|| format!("capture device name {:?}", device.name))?; + let mut errbuf = [0u8; PCAP_ERRBUF_SIZE + 1]; + let handle = unsafe { + (self.api.open_live)( + name.as_ptr().cast(), + SNAPLEN, + 0, // promiscuous off — mirrors RCVALL_IPLEVEL; promiscuous + // mode drops the host's own inbound traffic on some Wi-Fi + // adapters (see rawsock.rs), breaking TLS key establishment. + READ_TIMEOUT_MS, + errbuf.as_mut_ptr(), + ) + }; + if handle.is_null() { + bail!( + "pcap_open_live on {} failed: {}", + device.name, + c_to_string(errbuf.as_ptr()) + ); + } + + // Enlarge the kernel buffer to reduce drops; best-effort, like + // rawsock's SO_RCVBUF. + if let Some(setbuff) = self.api.setbuff { + let _ = unsafe { setbuff(handle, KERNEL_BUFFER_BYTES) }; + } + + let datalink = unsafe { (self.api.datalink)(handle) }; + Ok(Capture { + api: self.api, + handle, + datalink, + }) + } + + fn list_devices(&self) -> Result> { + let mut list: *mut PcapIf = std::ptr::null_mut(); + let mut errbuf = [0u8; PCAP_ERRBUF_SIZE + 1]; + if unsafe { (self.api.findalldevs)(&mut list, errbuf.as_mut_ptr()) } != 0 { + bail!( + "listing Npcap capture devices failed: {}", + c_to_string(errbuf.as_ptr()) + ); + } + + let mut devices = Vec::new(); + let mut current = list; + while !current.is_null() { + let entry = unsafe { &*current }; + let name = c_to_string(entry.name); + if !name.is_empty() { + let description = Some(c_to_string(entry.description)) + .filter(|description| !description.is_empty()); + devices.push(Device { name, description }); + } + current = entry.next; + } + if !list.is_null() { + unsafe { (self.api.freealldevs)(list) }; + } + Ok(devices) + } + } + + pub struct Capture { + api: &'static Api, + handle: *mut PcapT, + datalink: i32, + } + + impl Capture { + pub fn next_packet(&mut self) -> Result> { + let mut header: *mut PcapPkthdr = std::ptr::null_mut(); + let mut data: *const u8 = std::ptr::null(); + let result = unsafe { (self.api.next_ex)(self.handle, &mut header, &mut data) }; + match result { + // The header and data buffers are only valid until the next + // pcap call, so copy out immediately. + 1 => { + if header.is_null() || data.is_null() { + return Ok(None); + } + let header = unsafe { &*header }; + let captured = header.caplen as usize; + let bytes = unsafe { std::slice::from_raw_parts(data, captured) }; + Ok(Some(Packet { + timestamp_us: super::pkthdr_timestamp_us(header.ts_sec, header.ts_usec), + captured_len: header.caplen, + original_len: header.len, + data: bytes.to_vec(), + })) + } + 0 => Ok(None), // read timeout — nothing captured this round + -2 => Ok(None), // pcap_breakloop, not used but harmless + _ => bail!("Npcap capture read failed: {}", self.last_error()), + } + } + + pub fn datalink(&self) -> Result { + Ok(self.datalink) + } + + pub fn set_filter(&mut self, expression: &str) -> Result<()> { + let filter = CString::new(expression) + .with_context(|| format!("capture filter {expression:?}"))?; + let mut program = BpfProgram { + bf_len: 0, + bf_insns: std::ptr::null_mut(), + }; + if unsafe { + (self.api.compile)( + self.handle, + &mut program, + filter.as_ptr().cast(), + 1, // optimize + PCAP_NETMASK_UNKNOWN, + ) + } != 0 + { + bail!( + "compiling capture filter {expression:?} failed: {}", + self.last_error() + ); + } + let result = unsafe { (self.api.setfilter)(self.handle, &mut program) }; + unsafe { (self.api.freecode)(&mut program) }; + if result != 0 { + bail!( + "installing capture filter {expression:?} failed: {}", + self.last_error() + ); + } + Ok(()) + } + + fn last_error(&self) -> String { + c_to_string(unsafe { (self.api.geterr)(self.handle) }) + } + } + + impl Drop for Capture { + fn drop(&mut self) { + unsafe { (self.api.close)(self.handle) }; + } + } + + // ---- wpcap.dll loading ---- + + fn load_api() -> Result<&'static Api> { + if let Some(api) = API.get() { + return Ok(api); + } + let api = probe_wpcap()?; + // A racing thread may have loaded it too; either Api is equivalent. + Ok(API.get_or_init(|| api)) + } + + fn probe_wpcap() -> Result { + // (1) The standard Npcap install: \Npcap\wpcap.dll. + // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR lets its dependency Packet.dll + // resolve from that same directory. + let mut module: isize = 0; + if let Some(system32) = system_directory() { + let path = wide(&format!("{system32}\\Npcap\\wpcap.dll")); + module = unsafe { + LoadLibraryExW( + path.as_ptr(), + std::ptr::null_mut(), + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, + ) + }; + } + // (2) "WinPcap API-compatible mode" installs place wpcap.dll in + // System32 itself. Restricting the search to System32 avoids picking + // up a planted wpcap.dll next to our exe or on PATH. + if module == 0 { + let name = wide("wpcap.dll"); + module = unsafe { + LoadLibraryExW( + name.as_ptr(), + std::ptr::null_mut(), + LOAD_LIBRARY_SEARCH_SYSTEM32, + ) + }; + } + if module == 0 { + bail!("{NOT_INSTALLED}"); + } + + macro_rules! required { + ($name:literal, $ty:ty) => {{ + let address = unsafe { GetProcAddress(module, concat!($name, "\0").as_ptr()) }; + if address.is_null() { + bail!( + "wpcap.dll is missing the expected function {} — the Npcap install \ + may be damaged; reinstall it from https://npcap.com", + $name + ); + } + unsafe { std::mem::transmute::<*mut core::ffi::c_void, $ty>(address) } + }}; + } + + let setbuff_address = unsafe { GetProcAddress(module, c"pcap_setbuff".as_ptr().cast()) }; + Ok(Api { + findalldevs: required!("pcap_findalldevs", FindAllDevsFn), + freealldevs: required!("pcap_freealldevs", FreeAllDevsFn), + open_live: required!("pcap_open_live", OpenLiveFn), + compile: required!("pcap_compile", CompileFn), + setfilter: required!("pcap_setfilter", SetFilterFn), + freecode: required!("pcap_freecode", FreeCodeFn), + next_ex: required!("pcap_next_ex", NextExFn), + datalink: required!("pcap_datalink", DatalinkFn), + close: required!("pcap_close", CloseFn), + geterr: required!("pcap_geterr", GetErrFn), + lib_version: required!("pcap_lib_version", LibVersionFn), + setbuff: if setbuff_address.is_null() { + None + } else { + Some(unsafe { + std::mem::transmute::<*mut core::ffi::c_void, SetBuffFn>(setbuff_address) + }) + }, + }) + } + + fn system_directory() -> Option { + let mut buffer = [0u16; 260]; + let written = unsafe { GetSystemDirectoryW(buffer.as_mut_ptr(), buffer.len() as u32) }; + if written == 0 || written as usize >= buffer.len() { + return None; + } + Some(String::from_utf16_lossy(&buffer[..written as usize])) + } + + fn wide(text: &str) -> Vec { + text.encode_utf16().chain(Some(0)).collect() + } + + fn c_to_string(ptr: *const u8) -> String { + if ptr.is_null() { + return String::new(); + } + let mut len = 0usize; + while unsafe { *ptr.add(len) } != 0 { + len += 1; + } + let bytes = unsafe { std::slice::from_raw_parts(ptr, len) }; + String::from_utf8_lossy(bytes).into_owned() + } + + #[link(name = "Kernel32")] + extern "system" { + fn LoadLibraryExW(name: *const u16, file: *mut core::ffi::c_void, flags: u32) -> isize; + fn GetProcAddress(module: isize, name: *const u8) -> *mut core::ffi::c_void; + fn GetSystemDirectoryW(buffer: *mut u16, size: u32) -> u32; + } + + #[cfg(test)] + mod tests { + use super::PcapPkthdr; + + /// Layout guard: `pcap_pkthdr` on 64-bit Windows is `timeval` (two + /// 32-bit longs) + two `bpf_u_int32`s — 16 bytes, no padding. + #[test] + fn pcap_pkthdr_layout_matches_windows_abi() { + assert_eq!(std::mem::size_of::(), 16); + let header = PcapPkthdr { + ts_sec: 1, + ts_usec: 2, + caplen: 3, + len: 4, + }; + assert_eq!( + std::mem::offset_of!(PcapPkthdr, caplen), + 8, + "caplen must directly follow the 8-byte timeval" + ); + assert_eq!(header.len, 4); + } + } +} + +#[cfg(not(windows))] +mod stub { + use anyhow::{bail, Result}; + + use crate::capture_backend::{Device, Packet}; + + pub struct Npcap; + pub struct Capture; + + impl Npcap { + pub fn load() -> Result { + bail!("Npcap capture is only supported on Windows") + } + pub fn is_installed() -> bool { + false + } + pub fn lib_version(&self) -> String { + String::new() + } + #[allow(dead_code)] + pub fn list_devices(&self) -> Result> { + Ok(Vec::new()) + } + pub fn open_adapter(&self, _adapter_guid: &str) -> Result { + bail!("Npcap capture is only supported on Windows") + } + } + + impl Capture { + pub fn next_packet(&mut self) -> Result> { + Ok(None) + } + pub fn datalink(&self) -> Result { + Ok(crate::packet::DLT_EN10MB) + } + pub fn set_filter(&mut self, _expression: &str) -> Result<()> { + Ok(()) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn npf_name_matches_braced_guid_case_insensitively() { + let pcap_name = r"\Device\NPF_{F3A9B2C1-0D4E-4F56-9A78-1B2C3D4E5F60}"; + assert!(npf_name_matches_adapter( + pcap_name, + "{f3a9b2c1-0d4e-4f56-9a78-1b2c3d4e5f60}" + )); + assert!(npf_name_matches_adapter( + pcap_name, + "{F3A9B2C1-0D4E-4F56-9A78-1B2C3D4E5F60}" + )); + } + + #[test] + fn npf_name_matches_guid_without_braces() { + assert!(npf_name_matches_adapter( + r"\Device\NPF_{F3A9B2C1-0D4E-4F56-9A78-1B2C3D4E5F60}", + "F3A9B2C1-0D4E-4F56-9A78-1B2C3D4E5F60" + )); + } + + #[test] + fn npf_loopback_device_never_matches() { + assert!(!npf_name_matches_adapter( + r"\Device\NPF_Loopback", + "Loopback" + )); + } + + #[test] + fn npf_name_rejects_different_guid() { + assert!(!npf_name_matches_adapter( + r"\Device\NPF_{F3A9B2C1-0D4E-4F56-9A78-1B2C3D4E5F60}", + "{00000000-0000-0000-0000-000000000000}" + )); + } + + #[test] + fn npf_name_rejects_empty_guid() { + let pcap_name = r"\Device\NPF_{F3A9B2C1-0D4E-4F56-9A78-1B2C3D4E5F60}"; + assert!(!npf_name_matches_adapter(pcap_name, "")); + assert!(!npf_name_matches_adapter(pcap_name, "{}")); + } + + #[test] + fn pkthdr_timestamp_converts_to_unix_micros() { + assert_eq!( + pkthdr_timestamp_us(1_700_000_000, 250_000), + 1_700_000_000_250_000 + ); + assert_eq!(pkthdr_timestamp_us(0, 0), 0); + assert_eq!(pkthdr_timestamp_us(1, 999_999), 1_999_999); + } +} diff --git a/src/widgets.rs b/src/widgets.rs index 1fe626c..964ee04 100644 --- a/src/widgets.rs +++ b/src/widgets.rs @@ -140,13 +140,18 @@ pub fn settings_row( ) { ui.add_space(SPACE_XS); ui.horizontal(|ui| { - ui.vertical(|ui| { - ui.label(RichText::new(label).color(arc_foreground())); - if !sub.is_empty() { - ui.label(RichText::new(sub).size(TEXT_CAPTION).color(arc_fg_dim())); - } + // Lay the control out from the right edge first so the remaining width + // bounds the text column — a long sub-label (or translation) wraps + // instead of running underneath the control. + ui.with_layout(Layout::right_to_left(Align::Center), |ui| { + add_control(ui); + ui.with_layout(Layout::top_down(Align::Min), |ui| { + ui.label(RichText::new(label).color(arc_foreground())); + if !sub.is_empty() { + ui.label(RichText::new(sub).size(TEXT_CAPTION).color(arc_fg_dim())); + } + }); }); - ui.with_layout(Layout::right_to_left(Align::Center), add_control); }); ui.add_space(SPACE_XS); }