Replace the Inbox badge button in MonthHeader with a bottom-nav tab (hidden when notification parsing is disabled). Redirect /inbox → /home when parsing is off, register the Inbox shell branch unconditionally, and add a settings action to the Inbox screen. Move the parsing tile to the top of the profile screen so settings stay reachable when the tab is hidden. Add tests for the nav tab visibility and inbox routing, plus a release-install PowerShell helper that preserves app data. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1133 lines
25 KiB
Dart
1133 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 navInbox => 'Inbox';
|
|
|
|
@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';
|
|
}
|