diff --git a/android-client/PMA.Biometric.pas b/android-client/PMA.Biometric.pas index 0ff3846..5ce4a59 100644 --- a/android-client/PMA.Biometric.pas +++ b/android-client/PMA.Biometric.pas @@ -104,12 +104,12 @@ begin try if not AcquireService(LSvc) then begin - FLastError := 'service biometrique absent de la plateforme'; + FLastError := 'biometric service missing from the platform'; Exit(False); end; Result := LSvc.CanAuthenticate; if not Result then - FLastError := 'CanAuthenticate: aucune protection utilisable'; + FLastError := 'CanAuthenticate: no usable protection'; except on E: Exception do begin @@ -136,7 +136,7 @@ begin FLastError := ''; if not AcquireService(LSvc) then begin - FLastError := 'service biometrique absent de la plateforme'; + FLastError := 'biometric service missing from the platform'; AThen(boFailed); // pas boUnavailable : on ne sait rien de l'appareil Exit; end; @@ -144,7 +144,7 @@ begin if not LSvc.CanAuthenticate then begin // Reponse NETTE du systeme : l'appareil n'a rien pour authentifier. - FLastError := 'CanAuthenticate: aucune protection utilisable'; + FLastError := 'CanAuthenticate: no usable protection'; AThen(boUnavailable); Exit; end; @@ -158,9 +158,9 @@ begin end; LProps := Default(TBiometricPromptProperties); - LProps.Title := 'Deverrouiller le coffre'; + LProps.Title := 'Unlock the vault'; LProps.Description := APrompt; - LProps.CancelButtonText := 'Annuler'; + LProps.CancelButtonText := 'Cancel'; LSvc.SetPromptProperties(LProps); // Meme raison que plus haut : ce qui remonte de la couche Java doit diff --git a/android-client/PMA.Clipboard.pas b/android-client/PMA.Clipboard.pas index 94ba175..c782cf4 100644 --- a/android-client/PMA.Clipboard.pas +++ b/android-client/PMA.Clipboard.pas @@ -68,7 +68,7 @@ begin // contenu, seulement son origine. // Les DEUX arguments sont des CharSequence : passer un JString au premier // compile ailleurs mais pas ici. - LClip := TJClipData.JavaClass.newPlainText(StrToJCharSequence('coffre'), + LClip := TJClipData.JavaClass.newPlainText(StrToJCharSequence('vault'), StrToJCharSequence(AText)); LExtras := TJPersistableBundle.JavaClass.init; LExtras.putBoolean(StringToJString(EXTRA_IS_SENSITIVE), True); diff --git a/android-client/PMA.Store.pas b/android-client/PMA.Store.pas index 0bc5003..7948158 100644 --- a/android-client/PMA.Store.pas +++ b/android-client/PMA.Store.pas @@ -594,7 +594,7 @@ begin LStore := OpenKeyStore; LCert := LStore.getCertificate(StringToJString(KEY_ALIAS_WRAP)); if LCert = nil then - raise EPMAStore.Create('Cle publique introuvable dans le Keystore'); + raise EPMAStore.Create('Public key not found in the Keystore'); LPub := LCert.getPublicKey; LFactory := TJKeyFactoryX.JavaClass.getInstance(LPub.getAlgorithm); Result := LFactory.generatePublic( @@ -804,7 +804,7 @@ begin end; {$ELSE} begin - raise EPMAStore.Create('Le stockage Keystore est propre a Android'); + raise EPMAStore.Create('Keystore storage is Android-only'); end; {$ENDIF} diff --git a/android-client/PMA.Vault.pas b/android-client/PMA.Vault.pas index 86c06b9..2eb8201 100644 --- a/android-client/PMA.Vault.pas +++ b/android-client/PMA.Vault.pas @@ -110,7 +110,7 @@ begin Result := Title.Trim; if Result = '' then Result := Site.Trim; if Result = '' then Result := Username.Trim; - if Result = '' then Result := '(sans nom)'; + if Result = '' then Result := '(no name)'; end; { TVault } @@ -206,7 +206,7 @@ begin Clear; LRoot := TJSONObject.ParseJSONValue(APlainJson) as TJSONObject; if LRoot = nil then - raise Exception.Create('Instantane illisible : ce n''est pas du JSON'); + raise Exception.Create('Snapshot unreadable: this is not JSON'); try FUsername := LRoot.GetValue('username', ''); FExportedAt := LRoot.GetValue('exported_at', @@ -228,7 +228,7 @@ begin end; if not LRoot.TryGetValue('entries', LArr) then - raise Exception.Create('Instantane sans tableau "entries"'); + raise Exception.Create('Snapshot has no "entries" array'); SetLength(FEntries, LArr.Count); N := 0; diff --git a/mainApk.pas b/mainApk.pas index 94eb352..c1fc5e2 100644 --- a/mainApk.pas +++ b/mainApk.pas @@ -1,4 +1,4 @@ -unit mainApk; +unit mainApk; { Client Android en LECTURE SEULE : deverrouiller, chercher, copier. @@ -218,7 +218,7 @@ var LEvents: IFMXApplicationEventService; begin inherited; - Caption := 'Coffre'; + Caption := 'Vault'; // Le fond de la forme, et non celui du style : tout le reste est peint // par-dessus, et un gris herite se verrait entre les blocs. Fill.Kind := TBrushKind.Solid; @@ -328,8 +328,8 @@ begin FLaySettings.Align := TAlignLayout.Top; FLaySettings.Height := 116; FLaySettings.Visible := False; - FToken := TopEdit(FLaySettings, 'jeton Bearer', FIRSTRUN_TOKEN); - FUrl := TopEdit(FLaySettings, 'URL de l''endpoint', FIRSTRUN_URL); + FToken := TopEdit(FLaySettings, 'bearer token', FIRSTRUN_TOKEN); + FUrl := TopEdit(FLaySettings, 'endpoint URL', FIRSTRUN_URL); FToken.Margins.Rect := RectF(16, 8, 16, 0); FUrl.Margins.Rect := RectF(16, 8, 16, 0); // Ce que l'appareil a retenu l'emporte sur les valeurs de premier lancement. @@ -347,20 +347,20 @@ begin LRow.Height := 48; LRow.Margins.Rect := RectF(16, 8, 16, 0); - FBtnLog := FlatButton(LRow, 'Journal', OnToggleLog); + FBtnLog := FlatButton(LRow, 'Log', OnToggleLog); FBtnLog.Align := TAlignLayout.Right; FBtnLog.Width := 120; FBtnLog.Margins.Left := 8; - FBtnSettings := FlatButton(LRow, 'Reglages du serveur', OnToggleSettings); + FBtnSettings := FlatButton(LRow, 'Server settings', OnToggleSettings); FBtnSettings.Align := TAlignLayout.Client; - FBtnSync := TopButton(FLayUnlock, 'Synchroniser', DoSync); + FBtnSync := TopButton(FLayUnlock, 'Sync', DoSync); // Accentue : c'est l'action attendue quand aucun coffre n'est encore la. - FBtnOpen := TopButton(FLayUnlock, 'Ouvrir le coffre', DoOpenLocal, 52, True); + FBtnOpen := TopButton(FLayUnlock, 'Open vault', DoOpenLocal, 52, True); // Pre-rempli depuis le fichier local, jamais depuis ce fichier-ci. - FPwd := TopEdit(FLayUnlock, 'mot de passe de sync', TEST_PWD, True); + FPwd := TopEdit(FLayUnlock, 'sync password', TEST_PWD, True); FPwd.Margins.Rect := RectF(16, 16, 16, 0); FStatus := TLabel.Create(Self); @@ -386,7 +386,7 @@ begin LBar.Align := TAlignLayout.Bottom; LBar.Height := 52; - LBtnLock := FlatButton(LBar, 'Verrouiller', OnBackTap); + LBtnLock := FlatButton(LBar, 'Lock', OnBackTap); LBtnLock.Align := TAlignLayout.Left; LBtnLock.Margins.Rect := RectF(16, 4, 0, 8); LBtnLock.Width := 140; @@ -422,7 +422,7 @@ begin // // Bouton peint et non TComboBox : le combo etait l'un des deux derniers // controles a porter encore le style, et il jurait avec le reste. - FBtnFolder := FlatButton(LTop, 'Tous les dossiers', OnFolderTap); + FBtnFolder := FlatButton(LTop, 'All folders', OnFolderTap); FBtnFolder.Align := TAlignLayout.Right; FBtnFolder.Width := 170; FBtnFolder.Margins.Left := 8; @@ -445,7 +445,7 @@ begin FSearchHint.Margins.Left := 10; FSearchHint.HitTest := False; FSearchHint.Opacity := 0.45; - FSearchHint.Text := 'Rechercher'; + FSearchHint.Text := 'Search'; end; /// Intitule discret au-dessus d'une valeur. Meme forme pour toutes les @@ -504,7 +504,7 @@ begin FLayDetail.Align := TAlignLayout.Client; FLayDetail.Visible := False; - LBtnBack := FlatButton(FLayDetail, 'Retour', OnBackTap); + LBtnBack := FlatButton(FLayDetail, 'Back', OnBackTap); LBtnBack.Align := TAlignLayout.Bottom; LBtnBack.Height := 52; LBtnBack.Margins.Rect := RectF(16, 8, 16, 8); @@ -547,15 +547,15 @@ begin if HasVault then begin if VaultNeedsAuth then - Status('Coffre present sur cet appareil - protege') + Status('Vault on this device - protected') else - Status('Coffre present sur cet appareil'); - SetButtonText(FBtnSync, 'Synchroniser'); + Status('Vault on this device'); + SetButtonText(FBtnSync, 'Sync'); end else begin - Status('Aucun coffre local - premier telechargement'); - SetButtonText(FBtnSync, 'Telecharger le coffre'); + Status('No local vault - first download'); + SetButtonText(FBtnSync, 'Download vault'); end; end; @@ -635,10 +635,10 @@ begin // Le corps d'une note est stocke dans le champ mot de passe : meme donnee, // autre intitule, et pas de raison de la masquer comme un secret. - if FCurrent.IsNote then LPwdCaption := 'Contenu' else LPwdCaption := 'Mot de passe'; + if FCurrent.IsNote then LPwdCaption := 'Content' else LPwdCaption := 'Password'; Add('Site', FCurrent.Site, False); - Add('Identifiant', FCurrent.Username, False); + Add('Username', FCurrent.Username, False); Add(LPwdCaption, FCurrent.Password, not FCurrent.IsNote); for I := 0 to High(FCurrent.Fields) do Add(FCurrent.Fields[I].Caption, FCurrent.Fields[I].Value, @@ -658,16 +658,16 @@ begin // rendu bidirectionnel de FMX en fait n'importe quoi. Separes, chacun se // lit dans son sens. for I := 0 to High(FCurrent.Attachments) do - Add('Piece jointe - ' + HumanSize(FCurrent.Attachments[I].SizeBytes), + Add('Attachment - ' + HumanSize(FCurrent.Attachments[I].SizeBytes), FCurrent.Attachments[I].FileName, False); - Add('Dossier / etiquettes', LMeta, False); + Add('Folder / tags', LMeta, False); // Le sous-type n'existe que pour les modeles (carte, cle SSH, serveur...) ; // Add ignore une valeur vide, donc rien a tester ici. Add('Type', FCurrent.Template, False); // Horodatage tel quel : c'est de l'ISO 8601 UTC, lisible, et le reformater // demanderait de decider d'un fuseau alors qu'il n'y a rien a arbitrer. - Add('Modifie le', FCurrent.UpdatedAt, False); + Add('Updated', FCurrent.UpdatedAt, False); SetLength(FRowValues, Length(FRows)); SetLength(FRowShown, Length(FRows)); @@ -678,12 +678,12 @@ begin LOrder := 0; if FCurrent.Totp <> '' then begin - LRow := MakeRow(FDetBody, 'Code 2FA', LOrder, FTotpValue); + LRow := MakeRow(FDetBody, '2FA code', LOrder, FTotpValue); Inc(LOrder); SetLength(FRowCtls, Length(FRowCtls) + 1); FRowCtls[High(FRowCtls)] := LRow; FTotpValue.TextSettings.Font.Size := 26; - AddRowButton(LRow, 'Copier', -1, OnCopyTap); + AddRowButton(LRow, 'Copy', -1, OnCopyTap); OnTotpTick(nil); // pas d'attente d'une seconde a l'ouverture FTotpTimer.Enabled := True; end; @@ -698,11 +698,11 @@ begin if FRows[I].Secret then begin LValue.Text := MASK; - AddRowButton(LRow, 'Afficher', I, OnRevealTap); + AddRowButton(LRow, 'Show', I, OnRevealTap); end else LValue.Text := FRows[I].Value; - AddRowButton(LRow, 'Copier', I, OnCopyTap); + AddRowButton(LRow, 'Copy', I, OnCopyTap); end; // La derniere ligne affichee touche sinon le bord du defilement, ce qui la // fait passer pour tronquee alors qu'elle est juste collee. @@ -728,7 +728,7 @@ begin if FTotpCode = '' then begin // Un secret illisible ne doit pas passer pour un code : le dire. - FTotpValue.Text := 'secret illisible'; + FTotpValue.Text := 'unreadable secret'; FTotpTimer.Enabled := False; Exit; end; @@ -810,8 +810,8 @@ end; procedure TForm8.AdoptVault(const APlainJson: string); begin FVault.LoadFromJson(APlainJson); - Log(' ' + FVault.LiveCount.ToString + ' entrees, ' + - FVault.TrashCount.ToString + ' en corbeille'); + Log(' ' + FVault.LiveCount.ToString + ' entries, ' + + FVault.TrashCount.ToString + ' in trash'); RebuildIcons; PopulateFolders; Touch; @@ -845,7 +845,7 @@ begin on E: Exception do begin // Un coffre local illisible se remplace, il ne se repare pas. - Log('Coffre local corrompu : ' + E.Message); + Log('Local vault corrupt: ' + E.Message); ClearVault; ShowUnlock; end; @@ -856,8 +856,8 @@ begin // ShowUnlock AVANT le message : il repositionne le statut selon ce que // l'appareil detient, et ecraserait donc l'explication. ShowUnlock; - Log('Coffre local illisible : ' + LastStoreError); - Status('Coffre local illisible - voir le journal'); + Log('Local vault unreadable: ' + LastStoreError); + Status('Local vault unreadable - see log'); end; end; @@ -877,13 +877,13 @@ begin Exit; end; - if not AAuto then Status('Authentification...'); - AuthenticateThen('Acceder au coffre', + if not AAuto then Status('Authenticating...'); + AuthenticateThen('Unlock the vault', procedure(AOutcome: TBioOutcome) begin case AOutcome of boOK: OpenLocalNow; - boCancelled: Status('Annule'); + boCancelled: Status('Cancelled'); boUnavailable: // Reponse nette du systeme : plus rien pour authentifier sur cet // appareil, donc la cle est perdue et le cache avec elle. @@ -895,13 +895,13 @@ begin // masquerait la vraie cause. L'utilisateur tranche en reessayant. if AAuto then begin - Log('Authentification indisponible au lancement - cache conserve'); + Log('Authentication unavailable at launch - cache kept'); Log(' ' + LastBiometricError); - Status('Authentification indisponible - reessayer'); + Status('Authentication unavailable - try again'); end else begin - Log('Plus aucune protection sur l''appareil - cache efface'); + Log('No protection left on this device - cache cleared'); Log(' ' + LastBiometricError); ClearVault; ShowUnlock; @@ -909,8 +909,8 @@ begin else // boFailed : la couche Java a leve quelque chose. Cela ne dit rien de // l'appareil, donc on ne touche a rien - on rapporte. - Log('Echec de l''authentification : ' + LastBiometricError); - Status('Echec de l''authentification'); + Log('Authentication failed: ' + LastBiometricError); + Status('Authentication failed'); end; end); end; @@ -930,7 +930,7 @@ begin if LPwd = '' then LPwd := FSyncPwd; if LPwd = '' then begin - Status('Mot de passe de sync requis'); + Status('Sync password required'); Exit; end; FLog.Lines.Clear; @@ -942,16 +942,16 @@ begin // cet appareil - c'est lui qui exprime le choix de l'utilisateur. if VaultNeedsAuth and (FVault.Count = 0) then begin - Status('Authentification...'); - AuthenticateThen('Acceder au coffre', + Status('Authenticating...'); + AuthenticateThen('Unlock the vault', procedure(AOutcome: TBioOutcome) begin if AOutcome = boOK then FetchAndDecrypt(LUrl, LTok, LPwd) else begin - Log('Synchronisation refusee : ' + LastBiometricError); - Status('Authentification requise'); + Log('Sync refused: ' + LastBiometricError); + Status('Authentication required'); end; end); Exit; @@ -966,7 +966,7 @@ var LCanAuth: Boolean; begin SetBusy(True); - if not ASilent then Status('Telechargement...'); + if not ASilent then Status('Downloading...'); // NE JAMAIS FERMER LE CACHE DERRIERE UNE PORTE QU'ON NE SAIT PAS OUVRIR. // Demander une cle protegee par authentification alors que l'invite ne peut // pas s'afficher (permission absente, aucune protection configuree) produit @@ -997,7 +997,7 @@ begin LSw := TStopwatch.StartNew; LRes := LClient.Fetch(FETag); LSw.Stop; - Log(' HTTP ' + LRes.HttpCode.ToString + ' en ' + + Log(' HTTP ' + LRes.HttpCode.ToString + ' in ' + LSw.ElapsedMilliseconds.ToString + ' ms'); case LRes.Status of @@ -1018,14 +1018,14 @@ begin // rafraichissement de fond c'est le cas courant, et il // doit passer inapercu - surtout pas de retour a la liste // alors que l'utilisateur consulte une entree. - Log(' 304 : inchange, coffre deja ouvert') + Log(' 304: unchanged, vault already open') else if LCached <> '' then begin - Log(' 304 : inchange, coffre servi depuis le cache'); + Log(' 304: unchanged, vault served from cache'); try AdoptVault(LCached); except - on E: Exception do Status('Cache illisible : ' + E.Message); + on E: Exception do Status('Cache unreadable: ' + E.Message); end; end else @@ -1034,7 +1034,7 @@ begin // On le jette pour que l'appel suivant retelecharge. FETag := ''; if not ASilent then - Status('Cache absent - appuyer a nouveau pour telecharger'); + Status('No cache - tap again to download'); end; end); Exit; @@ -1042,10 +1042,10 @@ begin ssNoSnapshot: begin // Le serveur repond pareil dans les deux cas, par conception. - Log(' 404 : pas d''instantane OU jeton invalide'); + Log(' 404: no snapshot OR invalid token'); if not ASilent then TThread.Queue(nil, procedure - begin Status('Rien a telecharger (404)'); end); + begin Status('Nothing to download (404)'); end); Exit; end; ssRefused, ssHttpError, ssNetworkError: @@ -1053,17 +1053,17 @@ begin // En fond, un echec reseau ne se signale pas : le coffre local // est affiche, hors ligne est un etat normal, et une alerte ici // apprendrait a l'utilisateur a ignorer les alertes. - Log(' echec : ' + LRes.Error); + Log(' failed: ' + LRes.Error); if not ASilent then TThread.Queue(nil, procedure - begin Status('Echec reseau'); end); + begin Status('Network failure'); end); Exit; end; end; - Log(' recu ' + Length(LRes.Container).ToString + ' octets'); + Log(' received ' + Length(LRes.Container).ToString + ' bytes'); if not ASilent then - TThread.Queue(nil, procedure begin Status('Dechiffrement...'); end); + TThread.Queue(nil, procedure begin Status('Decrypting...'); end); LSw := TStopwatch.StartNew; // Volontairement AVANT de retenir l'ETag : un echec ici doit laisser @@ -1071,7 +1071,7 @@ begin LPlain := DecryptContainer(LRes.Container, APwd); LSw.Stop; FETag := LRes.ETag; - Log(' dechiffre en ' + LSw.ElapsedMilliseconds.ToString + ' ms'); + Log(' decrypted in ' + LSw.ElapsedMilliseconds.ToString + ' ms'); // Ecrit APRES un dechiffrement reussi seulement, et avec son ETag : // les deux doivent rester coherents. @@ -1083,16 +1083,16 @@ begin // pas des reglages saisis, on enregistre des reglages EPROUVES. SaveDeviceSettings(AUrl, ATok); if VaultNeedsAuth then - Log(' cache ecrit - protege par biometrie/code') + Log(' cache written - protected by biometrics/PIN') else if LCanAuth then - Log(' cache ecrit - cle simple (Keystore a refuse la contrainte)') + Log(' cache written - plain key (Keystore refused the constraint)') else - Log(' cache ecrit - AUCUNE protection : pas d''authentification ici'); + Log(' cache written - NO protection: no authentication here'); except // La classe compte autant que le message : "methode introuvable" // designe une signature JNI fausse, pas un probleme de stockage. on E: Exception do - Log(' cache non ecrit : ' + E.ClassName + ' - ' + E.Message); + Log(' cache not written: ' + E.ClassName + ' - ' + E.Message); end; TThread.Queue(nil, @@ -1104,13 +1104,13 @@ begin except on E: Exception do if not ASilent then - Status('Instantane illisible : ' + E.Message); + Status('Snapshot unreadable: ' + E.Message); end; end); except on E: Exception do begin - Log('ERREUR ' + E.ClassName + ' : ' + E.Message); + Log('ERROR ' + E.ClassName + ' : ' + E.Message); // Le cas de loin le plus frequent, et le message par defaut ne le // dit pas : GCM echoue a la verification quand la cle est fausse. // @@ -1120,7 +1120,7 @@ begin // le champ prerempli, et le coffre local reste consultable. if not ASilent then TThread.Queue(nil, procedure - begin Status('Echec - mot de passe de sync incorrect ?'); end); + begin Status('Failed - wrong sync password?'); end); end; end; finally @@ -1188,7 +1188,7 @@ begin LPrev := FFolderNames[FFolderSel]; SetLength(FFolderNames, 1); - FFolderNames[0] := 'Tous les dossiers'; + FFolderNames[0] := 'All folders'; for LF in FVault.Folders do begin SetLength(FFolderNames, Length(FFolderNames) + 1); @@ -1341,7 +1341,7 @@ begin end; if (FSearch.Text.Trim = '') and (LFolder = '') then - FCount.Text := FVault.LiveCount.ToString + ' entrees' + FCount.Text := FVault.LiveCount.ToString + ' entries' else FCount.Text := Length(FFiltered).ToString + ' / ' + FVault.LiveCount.ToString; @@ -1369,12 +1369,12 @@ begin if FRowShown[I] then begin FRowValues[I].Text := FRows[I].Value; - SetButtonText(TRectangle(Sender), 'Masquer'); + SetButtonText(TRectangle(Sender), 'Hide'); end else begin FRowValues[I].Text := MASK; - SetButtonText(TRectangle(Sender), 'Afficher'); + SetButtonText(TRectangle(Sender), 'Show'); end; end; @@ -1388,7 +1388,7 @@ begin // -1 : la ligne du TOTP, qui n'est pas dans FRows - sa valeur change chaque // periode et ne vit que dans FTotpCode. Copie sans l'espace d'affichage. if I = -1 then - CopyToClipboard(FTotpCode, 'Code 2FA') + CopyToClipboard(FTotpCode, '2FA code') else if (I >= 0) and (I <= High(FRows)) then CopyToClipboard(FRows[I].Value, FRows[I].Caption); end; @@ -1408,7 +1408,7 @@ begin // ponytail: le message reste jusqu'a la prochaine navigation, pas de minuterie // pour l'effacer. Un deuxieme TTimer pour deux secondes d'affichage serait // plus de code que ce que ca apporte. - FDetToast.Text := ALabel + ' copie - presse-papiers efface dans ' + + FDetToast.Text := ALabel + ' copied - clipboard cleared in ' + CLIPBOARD_CLEAR_SECONDS.ToString + ' s'; end; @@ -1477,7 +1477,7 @@ begin end; if MinutesBetween(Now, FLastActivity) >= AUTOLOCK_MINUTES then begin - Log('Verrouille apres ' + AUTOLOCK_MINUTES.ToString + ' min d''inactivite'); + Log('Locked after ' + AUTOLOCK_MINUTES.ToString + ' min idle'); LockVault; end; end;