Files
OnBudget/lib/l10n/app_localizations_en.dart
T
SandersandClaude Opus 4.8 fdc5c14852 Move Inbox to a dedicated bottom-nav tab gated by parsing toggle
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>
2026-07-19 16:45:21 +03:00

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';
}