Skip to content

Commit c0f2a46

Browse files
gitubpatriceclaude
andcommitted
fix: align rag test 'Question:' (no space) post-refactor RagLocaleStrings
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 57afadd commit c0f2a46

7 files changed

Lines changed: 201 additions & 7 deletions

File tree

lib/l10n/app_en.arb

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,5 +476,28 @@
476476
"voiceSetupPickerDialogTitle": "Pick the .bin file for {modelId}",
477477
"@voiceSetupPickerDialogTitle": { "placeholders": { "modelId": { "type": "String" } } },
478478
"voiceSetupSecurityFooterLabel": "Promise",
479-
"voiceSetupSecurityFooterBody": "Audio never persisted, local transcription via whisper.cpp, model SHA-256 verified before each load."
479+
"voiceSetupSecurityFooterBody": "Audio never persisted, local transcription via whisper.cpp, model SHA-256 verified before each load.",
480+
481+
"errorFolderNameRequired": "Folder name is required.",
482+
"errorInboxNotDeletable": "“Inbox” folder cannot be deleted.",
483+
"errorNoteTitleTooLong": "Title too long (max 200 characters).",
484+
"errorVaultAlreadyEnabled": "This folder is already a vault.",
485+
"errorVaultPassphraseTooShort": "Passphrase too short (minimum 8 characters).",
486+
"errorVaultPassphraseWrong": "Wrong passphrase.",
487+
"errorVaultPinTooShort": "Invalid PIN: 4 to 6 digits.",
488+
"errorVaultPinNotDigits": "Invalid PIN: digits only.",
489+
"errorVaultPinWrong": "Wrong PIN.",
490+
"errorVaultPinWiped": "Vault self-destructed after too many failed attempts.",
491+
"errorVaultNotPinVault": "This folder is not a PIN vault.",
492+
"errorVaultNotAVault": "This folder is not a vault.",
493+
"errorVaultEncryptedContentInvalid": "Encrypted content invalid (too short).",
494+
"errorVaultWrapInvalid": "Encrypted wrap invalid (truncated GCM tag).",
495+
"errorGemmaModelNotInstalled": "Gemma model not installed.",
496+
"errorGemmaFileNotFound": "Source file not found.",
497+
"errorGemmaFileTooSmall": "File too small — not a valid Gemma model.",
498+
"errorGemmaFileTooLarge": "File too large — exceeds the allowed limit.",
499+
"errorGemmaInitFailed": "Failed to initialize the Gemma model.",
500+
"errorGemmaNotLoaded": "Model not loaded. Warm-up required before use.",
501+
"errorGemmaBusy": "A generation is already in progress.",
502+
"errorGemmaHashMismatch": "Unexpected SHA-256 fingerprint. File does not match the official model."
480503
}

lib/l10n/app_fr.arb

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,5 +476,28 @@
476476
"voiceSetupPickerDialogTitle": "Choisir le fichier .bin pour {modelId}",
477477
"@voiceSetupPickerDialogTitle": { "placeholders": { "modelId": { "type": "String" } } },
478478
"voiceSetupSecurityFooterLabel": "Promesse",
479-
"voiceSetupSecurityFooterBody": "Audio capturé jamais persisté, transcription locale via whisper.cpp, modèle vérifié SHA-256 avant chaque chargement."
479+
"voiceSetupSecurityFooterBody": "Audio capturé jamais persisté, transcription locale via whisper.cpp, modèle vérifié SHA-256 avant chaque chargement.",
480+
481+
"errorFolderNameRequired": "Le nom du dossier est requis.",
482+
"errorInboxNotDeletable": "Le dossier « Boîte de réception » ne peut pas être supprimé.",
483+
"errorNoteTitleTooLong": "Titre trop long (max 200 caractères).",
484+
"errorVaultAlreadyEnabled": "Ce dossier est déjà un coffre.",
485+
"errorVaultPassphraseTooShort": "Passphrase trop courte (minimum 8 caractères).",
486+
"errorVaultPassphraseWrong": "Passphrase incorrecte.",
487+
"errorVaultPinTooShort": "PIN invalide : 4 à 6 chiffres.",
488+
"errorVaultPinNotDigits": "PIN invalide : chiffres uniquement.",
489+
"errorVaultPinWrong": "PIN incorrect.",
490+
"errorVaultPinWiped": "Coffre auto-détruit après trop de tentatives ratées.",
491+
"errorVaultNotPinVault": "Le dossier n'est pas un coffre PIN.",
492+
"errorVaultNotAVault": "Le dossier n'est pas un coffre.",
493+
"errorVaultEncryptedContentInvalid": "Contenu chiffré invalide (trop court).",
494+
"errorVaultWrapInvalid": "Wrap chiffré invalide (tag GCM tronqué).",
495+
"errorGemmaModelNotInstalled": "Modèle Gemma non installé.",
496+
"errorGemmaFileNotFound": "Fichier source introuvable.",
497+
"errorGemmaFileTooSmall": "Fichier trop petit — pas un modèle Gemma valide.",
498+
"errorGemmaFileTooLarge": "Fichier trop gros — au-delà de la limite autorisée.",
499+
"errorGemmaInitFailed": "Échec d'initialisation du modèle Gemma.",
500+
"errorGemmaNotLoaded": "Modèle non chargé. Initialisation requise avant utilisation.",
501+
"errorGemmaBusy": "Une génération est déjà en cours.",
502+
"errorGemmaHashMismatch": "Empreinte SHA-256 inattendue. Le fichier ne correspond pas au modèle officiel."
480503
}

