From b41b32d472190f600b15706f7822f83023838c37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Wed, 29 Jul 2026 15:11:40 +0200 Subject: [PATCH] feat(i18n): complete v1.34.1 locale reconciliation --- messages/en.json | 4 +-- messages/fr.json | 26 +++++++++++++------ messages/it.json | 26 +++++++++++++------ messages/pl.json | 26 +++++++++++++------ src/__tests__/v1341-locale-parity.test.ts | 8 ++---- .../__tests__/i18n-locale-integrity.test.ts | 6 ++--- 6 files changed, 60 insertions(+), 36 deletions(-) diff --git a/messages/en.json b/messages/en.json index 1fc7e5c02..7667cc0b7 100644 --- a/messages/en.json +++ b/messages/en.json @@ -5634,8 +5634,8 @@ "nightscoutTokenOptional": "Optional for a public site", "nightscoutTokenSavedPlaceholder": "Saved — enter a new token to replace it", "nightscoutTokenHelp": "Paste an access token from your Nightscout admin tools. Leave empty if your site is publicly readable.", - "nightscoutPrivateOperatorTitle": "Private Nightscout access requires server approval.", - "nightscoutPrivateOperatorDescription": "Ask your server administrator to approve this exact Nightscout origin.", + "nightscoutPrivateOperatorTitle": "Private Nightscout access requires server operator approval.", + "nightscoutPrivateOperatorDescription": "Ask your server operator to approve this exact Nightscout origin.", "nightscoutConnect": "Connect", "nightscoutUpdate": "Save changes", "nightscoutConnected": "Nightscout connected.", diff --git a/messages/fr.json b/messages/fr.json index 4648651f3..45575fc98 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -2252,16 +2252,12 @@ "heroActionAskCoach": "Demander au coach", "healthScore": { "label": "Score de santé", - "algorithmChanged": "Le score utilise désormais des plages de référence cardiométaboliques publiées; le poids n'est plus inclus car son ancienne cible provenait de la taille plutôt que d'un objectif personnel, les variations quotidiennes de l'humeur et l'observance médicamenteuse sont des actions plutôt que des états de santé, et la fréquence cardiaque au repos comme la VFC n'ont pas de cible universelle. La progression du poids reste affichée ci-dessous comme contexte personnel, les autres signaux conservent leurs propres cartes et un nouveau chiffre ne signifie pas que ta santé a changé.", - "dismissAlgorithmChanged": "Fermer la note sur la méthode", "band": { "green": "Dans la plage de référence", "yellow": "Certains piliers demandent une attention", "red": "Un ou plusieurs piliers sont hors de la plage de référence" }, - "method": "Moyenne à poids égal des piliers admissibles. Le pilier le plus bas fixe la catégorie globale.", "insufficient": "{count} piliers admissibles. Le score en requiert au moins trois, dont un pilier physiologique mesuré.", - "composition": "Inclus : {pillars}", "bandSetter": "Catégorie globale fixée par {pillar}", "versionAndNoise": "Version de la méthode {version}. Seuil de comparaison hebdomadaire : {noise} points.", "methodVersion": "Version de la méthode {version}.", @@ -4614,6 +4610,7 @@ "rowsImported": "{count} lignes importées jusqu'ici", "doneSummary": "Terminé — {imported} enregistrements sur {read} importés, {skipped} enregistrements cliniques ignorés.", "doneNothing": "Rien n'a été importé de cette archive : 0 enregistrement sur {read} est arrivé.", + "ecgResult": "ECG : {discovered} détectés, {imported} importés, {updated} mis à jour, {skipped} ignorés et {failed} échoués. Les erreurs d’ECG n’annulent pas les enregistrements compatibles importés depuis export.xml.", "estimateWarning": "Les totaux cumulés de {count} jour(s) ont été estimés à partir de la source d’export la plus élevée. Les statistiques Apple Santé natives restent la référence.", "phase": { "queued": "En file d'attente…", @@ -4930,6 +4927,21 @@ "passwordUpdated": "Mot de passe mis à jour", "passkeys": "Passkeys", "passkeysDescription": "Les clés d’accès permettent une connexion sécurisée sans mot de passe.", + "passkeyReauth": { + "title": "Confirmez votre identité", + "description": "Vérifiez une méthode de connexion existante avant d’ajouter une nouvelle clé d’accès.", + "methodLabel": "Méthode de vérification", + "methods": { + "password": "Mot de passe", + "totp": "Code d’authentification", + "passkey": "Clé d’accès", + "webauthn": "Clé de sécurité" + }, + "currentPassword": "Mot de passe actuel", + "authenticatorCode": "Code d’authentification", + "authenticatorPlaceholder": "Code d’authentification à 6 chiffres", + "verifyAndAdd": "Vérifier et ajouter" + }, "passkeyName": "Nom", "noPasskeys": "Aucune clé d’accès enregistrée.", "addPasskey": "Ajouter une clé d’accès", @@ -5622,8 +5634,8 @@ "nightscoutTokenOptional": "Facultatif pour un site public", "nightscoutTokenSavedPlaceholder": "Enregistré — saisissez un nouveau jeton pour le remplacer", "nightscoutTokenHelp": "Collez un jeton d'accès depuis les outils d'administration de Nightscout. Laissez vide si votre site est lisible publiquement.", - "nightscoutPrivateHost": "Ce site fonctionne sur un réseau privé", - "nightscoutPrivateHostHelp": "Activez uniquement si votre instance Nightscout est sur une adresse LAN, VPN ou Tailscale. Désactivé pour les sites publics.", + "nightscoutPrivateOperatorTitle": "L’accès à un Nightscout privé nécessite l’autorisation de l’administrateur du serveur.", + "nightscoutPrivateOperatorDescription": "Demandez à l’administrateur du serveur d’autoriser précisément cette origine Nightscout.", "nightscoutConnect": "Connecter", "nightscoutUpdate": "Enregistrer les modifications", "nightscoutConnected": "Nightscout connecté.", @@ -8581,7 +8593,6 @@ "notRecorded": "Non renseigné", "unreadable": "La valeur enregistrée n'a pas pu être lue", "save": "Enregistrer", - "correct": "Corriger", "savedToast": "Contexte du mode de vie enregistré", "saveError": "Impossible d'enregistrer le contexte du mode de vie", "loadError": "Impossible de charger le contexte du mode de vie", @@ -8823,7 +8834,6 @@ "withheld": "Un résumé a été généré mais n’a pas passé le contrôle de sécurité, il n’est donc pas affiché. Vous pouvez réessayer ou lire le document lui-même.", "unavailable": "Aucun résumé n’a pu être généré pour ce document.", "generate": "Générer le résumé", - "regenerate": "Regénérer", "generating": "Génération…" }, "loadError": "Impossible de charger ce document.", diff --git a/messages/it.json b/messages/it.json index c4be5e934..da70db024 100644 --- a/messages/it.json +++ b/messages/it.json @@ -2252,16 +2252,12 @@ "heroActionAskCoach": "Chiedi al coach", "healthScore": { "label": "Punteggio di salute", - "algorithmChanged": "Il punteggio usa ora intervalli di riferimento cardiometabolici pubblicati; il peso non è più incluso perché il vecchio obiettivo derivava dall'altezza anziché da un obiettivo personale, la variabilità quotidiana dell'umore e l'aderenza ai farmaci sono azioni anziché stati di salute, e la frequenza cardiaca a riposo e l'HRV non hanno un obiettivo universale. I progressi del peso restano visibili sotto come contesto personale, gli altri segnali conservano le proprie schede e un numero nuovo non significa che la tua salute sia cambiata.", - "dismissAlgorithmChanged": "Chiudi la nota sul metodo", "band": { "green": "Nell'intervallo di riferimento", "yellow": "Alcuni pilastri richiedono attenzione", "red": "Uno o più pilastri sono fuori dall'intervallo di riferimento" }, - "method": "Media con peso uguale dei pilastri idonei. Il pilastro più basso determina la fascia complessiva.", "insufficient": "{count} pilastri idonei. Il punteggio ne richiede almeno tre, incluso un pilastro fisiologico misurato.", - "composition": "Inclusi: {pillars}", "bandSetter": "Fascia complessiva determinata da {pillar}", "versionAndNoise": "Versione del metodo {version}. Soglia del confronto settimanale: {noise} punti.", "methodVersion": "Versione del metodo {version}.", @@ -4614,6 +4610,7 @@ "rowsImported": "{count} righe importate finora", "doneSummary": "Fatto: {imported} di {read} record importati, {skipped} record clinici saltati.", "doneNothing": "Da questo archivio non è stato importato nulla: sono arrivati 0 record su {read}.", + "ecgResult": "ECG: {discovered} rilevati, {imported} importati, {updated} aggiornati, {skipped} ignorati e {failed} non riusciti. Gli errori ECG non eliminano i record supportati importati da export.xml.", "estimateWarning": "I totali cumulativi di {count} giorno/i sono stati stimati dalla fonte di esportazione più alta. Le statistiche native di Apple Salute restano autorevoli.", "phase": { "queued": "In coda…", @@ -4930,6 +4927,21 @@ "passwordUpdated": "Password aggiornata correttamente", "passkeys": "Passkeys", "passkeysDescription": "Le passkey consentono un accesso sicuro senza password.", + "passkeyReauth": { + "title": "Conferma la tua identità", + "description": "Verifica un metodo di accesso esistente prima di aggiungere una nuova passkey.", + "methodLabel": "Metodo di verifica", + "methods": { + "password": "Password", + "totp": "Codice dell’app di autenticazione", + "passkey": "Passkey", + "webauthn": "Chiave di sicurezza" + }, + "currentPassword": "Password attuale", + "authenticatorCode": "Codice dell’app di autenticazione", + "authenticatorPlaceholder": "Codice a 6 cifre dell’app di autenticazione", + "verifyAndAdd": "Verifica e aggiungi" + }, "passkeyName": "Nome", "noPasskeys": "Nessuna passkey registrata.", "addPasskey": "Aggiungi passkey", @@ -5622,8 +5634,8 @@ "nightscoutTokenOptional": "Facoltativo per un sito pubblico", "nightscoutTokenSavedPlaceholder": "Salvato — inserisci un nuovo token per sostituirlo", "nightscoutTokenHelp": "Incolla un token di accesso dagli strumenti di amministrazione di Nightscout. Lascia vuoto se il tuo sito è leggibile pubblicamente.", - "nightscoutPrivateHost": "Questo sito è su una rete privata", - "nightscoutPrivateHostHelp": "Attiva solo se la tua istanza Nightscout è su un indirizzo LAN, VPN o Tailscale. Disattivato per i siti pubblici.", + "nightscoutPrivateOperatorTitle": "L’accesso a un Nightscout privato richiede l’approvazione dell’amministratore del server.", + "nightscoutPrivateOperatorDescription": "Chiedi all’amministratore del server di approvare esattamente questa origine Nightscout.", "nightscoutConnect": "Connetti", "nightscoutUpdate": "Salva modifiche", "nightscoutConnected": "Nightscout connesso.", @@ -8581,7 +8593,6 @@ "notRecorded": "Non registrato", "unreadable": "Impossibile leggere il valore salvato", "save": "Salva", - "correct": "Correggi", "savedToast": "Contesto dello stile di vita salvato", "saveError": "Impossibile salvare il contesto dello stile di vita", "loadError": "Impossibile caricare il contesto dello stile di vita", @@ -8823,7 +8834,6 @@ "withheld": "Un riepilogo è stato generato ma non ha superato il controllo di sicurezza, quindi non viene mostrato. Puoi riprovare o leggere il documento stesso.", "unavailable": "Non è stato possibile generare un riepilogo per questo documento.", "generate": "Genera riepilogo", - "regenerate": "Genera di nuovo", "generating": "Generazione…" }, "loadError": "Impossibile caricare questo documento.", diff --git a/messages/pl.json b/messages/pl.json index 4d2edb34f..1ccbe428c 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -2252,16 +2252,12 @@ "heroActionAskCoach": "Zapytaj coacha", "healthScore": { "label": "Wynik zdrowia", - "algorithmChanged": "Wynik korzysta teraz z opublikowanych kardiometabolicznych zakresów referencyjnych; masa ciała nie jest już uwzględniana, ponieważ poprzedni cel wynikał ze wzrostu, a nie z celu ustawionego przez użytkownika, codzienna zmienność nastroju i przestrzeganie zaleceń lekowych są działaniami, a nie stanami zdrowia, zaś tętno spoczynkowe i HRV nie mają uniwersalnego celu. Postęp masy ciała pozostaje poniżej jako osobisty kontekst, pozostałe sygnały zachowują własne karty, a nowa liczba nie oznacza zmiany stanu zdrowia.", - "dismissAlgorithmChanged": "Zamknij informację o metodzie", "band": { "green": "W zakresie referencyjnym", "yellow": "Niektóre filary wymagają uwagi", "red": "Co najmniej jeden filar jest poza zakresem referencyjnym" }, - "method": "Średnia z równą wagą kwalifikujących się filarów. Najniższy filar wyznacza ogólny zakres.", "insufficient": "{count} kwalifikujące się filary. Wynik wymaga co najmniej trzech, w tym zmierzonego filaru fizjologicznego.", - "composition": "Uwzględniono: {pillars}", "bandSetter": "Ogólny zakres wyznacza {pillar}", "versionAndNoise": "Wersja metody {version}. Próg porównania tygodniowego: {noise} pkt.", "methodVersion": "Wersja metody {version}.", @@ -4614,6 +4610,7 @@ "rowsImported": "Zaimportowano dotąd {count} wierszy", "doneSummary": "Gotowe — zaimportowano {imported} z {read} rekordów, pominięto {skipped} rekordów klinicznych.", "doneNothing": "Z tego archiwum nic nie zaimportowano: dotarło 0 z {read} rekordów.", + "ecgResult": "EKG: wykryto {discovered}, zaimportowano {imported}, zaktualizowano {updated}, pominięto {skipped}, nie powiodło się {failed}. Błędy EKG nie usuwają obsługiwanych rekordów zaimportowanych z pliku export.xml.", "estimateWarning": "Łączne wartości dla {count} dni oszacowano na podstawie największego źródła w eksporcie. Natywne statystyki Apple Health pozostają nadrzędne.", "phase": { "queued": "W kolejce…", @@ -4930,6 +4927,21 @@ "passwordUpdated": "Hasło zaktualizowane pomyślnie", "passkeys": "Passkeys", "passkeysDescription": "Klucze dostępu umożliwiają bezpieczne logowanie bez hasła.", + "passkeyReauth": { + "title": "Potwierdź swoją tożsamość", + "description": "Przed dodaniem nowego klucza dostępu zweryfikuj jedną z istniejących metod logowania.", + "methodLabel": "Metoda weryfikacji", + "methods": { + "password": "Hasło", + "totp": "Kod z aplikacji uwierzytelniającej", + "passkey": "Klucz dostępu", + "webauthn": "Klucz bezpieczeństwa" + }, + "currentPassword": "Aktualne hasło", + "authenticatorCode": "Kod z aplikacji uwierzytelniającej", + "authenticatorPlaceholder": "6-cyfrowy kod z aplikacji uwierzytelniającej", + "verifyAndAdd": "Zweryfikuj i dodaj" + }, "passkeyName": "Nazwa", "noPasskeys": "Brak zarejestrowanych kluczy dostępu.", "addPasskey": "Dodaj klucz dostępu", @@ -5622,8 +5634,8 @@ "nightscoutTokenOptional": "Opcjonalny dla witryny publicznej", "nightscoutTokenSavedPlaceholder": "Zapisano — wpisz nowy token, aby go zastąpić", "nightscoutTokenHelp": "Wklej token dostępu z narzędzi administracyjnych Nightscout. Pozostaw puste, jeśli witryna jest publicznie czytelna.", - "nightscoutPrivateHost": "Ta witryna działa w sieci prywatnej", - "nightscoutPrivateHostHelp": "Włącz tylko, jeśli instancja Nightscout znajduje się pod adresem LAN, VPN lub Tailscale. Wyłączone dla witryn publicznych.", + "nightscoutPrivateOperatorTitle": "Dostęp do prywatnego serwera Nightscout wymaga zgody administratora serwera.", + "nightscoutPrivateOperatorDescription": "Poproś administratora serwera o zatwierdzenie dokładnie tego pochodzenia Nightscout.", "nightscoutConnect": "Połącz", "nightscoutUpdate": "Zapisz zmiany", "nightscoutConnected": "Nightscout połączony.", @@ -8581,7 +8593,6 @@ "notRecorded": "Brak danych", "unreadable": "Nie udało się odczytać zapisanej wartości", "save": "Zapisz", - "correct": "Popraw", "savedToast": "Zapisano kontekst stylu życia", "saveError": "Nie udało się zapisać kontekstu stylu życia", "loadError": "Nie udało się wczytać kontekstu stylu życia", @@ -8823,7 +8834,6 @@ "withheld": "Podsumowanie zostało wygenerowane, ale nie przeszło kontroli bezpieczeństwa, więc nie jest wyświetlane. Możesz spróbować ponownie lub przeczytać sam dokument.", "unavailable": "Nie udało się wygenerować podsumowania dla tego dokumentu.", "generate": "Wygeneruj podsumowanie", - "regenerate": "Wygeneruj ponownie", "generating": "Generowanie…" }, "loadError": "Nie udało się wczytać tego dokumentu.", diff --git a/src/__tests__/v1341-locale-parity.test.ts b/src/__tests__/v1341-locale-parity.test.ts index b1993b23f..69c39370b 100644 --- a/src/__tests__/v1341-locale-parity.test.ts +++ b/src/__tests__/v1341-locale-parity.test.ts @@ -95,11 +95,7 @@ function readCatalog(locale: (typeof LOCALES)[number]): Catalog { function resolveLeaf(catalog: Catalog, dottedKey: string): string | undefined { let value: unknown = catalog; for (const segment of dottedKey.split(".")) { - if ( - typeof value !== "object" || - value === null || - !(segment in value) - ) { + if (typeof value !== "object" || value === null || !(segment in value)) { return undefined; } value = (value as Record)[segment]; @@ -123,7 +119,7 @@ describe("v1.34.1 locale reconciliation", () => { const source = readFileSync(join(ROOT, relativePath), "utf8"); for (const key of keys) { expect(source, `${relativePath} must translate ${key}`).toMatch( - new RegExp(`\\bt\\(["']${key.replaceAll(".", "\\.")}["']`), + new RegExp(`\\bt\\(\\s*["']${key.replaceAll(".", "\\.")}["']`), ); } } diff --git a/src/lib/__tests__/i18n-locale-integrity.test.ts b/src/lib/__tests__/i18n-locale-integrity.test.ts index 44084cd26..bc739d32d 100644 --- a/src/lib/__tests__/i18n-locale-integrity.test.ts +++ b/src/lib/__tests__/i18n-locale-integrity.test.ts @@ -360,13 +360,11 @@ describe("i18n locale file integrity", () => { } }); - it("Health Score transparency keys resolve in every locale", () => { + it("retained Health Score transparency keys resolve in every locale", () => { const transparencyKeys = [ - "insights.healthScore.algorithmChanged", - "insights.healthScore.method", - "insights.healthScore.composition", "insights.healthScore.bandSetter", "insights.healthScore.versionAndNoise", + "insights.healthScore.methodVersion", "insights.healthScore.observed", "insights.healthScore.reference", "insights.healthScore.source",