Notification parsing: - Drop the account_bindings table/DAO/repo/entity/controller/screen; account resolution now goes senderToAccount rule -> source_apps.defaultAccountId (trusted) -> global default (untrusted -> Inbox), via v1->v2 migration. - Add defaultAccountId to source_apps; per-app settings consolidated into source_app_detail_screen (/settings/parsing/apps/:pkg). - Inbox auto-learns an app default on first Confirm/CreateRule; account picker on the card instead of a disabled button; parse_error_labels extracted. Analytics: - Replace placeholder screen with fl_chart cards (chart_card, chart_theme, month_stepper, month_math domain helper); slim down habit_analysis_screen. Android: add launcher icon (adaptive foreground + colors.xml) and app_name. Tests: migration_v2, analytics (screen/month_math), AI retry, inbox visibility; update resolver/gate/inbox suites for the new resolution path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1130 lines
25 KiB
Dart
1130 lines
25 KiB
Dart
// ignore: unused_import
|
|
import 'package:intl/intl.dart' as intl;
|
|
import 'app_localizations.dart';
|
|
|
|
// ignore_for_file: type=lint
|
|
|
|
/// The translations for English (`en`).
|
|
class AppLocalizationsEn extends AppLocalizations {
|
|
AppLocalizationsEn([String locale = 'en']) : super(locale);
|
|
|
|
@override
|
|
String get appTitle => 'Kitty finances';
|
|
|
|
@override
|
|
String get navHome => 'Home';
|
|
|
|
@override
|
|
String get navAnalytics => 'Analytics';
|
|
|
|
@override
|
|
String get navAccounts => 'Accounts';
|
|
|
|
@override
|
|
String get navProfile => 'Profile';
|
|
|
|
@override
|
|
String get allAccounts => 'All';
|
|
|
|
@override
|
|
String get comingSoon => 'Coming soon';
|
|
|
|
@override
|
|
String get budget => 'BUDGET';
|
|
|
|
@override
|
|
String get balance => 'BALANCE';
|
|
|
|
@override
|
|
String get income => 'INCOME';
|
|
|
|
@override
|
|
String get expenses => 'EXPENSES';
|
|
|
|
@override
|
|
String get transactions => 'Transactions';
|
|
|
|
@override
|
|
String transactionCount(int count) {
|
|
String _temp0 = intl.Intl.pluralLogic(
|
|
count,
|
|
locale: localeName,
|
|
other: '$count transactions',
|
|
one: '$count transaction',
|
|
);
|
|
return '$_temp0';
|
|
}
|
|
|
|
@override
|
|
String get allCategoriesFilter => 'All categories · all types';
|
|
|
|
@override
|
|
String get filterByCategories => 'Filter by category';
|
|
|
|
@override
|
|
String get clearFilter => 'Clear';
|
|
|
|
@override
|
|
String get selectAll => 'Select all';
|
|
|
|
@override
|
|
String categoriesSelectedCount(int count) {
|
|
String _temp0 = intl.Intl.pluralLogic(
|
|
count,
|
|
locale: localeName,
|
|
other: '$count categories',
|
|
one: '$count category',
|
|
);
|
|
return '$_temp0';
|
|
}
|
|
|
|
@override
|
|
String moreCategories(int count) {
|
|
String _temp0 = intl.Intl.pluralLogic(
|
|
count,
|
|
locale: localeName,
|
|
other: '+ $count more →',
|
|
one: '+ $count more →',
|
|
);
|
|
return '$_temp0';
|
|
}
|
|
|
|
@override
|
|
String todayWithDate(String date) {
|
|
return 'Today · $date';
|
|
}
|
|
|
|
@override
|
|
String yesterdayWithDate(String date) {
|
|
return 'Yesterday · $date';
|
|
}
|
|
|
|
@override
|
|
String get analyticsTitle => 'Reports';
|
|
|
|
@override
|
|
String get analyticsSubtitle => 'Analytics';
|
|
|
|
@override
|
|
String get analyticsNoData => 'No data for this month';
|
|
|
|
@override
|
|
String get accountsSubtitle => 'Management';
|
|
|
|
@override
|
|
String get profileSubtitle => 'Settings';
|
|
|
|
@override
|
|
String get darkTheme => 'Dark theme';
|
|
|
|
@override
|
|
String get profileLanguageTile => 'Language';
|
|
|
|
@override
|
|
String get langEnglish => 'English';
|
|
|
|
@override
|
|
String get langRussian => 'Russian';
|
|
|
|
@override
|
|
String get profileHint =>
|
|
'User profile, currency, locale and other settings will appear here.';
|
|
|
|
@override
|
|
String get onboardingTitle => 'Welcome';
|
|
|
|
@override
|
|
String get onboardingSubtitle => 'Tell us your name to get started.';
|
|
|
|
@override
|
|
String get onboardingNameLabel => 'Your name';
|
|
|
|
@override
|
|
String get onboardingNameHint => 'How should we address you?';
|
|
|
|
@override
|
|
String get onboardingContinue => 'Continue';
|
|
|
|
@override
|
|
String get onboardingAccountTitle => 'Your first account';
|
|
|
|
@override
|
|
String get onboardingAccountSubtitle =>
|
|
'Add an account to track your money. You can add more later.';
|
|
|
|
@override
|
|
String get txNewTitle => 'New transaction';
|
|
|
|
@override
|
|
String get txEditTitle => 'Edit transaction';
|
|
|
|
@override
|
|
String get txTypeExpense => 'Expense';
|
|
|
|
@override
|
|
String get txTypeIncome => 'Income';
|
|
|
|
@override
|
|
String get txTypeTransfer => 'Transfer';
|
|
|
|
@override
|
|
String get txAmountHint => '0';
|
|
|
|
@override
|
|
String get txCategoryLabel => 'Category';
|
|
|
|
@override
|
|
String get txAccountLabel => 'Account';
|
|
|
|
@override
|
|
String get txAccountFromLabel => 'From';
|
|
|
|
@override
|
|
String get txAccountToLabel => 'To';
|
|
|
|
@override
|
|
String get txDateTimeLabel => 'Date & time';
|
|
|
|
@override
|
|
String get txBalanceAfter => 'Balance after';
|
|
|
|
@override
|
|
String get txTransferAfter => 'After transfer';
|
|
|
|
@override
|
|
String get txNoteLabel => 'Merchant';
|
|
|
|
@override
|
|
String get txNoteHint => 'e.g. Amazon…';
|
|
|
|
@override
|
|
String get txExtraInfoLabel => 'Additional info';
|
|
|
|
@override
|
|
String get txExtraInfoHint => 'e.g. Groceries for the week…';
|
|
|
|
@override
|
|
String get txSaveButton => 'Add transaction';
|
|
|
|
@override
|
|
String get txSaveEditButton => 'Save changes';
|
|
|
|
@override
|
|
String txTransferButton(String amount) {
|
|
return 'Transfer $amount';
|
|
}
|
|
|
|
@override
|
|
String get txDeleteButton => 'Delete';
|
|
|
|
@override
|
|
String get txDeleteConfirmTitle => 'Delete transaction?';
|
|
|
|
@override
|
|
String get txDeleteConfirmMessage => 'This action cannot be undone.';
|
|
|
|
@override
|
|
String get txDeleteConfirmYes => 'Delete';
|
|
|
|
@override
|
|
String get txDeleteConfirmNo => 'Cancel';
|
|
|
|
@override
|
|
String get txPickCategory => 'Pick a category';
|
|
|
|
@override
|
|
String get txPickAccount => 'Pick an account';
|
|
|
|
@override
|
|
String get pickerAccountTitle => 'Account';
|
|
|
|
@override
|
|
String pickerAccountSubtitle(int count) {
|
|
String _temp0 = intl.Intl.pluralLogic(
|
|
count,
|
|
locale: localeName,
|
|
other: '$count accounts',
|
|
one: '$count account',
|
|
);
|
|
return '$_temp0';
|
|
}
|
|
|
|
@override
|
|
String get pickerCategoryTitle => 'Category';
|
|
|
|
@override
|
|
String pickerCategorySubtitle(int count) {
|
|
String _temp0 = intl.Intl.pluralLogic(
|
|
count,
|
|
locale: localeName,
|
|
other: '$count categories',
|
|
one: '$count category',
|
|
);
|
|
return '$_temp0';
|
|
}
|
|
|
|
@override
|
|
String get pickerAddAccount => 'Add account';
|
|
|
|
@override
|
|
String get pickerCreateCategory => 'Create category';
|
|
|
|
@override
|
|
String get comingSoonShort => 'Coming soon';
|
|
|
|
@override
|
|
String get txValidationAmountRequired => 'Enter an amount';
|
|
|
|
@override
|
|
String get txValidationAccountRequired => 'Pick an account';
|
|
|
|
@override
|
|
String get txValidationCategoryRequired => 'Pick a category';
|
|
|
|
@override
|
|
String get txValidationTransferSameAccount =>
|
|
'Source and destination must differ';
|
|
|
|
@override
|
|
String get txValidationTransferDestRequired => 'Pick a destination account';
|
|
|
|
@override
|
|
String get categoriesScreenTitle => 'Categories';
|
|
|
|
@override
|
|
String get categoriesEmpty =>
|
|
'No categories yet. Tap + to create your first one.';
|
|
|
|
@override
|
|
String get categoryNewTitle => 'New category';
|
|
|
|
@override
|
|
String get categoryEditTitle => 'Edit category';
|
|
|
|
@override
|
|
String get categoryNameLabel => 'Name';
|
|
|
|
@override
|
|
String get categoryNameHint => 'e.g. Groceries';
|
|
|
|
@override
|
|
String get categoryIconLabel => 'Icon';
|
|
|
|
@override
|
|
String get categoryColorLabel => 'Color';
|
|
|
|
@override
|
|
String get categorySaveButton => 'Create category';
|
|
|
|
@override
|
|
String get categoryArchiveButton => 'Archive';
|
|
|
|
@override
|
|
String get categoryArchiveConfirmTitle => 'Archive category?';
|
|
|
|
@override
|
|
String get categoryArchiveConfirmMessage =>
|
|
'Archived categories disappear from pickers and lists. Existing transactions keep their reference.';
|
|
|
|
@override
|
|
String get categoryValidationNameRequired => 'Enter a name';
|
|
|
|
@override
|
|
String get categoryValidationNameTooLong => 'Name is too long (max 50 chars)';
|
|
|
|
@override
|
|
String get iconPickerTitle => 'Pick an icon';
|
|
|
|
@override
|
|
String get colorPickerTitle => 'Pick a color';
|
|
|
|
@override
|
|
String get currencyPickerTitle => 'Pick a currency';
|
|
|
|
@override
|
|
String get currencyPickerSearchHint => 'Search…';
|
|
|
|
@override
|
|
String get colorPickerAllUsed =>
|
|
'All palette colors are already in use by other categories.';
|
|
|
|
@override
|
|
String get iconGroupFood => 'Food';
|
|
|
|
@override
|
|
String get iconGroupTransport => 'Transport';
|
|
|
|
@override
|
|
String get iconGroupShopping => 'Shopping';
|
|
|
|
@override
|
|
String get iconGroupHome => 'Home';
|
|
|
|
@override
|
|
String get iconGroupHealth => 'Health';
|
|
|
|
@override
|
|
String get iconGroupEntertainment => 'Leisure';
|
|
|
|
@override
|
|
String get iconGroupWork => 'Work';
|
|
|
|
@override
|
|
String get iconGroupTravel => 'Travel';
|
|
|
|
@override
|
|
String get iconGroupFinance => 'Finance';
|
|
|
|
@override
|
|
String get iconGroupOther => 'Other';
|
|
|
|
@override
|
|
String get profileCategoriesTile => 'Categories';
|
|
|
|
@override
|
|
String get profileAccountsTile => 'Accounts';
|
|
|
|
@override
|
|
String get accountsEmpty => 'No accounts yet. Tap + to add one.';
|
|
|
|
@override
|
|
String get accountNewTitle => 'New account';
|
|
|
|
@override
|
|
String get accountEditTitle => 'Edit account';
|
|
|
|
@override
|
|
String get accountNameLabel => 'Name';
|
|
|
|
@override
|
|
String get accountNameHint => 'e.g. Cash wallet';
|
|
|
|
@override
|
|
String get accountTypeLabel => 'Type';
|
|
|
|
@override
|
|
String get accountTypeCash => 'Cash';
|
|
|
|
@override
|
|
String get accountTypeCard => 'Card';
|
|
|
|
@override
|
|
String get accountTypeBank => 'Bank';
|
|
|
|
@override
|
|
String get accountTypeSavings => 'Savings';
|
|
|
|
@override
|
|
String get accountCurrencyLabel => 'Currency';
|
|
|
|
@override
|
|
String get accountInitialBalanceLabel => 'Initial balance';
|
|
|
|
@override
|
|
String get accountIconLabel => 'Icon';
|
|
|
|
@override
|
|
String get accountColorLabel => 'Color';
|
|
|
|
@override
|
|
String get accountIsDefaultLabel => 'Default account';
|
|
|
|
@override
|
|
String get accountIsDefaultHint => 'Used when creating new transactions';
|
|
|
|
@override
|
|
String get accountSaveButton => 'Create account';
|
|
|
|
@override
|
|
String get accountSaveEditButton => 'Save changes';
|
|
|
|
@override
|
|
String get accountArchiveButton => 'Archive';
|
|
|
|
@override
|
|
String get accountArchiveConfirmTitle => 'Archive account?';
|
|
|
|
@override
|
|
String get accountArchiveConfirmMessage =>
|
|
'Archived accounts disappear from pickers and lists. Existing transactions keep their reference.';
|
|
|
|
@override
|
|
String get accountValidationNameRequired => 'Enter a name';
|
|
|
|
@override
|
|
String get accountValidationNameTooLong => 'Name is too long (max 50 chars)';
|
|
|
|
@override
|
|
String get accountSaveError =>
|
|
'Failed to save the account. Please try again.';
|
|
|
|
@override
|
|
String get accountArchiveError =>
|
|
'Failed to archive the account. Please try again.';
|
|
|
|
@override
|
|
String get accountSetDefaultError =>
|
|
'Account saved, but couldn\'t mark it as default.';
|
|
|
|
@override
|
|
String get profileParsingTile => 'Notification parsing';
|
|
|
|
@override
|
|
String get parsingSettingsTitle => 'Notification parsing';
|
|
|
|
@override
|
|
String get parsingSettingsSubtitle => 'Settings';
|
|
|
|
@override
|
|
String get parsingEnableLabel => 'Recognize notifications';
|
|
|
|
@override
|
|
String get parsingAutoApplyLabel => 'Auto-add transactions';
|
|
|
|
@override
|
|
String get parsingAutoApplyHint =>
|
|
'Add without confirmation when a rule exists, the amount is found in the message text and the account is trusted.';
|
|
|
|
@override
|
|
String get parsingTransferPairingLabel => 'Merge transfers between accounts';
|
|
|
|
@override
|
|
String get parsingTransferPairingHint =>
|
|
'Two notifications about one transfer (debit + credit) are merged into a single transfer transaction pending confirmation.';
|
|
|
|
@override
|
|
String get parsingDiagnosticModeLabel => 'Diagnostic mode';
|
|
|
|
@override
|
|
String get parsingDiagnosticModeHint =>
|
|
'Capture every notification from monitored apps (incl. empty/duplicate) with a full dump of its fields. Temporary — for debugging, adds noise to the parsing log.';
|
|
|
|
@override
|
|
String inboxWhyNotAuto(String reasons) {
|
|
return 'Why not automatic: $reasons';
|
|
}
|
|
|
|
@override
|
|
String get gateCheckRuleMatched => 'no rule for this merchant';
|
|
|
|
@override
|
|
String get gateCheckAmountVerifiedInBody =>
|
|
'amount not found in the message text';
|
|
|
|
@override
|
|
String get gateCheckCurrencyKnown => 'currency not recognized';
|
|
|
|
@override
|
|
String get gateCheckTypeMatchesRule =>
|
|
'transaction type differs from the rule';
|
|
|
|
@override
|
|
String get gateCheckAccountResolved => 'account not resolved';
|
|
|
|
@override
|
|
String get gateCheckAccountTrusted => 'account not confirmed for this app';
|
|
|
|
@override
|
|
String get gateCheckAmountUnderCap => 'amount is too large';
|
|
|
|
@override
|
|
String get parsingRulesTile => 'Parsing rules';
|
|
|
|
@override
|
|
String parsingRulesCreatedCount(int count) {
|
|
return 'Rules created: $count';
|
|
}
|
|
|
|
@override
|
|
String get parsingAiSectionTitle => 'AI (DeepSeek)';
|
|
|
|
@override
|
|
String get parsingAiComingSoon =>
|
|
'AI recognition is coming in a future version.';
|
|
|
|
@override
|
|
String get parsingNotifAccessTitle => 'Notification access';
|
|
|
|
@override
|
|
String get parsingNotifAccessGranted =>
|
|
'Granted — notifications are being read';
|
|
|
|
@override
|
|
String get parsingNotifAccessDenied => 'Not granted — tap to open settings';
|
|
|
|
@override
|
|
String get parsingNotifAccessOpenSettings => 'Open settings';
|
|
|
|
@override
|
|
String get parsingDebugSectionTitle => 'Debug';
|
|
|
|
@override
|
|
String get parsingDebugInjectTile => 'Inject a test notification';
|
|
|
|
@override
|
|
String get parsingLogTile => 'Parsing log';
|
|
|
|
@override
|
|
String get parsingLogTitle => 'Parsing log';
|
|
|
|
@override
|
|
String get parsingLogEmpty =>
|
|
'No messages yet. Incoming notifications will appear here.';
|
|
|
|
@override
|
|
String get parsingLogError => 'Failed to load the log.';
|
|
|
|
@override
|
|
String get parsingLogFilterAll => 'All';
|
|
|
|
@override
|
|
String get parsingLogFilterInbox => 'Inbox';
|
|
|
|
@override
|
|
String get parsingLogFilterApplied => 'Applied';
|
|
|
|
@override
|
|
String get parsingLogFilterIgnored => 'Ignored';
|
|
|
|
@override
|
|
String get parsingLogFilterFailed => 'Failed';
|
|
|
|
@override
|
|
String get parsingStatusPending => 'Pending';
|
|
|
|
@override
|
|
String get parsingStatusInbox => 'Inbox';
|
|
|
|
@override
|
|
String get parsingStatusApplied => 'Applied';
|
|
|
|
@override
|
|
String get parsingStatusIgnored => 'Ignored';
|
|
|
|
@override
|
|
String get parsingStatusFailed => 'Failed';
|
|
|
|
@override
|
|
String get parsingStatusPendingAi => 'Waiting for AI';
|
|
|
|
@override
|
|
String get parsingStatusParsedPartial => 'Partial';
|
|
|
|
@override
|
|
String get parsingStatusWaitingPair => 'Waiting for pair';
|
|
|
|
@override
|
|
String get parsingStatusPaired => 'Merged into transfer';
|
|
|
|
@override
|
|
String get parsingUnmergeTransfer => 'Split transfer';
|
|
|
|
@override
|
|
String get parsingLogOnline => 'Online';
|
|
|
|
@override
|
|
String get parsingLogOffline => 'Offline';
|
|
|
|
@override
|
|
String get parsingLogFilterWaiting => 'Waiting';
|
|
|
|
@override
|
|
String get parsingDetailConfidence => 'Confidence';
|
|
|
|
@override
|
|
String get parsingDetailPipeline => 'Pipeline';
|
|
|
|
@override
|
|
String get parsingDetailMessage => 'Message';
|
|
|
|
@override
|
|
String get parsingDetailDraft => 'Draft';
|
|
|
|
@override
|
|
String get parsingDetailRule => 'Rule suggestion';
|
|
|
|
@override
|
|
String get parsingDetailMeta => 'Meta';
|
|
|
|
@override
|
|
String get parsingDetailDiagnostics => 'Diagnostics';
|
|
|
|
@override
|
|
String parsingDetailAttempt(int count, int max) {
|
|
return 'Attempt $count/$max';
|
|
}
|
|
|
|
@override
|
|
String get parsingDetailSource => 'Source';
|
|
|
|
@override
|
|
String get parsingDetailFailedChecks => 'Why not automatic';
|
|
|
|
@override
|
|
String get parsingDetailAmountScore => 'Amount';
|
|
|
|
@override
|
|
String get parsingDetailAccountScore => 'Account';
|
|
|
|
@override
|
|
String get parsingDetailTypeScore => 'Type';
|
|
|
|
@override
|
|
String get parsingDetailMerchantScore => 'Merchant';
|
|
|
|
@override
|
|
String get parsingDetailCategoryScore => 'Category';
|
|
|
|
@override
|
|
String get parsingDetailTitle => 'Title';
|
|
|
|
@override
|
|
String get parsingDetailBody => 'Body';
|
|
|
|
@override
|
|
String get parsingDetailCard => 'Card';
|
|
|
|
@override
|
|
String get parsingDetailCurrency => 'Currency';
|
|
|
|
@override
|
|
String get parsingDetailKind => 'Kind';
|
|
|
|
@override
|
|
String get parsingDetailDate => 'Date';
|
|
|
|
@override
|
|
String get parsingDetailMerchantRaw => 'Merchant (raw)';
|
|
|
|
@override
|
|
String get parsingDetailMerchantCanonical => 'Merchant (canonical)';
|
|
|
|
@override
|
|
String get parsingDetailCounterparty => 'Counterparty';
|
|
|
|
@override
|
|
String get parsingDetailCategorySuggestion => 'Category hint';
|
|
|
|
@override
|
|
String get parsingDetailAccountId => 'Account ID';
|
|
|
|
@override
|
|
String get parsingDetailCategoryId => 'Category ID';
|
|
|
|
@override
|
|
String get parsingDetailTransferTo => 'Transfer to';
|
|
|
|
@override
|
|
String get parsingDetailRuleCategory => 'Category';
|
|
|
|
@override
|
|
String get parsingDetailTransactionId => 'Transaction ID';
|
|
|
|
@override
|
|
String get parsingDetailDedupHash => 'Dedup hash';
|
|
|
|
@override
|
|
String get parsingDetailReceivedAt => 'Received at';
|
|
|
|
@override
|
|
String get parsingDetailCreatedAt => 'Created at';
|
|
|
|
@override
|
|
String get inboxTitle => 'From notifications';
|
|
|
|
@override
|
|
String get inboxSubtitle =>
|
|
'A rule is learned on the first tap: similar messages will be confirmed automatically.';
|
|
|
|
@override
|
|
String get inboxEmpty =>
|
|
'Inbox is empty. New notifications will appear here.';
|
|
|
|
@override
|
|
String inboxCreateRule(String merchant, String category) {
|
|
return 'Create rule “$merchant → $category”';
|
|
}
|
|
|
|
@override
|
|
String inboxCreateRuleNoCategory(String merchant) {
|
|
return 'Create rule for “$merchant”';
|
|
}
|
|
|
|
@override
|
|
String get inboxConfirm => 'Confirm';
|
|
|
|
@override
|
|
String get inboxCategoryRequiredHint => 'Pick a category to confirm';
|
|
|
|
@override
|
|
String get inboxIgnore => 'Ignore';
|
|
|
|
@override
|
|
String get inboxApplyAll => 'Apply all';
|
|
|
|
@override
|
|
String get inboxTransferPairTitle => 'Transfer between accounts';
|
|
|
|
@override
|
|
String get inboxTransferFrom => 'From account';
|
|
|
|
@override
|
|
String get inboxTransferTo => 'To account';
|
|
|
|
@override
|
|
String get inboxTransferPickAccount => 'Choose…';
|
|
|
|
@override
|
|
String get inboxUnpair => 'Split';
|
|
|
|
@override
|
|
String get inboxUnrecognized => 'Not recognized';
|
|
|
|
@override
|
|
String get inboxParseErrorTitle => 'Recognition error';
|
|
|
|
@override
|
|
String get inboxRetry => 'Try again';
|
|
|
|
@override
|
|
String get inboxAddManually => 'Add manually';
|
|
|
|
@override
|
|
String get inboxNoCategory => 'No category';
|
|
|
|
@override
|
|
String get inboxAccountUnknown => 'Account unknown';
|
|
|
|
@override
|
|
String get inboxEditRuleTooltip => 'Edit before saving';
|
|
|
|
@override
|
|
String get inboxWaitingNetworkTitle => 'Waiting for network';
|
|
|
|
@override
|
|
String get inboxStuckOffline =>
|
|
'No internet connection. Parsing will resume once you\'re back online.';
|
|
|
|
@override
|
|
String get inboxStuckNetwork =>
|
|
'Network is up, but the AI request failed. Will retry automatically.';
|
|
|
|
@override
|
|
String get parseErrorOffline => 'No internet connection';
|
|
|
|
@override
|
|
String get parseErrorNetwork => 'AI request failed (network error)';
|
|
|
|
@override
|
|
String get parseErrorRetryLimit => 'AI retry limit reached';
|
|
|
|
@override
|
|
String get rulesTitle => 'Parsing rules';
|
|
|
|
@override
|
|
String get rulesSubtitle => 'Settings';
|
|
|
|
@override
|
|
String get rulesFilterAll => 'All';
|
|
|
|
@override
|
|
String get rulesFilterMerchants => 'Merchants';
|
|
|
|
@override
|
|
String get rulesFilterAccounts => 'Accounts';
|
|
|
|
@override
|
|
String get rulesFilterIgnore => 'Ignore';
|
|
|
|
@override
|
|
String get rulesEmpty =>
|
|
'No rules yet. Create them from the Inbox in one tap.';
|
|
|
|
@override
|
|
String ruleMatchesCount(int count) {
|
|
String _temp0 = intl.Intl.pluralLogic(
|
|
count,
|
|
locale: localeName,
|
|
other: '$count matches',
|
|
one: '$count match',
|
|
);
|
|
return '$_temp0';
|
|
}
|
|
|
|
@override
|
|
String get ruleDisabled => 'Disabled';
|
|
|
|
@override
|
|
String get ruleEditorNewTitle => 'New rule';
|
|
|
|
@override
|
|
String get ruleEditorEditTitle => 'Rule';
|
|
|
|
@override
|
|
String get ruleEditorIfContains => 'If the notification contains';
|
|
|
|
@override
|
|
String get ruleEditorPatternHint => 'e.g. WBSPB';
|
|
|
|
@override
|
|
String get ruleEditorModeContains => 'Contains';
|
|
|
|
@override
|
|
String get ruleEditorModeExact => 'Exact';
|
|
|
|
@override
|
|
String get ruleEditorModeRegex => 'Regex';
|
|
|
|
@override
|
|
String get ruleEditorThen => 'Then it is:';
|
|
|
|
@override
|
|
String get ruleEditorMerchant => 'Merchant';
|
|
|
|
@override
|
|
String get ruleEditorMerchantHint => 'e.g. Wildberries';
|
|
|
|
@override
|
|
String get ruleEditorCategory => 'Category';
|
|
|
|
@override
|
|
String get ruleEditorAccount => 'Account';
|
|
|
|
@override
|
|
String get ruleEditorAccountUnchanged => '— keep unchanged —';
|
|
|
|
@override
|
|
String get ruleEditorApp => 'App';
|
|
|
|
@override
|
|
String get ruleEditorAppPick => 'Select app';
|
|
|
|
@override
|
|
String get ruleEditorNoApps => 'Add a source app first';
|
|
|
|
@override
|
|
String get rulesUnknownApp => 'Unknown app';
|
|
|
|
@override
|
|
String get ruleEditorAdvanced => 'Advanced';
|
|
|
|
@override
|
|
String get ruleEditorPriority => 'Priority';
|
|
|
|
@override
|
|
String get ruleEditorMatchesTitle => 'Matches (last 30 days)';
|
|
|
|
@override
|
|
String get ruleEditorNoMatches => 'No matches in the last 30 days';
|
|
|
|
@override
|
|
String get ruleEditorSave => 'Save';
|
|
|
|
@override
|
|
String get ruleEditorDelete => 'Delete';
|
|
|
|
@override
|
|
String get ruleEditorEnabledLabel => 'Enabled';
|
|
|
|
@override
|
|
String get debugInjectTitle => 'Test notification';
|
|
|
|
@override
|
|
String get debugInjectSubtitle => 'Debug';
|
|
|
|
@override
|
|
String get debugInjectPackageLabel => 'App package';
|
|
|
|
@override
|
|
String get debugInjectTitleLabel => 'Title (optional)';
|
|
|
|
@override
|
|
String get debugInjectBodyLabel => 'Notification text';
|
|
|
|
@override
|
|
String get debugInjectSend => 'Send to pipeline';
|
|
|
|
@override
|
|
String get debugInjectSent => 'Sent';
|
|
|
|
@override
|
|
String get debugInjectFillSample => 'Sample: purchase';
|
|
|
|
@override
|
|
String get aiConsentKeyMissing => 'API Key is missing';
|
|
|
|
@override
|
|
String get aiConsentSaved => 'Settings saved';
|
|
|
|
@override
|
|
String get aiConsentTitle => 'AI Parsing';
|
|
|
|
@override
|
|
String get aiConsentBody =>
|
|
'We use the DeepSeek API to parse notifications with AI. Your data is sent to the selected model. You need your own API key. Tokens are used.';
|
|
|
|
@override
|
|
String get aiConsentKeyLabel => 'DeepSeek API Key';
|
|
|
|
@override
|
|
String get aiConsentKeyHint => 'sk-...';
|
|
|
|
@override
|
|
String get aiConsentModelLabel => 'AI Model';
|
|
|
|
@override
|
|
String get aiConsentAllow => 'Allow AI Parsing';
|
|
|
|
@override
|
|
String get aiConsentRegexOnly => 'Use Regex Only (Local)';
|
|
|
|
@override
|
|
String get parsingAiConfigure => 'Configure AI';
|
|
|
|
@override
|
|
String parsingAiTokensToday(int tokens) {
|
|
return 'Tokens used today: $tokens';
|
|
}
|
|
|
|
@override
|
|
String parsingAiTokensTodayLimited(int tokens, int limit) {
|
|
return 'Tokens today: $tokens / $limit';
|
|
}
|
|
|
|
@override
|
|
String get habitTrackingTile => 'Spending habit analysis';
|
|
|
|
@override
|
|
String get habitObligationRequired => 'Required';
|
|
|
|
@override
|
|
String get habitObligationOptional => 'Optional';
|
|
|
|
@override
|
|
String get habitObligationUnnecessary => 'Unnecessary';
|
|
|
|
@override
|
|
String get habitObligationOptionalShort => 'Optional';
|
|
|
|
@override
|
|
String get habitImpulseImpulsive => 'Impulse';
|
|
|
|
@override
|
|
String get habitImpulseConsidered => 'Thoughtful';
|
|
|
|
@override
|
|
String get habitNotMarked => 'not marked';
|
|
|
|
@override
|
|
String get habitFilterAll => 'All';
|
|
|
|
@override
|
|
String get habitScaleImpulseCaps => 'IMPULSIVENESS';
|
|
|
|
@override
|
|
String get habitScaleObligationCaps => 'NECESSITY';
|
|
|
|
@override
|
|
String get habitAnalysisTitle => 'Transactions';
|
|
|
|
@override
|
|
String get habitAnalysisTile => 'Habit analysis';
|
|
|
|
@override
|
|
String get profileSeedDemoTile => 'Fill with demo transactions';
|
|
|
|
@override
|
|
String get profileSeedDemoSuccess => 'Demo transactions added';
|
|
|
|
@override
|
|
String get commonAdd => 'Add';
|
|
|
|
@override
|
|
String get commonCancel => 'Cancel';
|
|
|
|
@override
|
|
String get commonDelete => 'Delete';
|
|
|
|
@override
|
|
String get parsingAppsTile => 'Source apps';
|
|
|
|
@override
|
|
String get sourceAppsTitle => 'Source apps';
|
|
|
|
@override
|
|
String get sourceAppsAddedSection => 'Monitored';
|
|
|
|
@override
|
|
String get sourceAppsAvailableSection => 'Available';
|
|
|
|
@override
|
|
String get sourceAppsEmpty =>
|
|
'No apps added yet. Pick a bank below or add one manually.';
|
|
|
|
@override
|
|
String get sourceAppsAddManual => 'Add manually';
|
|
|
|
@override
|
|
String get sourceAppsPackageLabel => 'Package name';
|
|
|
|
@override
|
|
String get sourceAppsNameLabel => 'Display name (optional)';
|
|
|
|
@override
|
|
String get sourceAppsPickFromInstalled => 'Choose from installed apps';
|
|
|
|
@override
|
|
String get sourceAppsPickerTitle => 'Installed apps';
|
|
|
|
@override
|
|
String get sourceAppsSearchHint => 'Search';
|
|
|
|
@override
|
|
String get sourceAppsPickerEmpty => 'No apps found';
|
|
|
|
@override
|
|
String get sourceAppsAlreadyAdded => 'Already added';
|
|
|
|
@override
|
|
String get sourceAppsSelfMerchantLabel => 'Merchant is the app itself';
|
|
|
|
@override
|
|
String get sourceAppsSelfMerchantHint =>
|
|
'Notifications never name the seller: pick the category manually, no rules are suggested';
|
|
|
|
@override
|
|
String get appDetailEnabled => 'Monitor notifications';
|
|
|
|
@override
|
|
String get appDetailDefaultAccount => 'Default account';
|
|
|
|
@override
|
|
String get appDetailDefaultAccountNone => 'Not set';
|
|
|
|
@override
|
|
String get appDetailDefaultAccountHint =>
|
|
'New transactions from this app go to this account. It is remembered automatically the first time you confirm a message in the Inbox.';
|
|
|
|
@override
|
|
String get appDetailRoutingRules => 'Account routing rules';
|
|
|
|
@override
|
|
String get appDetailRoutingRulesEmpty =>
|
|
'If the app reports several accounts (card, deposit), add a rule: text pattern → account. Rules override the default account.';
|
|
|
|
@override
|
|
String get appDetailAddRule => 'Add';
|
|
|
|
@override
|
|
String get inboxAppDefaultSet => 'Account saved as the app\'s default';
|
|
|
|
@override
|
|
String get ruleKindMerchant => 'Merchant → category';
|
|
|
|
@override
|
|
String get ruleKindAccount => 'Sender → account';
|
|
|
|
@override
|
|
String get ruleEditorAccountPick => 'Select account';
|
|
}
|