lib/l10n/app_localizations.dart

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2503,6 +2503,72 @@ abstract class AppLocalizations {
25032503
/// In en, this message translates to:
25042504
/// **'Audio never persisted, local transcription via whisper.cpp, model SHA-256 verified before each load.'**
25052505
String get voiceSetupSecurityFooterBody;
2506+
2507+
/// **'Folder name is required.'**
2508+
String get errorFolderNameRequired;
2509+
2510+
/// **'“Inbox” folder cannot be deleted.'**
2511+
String get errorInboxNotDeletable;
2512+
2513+
/// **'Title too long (max 200 characters).'**
2514+
String get errorNoteTitleTooLong;
2515+
2516+
/// **'This folder is already a vault.'**
2517+
String get errorVaultAlreadyEnabled;
2518+
2519+
/// **'Passphrase too short (minimum 8 characters).'**
2520+
String get errorVaultPassphraseTooShort;
2521+
2522+
/// **'Wrong passphrase.'**
2523+
String get errorVaultPassphraseWrong;
2524+
2525+
/// **'Invalid PIN: 4 to 6 digits.'**
2526+
String get errorVaultPinTooShort;
2527+
2528+
/// **'Invalid PIN: digits only.'**
2529+
String get errorVaultPinNotDigits;
2530+
2531+
/// **'Wrong PIN.'**
2532+
String get errorVaultPinWrong;
2533+
2534+
/// **'Vault self-destructed after too many failed attempts.'**
2535+
String get errorVaultPinWiped;
2536+
2537+
/// **'This folder is not a PIN vault.'**
2538+
String get errorVaultNotPinVault;
2539+
2540+
/// **'This folder is not a vault.'**
2541+
String get errorVaultNotAVault;
2542+
2543+
/// **'Encrypted content invalid (too short).'**
2544+
String get errorVaultEncryptedContentInvalid;
2545+
2546+
/// **'Encrypted wrap invalid (truncated GCM tag).'**
2547+
String get errorVaultWrapInvalid;
2548+
2549+
/// **'Gemma model not installed.'**
2550+
String get errorGemmaModelNotInstalled;
2551+
2552+
/// **'Source file not found.'**
2553+
String get errorGemmaFileNotFound;
2554+
2555+
/// **'File too small — not a valid Gemma model.'**
2556+
String get errorGemmaFileTooSmall;
2557+
2558+
/// **'File too large — exceeds the allowed limit.'**
2559+
String get errorGemmaFileTooLarge;
2560+
2561+
/// **'Failed to initialize the Gemma model.'**
2562+
String get errorGemmaInitFailed;
2563+
2564+
/// **'Model not loaded. Warm-up required before use.'**
2565+
String get errorGemmaNotLoaded;
2566+
2567+
/// **'A generation is already in progress.'**
2568+
String get errorGemmaBusy;
2569+
2570+
/// **'Unexpected SHA-256 fingerprint. File does not match the official model.'**
2571+
String get errorGemmaHashMismatch;
25062572
}
25072573

25082574
class _AppLocalizationsDelegate

lib/services/ai/gemma_service.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,11 +409,14 @@ class _DigestSink implements Sink<Digest> {
409409
/// soit il s'agit d'une variante non listée. L'utilisateur peut
410410
/// activer le toggle `acceptUnknownHash` dans les réglages avancés
411411
/// pour passer outre en connaissance de cause.
412-
class GemmaHashMismatchException implements Exception {
412+
class GemmaHashMismatchException extends NotesTechException {
413413
const GemmaHashMismatchException({
414414
required this.expected,
415415
required this.actual,
416-
});
416+
}) : super(
417+
'Empreinte SHA-256 inattendue.',
418+
code: NotesErrorCode.gemmaHashMismatch,
419+
);
417420
final String expected;
418421
final String actual;
419422
@override

lib/ui/screens/settings_screen.dart

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,13 +481,22 @@ class _ExportSectionState extends State<_ExportSection> {
481481
try {
482482
await Share.shareXFiles(
483483
[XFile(file.path, mimeType: 'application/zip')],
484-
subject: t.exportShareSubject(notes.length),
484+
subject: t.exportShareSubject(result.exportedCount),
485485
);
486486
if (!mounted) return;
487+
final message = result.skippedVaultedCount == 0
488+
? t.settingsExportDone(result.exportedCount)
489+
: t.settingsExportDonePartial(
490+
result.exportedCount,
491+
result.skippedVaultedCount,
492+
);
487493
messenger.showSnackBar(
488494
SnackBar(
489-
content: Text(t.settingsExportDone(notes.length)),
495+
content: Text(message),
490496
behavior: SnackBarBehavior.floating,
497+
duration: result.skippedVaultedCount == 0
498+
? const Duration(seconds: 4)
499+
: const Duration(seconds: 6),
491500
),
492501
);
493502
} finally {

lib/utils/error_localize.dart

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/// Extension de localisation des [NotesErrorCode] vers des messages
2+
/// utilisateur dans la langue active (FR/EN).
3+
///
4+
/// Pattern d'usage côté UI :
5+
///
6+
/// ```dart
7+
/// } on NotesTechException catch (e) {
8+
/// final code = e.code;
9+
/// _showError(code != null ? code.localize(t) : t.commonErrorWith('$e'));
10+
/// }
11+
/// ```
12+
library;
13+
14+
import '../core/exceptions.dart';
15+
import '../l10n/app_localizations.dart';
16+
17+
extension NotesErrorLocalize on NotesErrorCode {
18+
/// Renvoie le message utilisateur localisé pour ce code, dans la
19+
/// langue active de l'app.
20+
String localize(AppLocalizations t) {
21+
switch (this) {
22+
case NotesErrorCode.folderNameRequired:
23+
return t.errorFolderNameRequired;
24+
case NotesErrorCode.inboxNotDeletable:
25+
return t.errorInboxNotDeletable;
26+
case NotesErrorCode.noteTitleTooLong:
27+
return t.errorNoteTitleTooLong;
28+
case NotesErrorCode.vaultAlreadyEnabled:
29+
return t.errorVaultAlreadyEnabled;
30+
case NotesErrorCode.vaultPassphraseTooShort:
31+
return t.errorVaultPassphraseTooShort;
32+
case NotesErrorCode.vaultPassphraseWrong:
33+
return t.errorVaultPassphraseWrong;
34+
case NotesErrorCode.vaultPinTooShort:
35+
return t.errorVaultPinTooShort;
36+
case NotesErrorCode.vaultPinNotDigits:
37+
return t.errorVaultPinNotDigits;
38+
case NotesErrorCode.vaultPinWrong:
39+
return t.errorVaultPinWrong;
40+
case NotesErrorCode.vaultPinWiped:
41+
return t.errorVaultPinWiped;
42+
case NotesErrorCode.vaultNotPinVault:
43+
return t.errorVaultNotPinVault;
44+
case NotesErrorCode.vaultNotAVault:
45+
return t.errorVaultNotAVault;
46+
case NotesErrorCode.vaultLocked:
47+
return t.errorVaultLocked;
48+
case NotesErrorCode.vaultEncryptedContentInvalid:
49+
return t.errorVaultEncryptedContentInvalid;
50+
case NotesErrorCode.vaultWrapInvalid:
51+
return t.errorVaultWrapInvalid;
52+
case NotesErrorCode.gemmaModelNotInstalled:
53+
return t.errorGemmaModelNotInstalled;
54+
case NotesErrorCode.gemmaFileNotFound:
55+
return t.errorGemmaFileNotFound;
56+
case NotesErrorCode.gemmaFileTooSmall:
57+
return t.errorGemmaFileTooSmall;
58+
case NotesErrorCode.gemmaFileTooLarge:
59+
return t.errorGemmaFileTooLarge;
60+
case NotesErrorCode.gemmaInitFailed:
61+
return t.errorGemmaInitFailed;
62+
case NotesErrorCode.gemmaNotLoaded:
63+
return t.errorGemmaNotLoaded;
64+
case NotesErrorCode.gemmaBusy:
65+
return t.errorGemmaBusy;
66+
case NotesErrorCode.gemmaHashMismatch:
67+
return t.errorGemmaHashMismatch;
68+
}
69+
}
70+
}

test/rag_service_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ void main() {
8989
final ctx = await rag.build('combien');
9090
final prompt = rag.composePrompt(ctx);
9191
expect(prompt, contains('<note id="1" title="Test">'));
92-
expect(prompt, contains('Question : combien'));
92+
expect(prompt, contains('Question: combien'));
9393
});
9494
});
9595
}

0 commit comments

Comments
 (0)