Files
OnBudget/lib/l10n/app_en.arb
T
SandersandClaude Opus 4.8 ab66aebc5e Switch AI notification parsing from OpenRouter to DeepSeek API
Replace the OpenRouter HTTP client with a DeepSeek client:
- data/openrouter/ -> data/deepseek/; OpenRouterClient -> DeepSeekClient
  (+ DeepSeekCompletion / DeepSeek*Exception)
- base URL api.deepseek.com, drop OpenRouter-only headers
- DeepSeek has no strict json_schema: use response_format json_object
  and rely on the prompt for shape (ai_schema.dart removed)
- secure-storage key openrouter_api_key -> deepseek_api_key
- default model deepseek/deepseek-v4-flash -> deepseek-chat
- l10n strings, test dart-defines (DEEPSEEK_API_KEY/_TEST_MODEL), docs

Also bundles in-progress findBodyIgnoreRule (body-level ignore rules
applied before the AI call) already present in the working tree.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 00:23:38 +03:00

427 lines
15 KiB
Plaintext

{
"@@locale": "en",
"appTitle": "NewBudget",
"navHome": "Home",
"navAnalytics": "Analytics",
"navAccounts": "Accounts",
"navProfile": "Profile",
"allAccounts": "All",
"comingSoon": "Coming soon",
"budget": "BUDGET",
"balance": "BALANCE",
"income": "INCOME",
"expenses": "EXPENSES",
"transactions": "Transactions",
"transactionCount": "{count, plural, one{{count} transaction} other{{count} transactions}}",
"@transactionCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"allCategoriesFilter": "All categories · all types",
"filterByCategories": "Filter by category",
"clearFilter": "Clear",
"selectAll": "Select all",
"categoriesSelectedCount": "{count, plural, one{{count} category} other{{count} categories}}",
"@categoriesSelectedCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"moreCategories": "{count, plural, one{+ {count} more →} other{+ {count} more →}}",
"@moreCategories": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"todayWithDate": "Today · {date}",
"@todayWithDate": {
"placeholders": {
"date": {
"type": "String"
}
}
},
"yesterdayWithDate": "Yesterday · {date}",
"@yesterdayWithDate": {
"placeholders": {
"date": {
"type": "String"
}
}
},
"analyticsTitle": "Reports",
"analyticsSubtitle": "Analytics",
"accountsSubtitle": "Management",
"profileSubtitle": "Settings",
"darkTheme": "Dark theme",
"profileLanguageTile": "Language",
"langEnglish": "English",
"langRussian": "Russian",
"profileHint": "User profile, currency, locale and other settings will appear here.",
"onboardingTitle": "Welcome",
"onboardingSubtitle": "Tell us your name to get started.",
"onboardingNameLabel": "Your name",
"onboardingNameHint": "How should we address you?",
"onboardingContinue": "Continue",
"txNewTitle": "New transaction",
"txEditTitle": "Edit transaction",
"txTypeExpense": "Expense",
"txTypeIncome": "Income",
"txTypeTransfer": "Transfer",
"txAmountHint": "0",
"txCategoryLabel": "Category",
"txAccountLabel": "Account",
"txAccountFromLabel": "From",
"txAccountToLabel": "To",
"txDateTimeLabel": "Date & time",
"txBalanceAfter": "Balance after",
"txTransferAfter": "After transfer",
"txNoteLabel": "Merchant",
"txNoteHint": "e.g. Amazon…",
"txExtraInfoLabel": "Additional info",
"txExtraInfoHint": "e.g. Groceries for the week…",
"txSaveButton": "Add transaction",
"txSaveEditButton": "Save changes",
"txTransferButton": "Transfer {amount}",
"@txTransferButton": {
"placeholders": {
"amount": { "type": "String" }
}
},
"txDeleteButton": "Delete",
"txDeleteConfirmTitle": "Delete transaction?",
"txDeleteConfirmMessage": "This action cannot be undone.",
"txDeleteConfirmYes": "Delete",
"txDeleteConfirmNo": "Cancel",
"txPickCategory": "Pick a category",
"txPickAccount": "Pick an account",
"pickerAccountTitle": "Account",
"pickerAccountSubtitle": "{count, plural, one{{count} account} other{{count} accounts}}",
"@pickerAccountSubtitle": {
"placeholders": {
"count": { "type": "int" }
}
},
"pickerCategoryTitle": "Category",
"pickerCategorySubtitle": "{count, plural, one{{count} category} other{{count} categories}}",
"@pickerCategorySubtitle": {
"placeholders": {
"count": { "type": "int" }
}
},
"pickerAddAccount": "Add account",
"pickerCreateCategory": "Create category",
"comingSoonShort": "Coming soon",
"txValidationAmountRequired": "Enter an amount",
"txValidationAccountRequired": "Pick an account",
"txValidationCategoryRequired": "Pick a category",
"txValidationTransferSameAccount": "Source and destination must differ",
"txValidationTransferDestRequired": "Pick a destination account",
"categoriesScreenTitle": "Categories",
"categoriesEmpty": "No categories yet. Tap + to create your first one.",
"categoryNewTitle": "New category",
"categoryEditTitle": "Edit category",
"categoryNameLabel": "Name",
"categoryNameHint": "e.g. Groceries",
"categoryIconLabel": "Icon",
"categoryColorLabel": "Color",
"categorySaveButton": "Create category",
"categoryArchiveButton": "Archive",
"categoryArchiveConfirmTitle": "Archive category?",
"categoryArchiveConfirmMessage": "Archived categories disappear from pickers and lists. Existing transactions keep their reference.",
"categoryValidationNameRequired": "Enter a name",
"categoryValidationNameTooLong": "Name is too long (max 50 chars)",
"iconPickerTitle": "Pick an icon",
"colorPickerTitle": "Pick a color",
"currencyPickerTitle": "Pick a currency",
"currencyPickerSearchHint": "Search…",
"colorPickerAllUsed": "All palette colors are already in use by other categories.",
"iconGroupFood": "Food",
"iconGroupTransport": "Transport",
"iconGroupShopping": "Shopping",
"iconGroupHome": "Home",
"iconGroupHealth": "Health",
"iconGroupEntertainment": "Leisure",
"iconGroupWork": "Work",
"iconGroupTravel": "Travel",
"iconGroupFinance": "Finance",
"iconGroupOther": "Other",
"profileCategoriesTile": "Categories",
"profileAccountsTile": "Accounts",
"accountsEmpty": "No accounts yet. Tap + to add one.",
"accountNewTitle": "New account",
"accountEditTitle": "Edit account",
"accountNameLabel": "Name",
"accountNameHint": "e.g. Cash wallet",
"accountTypeLabel": "Type",
"accountTypeCash": "Cash",
"accountTypeCard": "Card",
"accountTypeBank": "Bank",
"accountTypeSavings": "Savings",
"accountCurrencyLabel": "Currency",
"accountInitialBalanceLabel": "Initial balance",
"accountIconLabel": "Icon",
"accountColorLabel": "Color",
"accountIsDefaultLabel": "Default account",
"accountIsDefaultHint": "Used when creating new transactions",
"accountSaveButton": "Create account",
"accountSaveEditButton": "Save changes",
"accountArchiveButton": "Archive",
"accountArchiveConfirmTitle": "Archive account?",
"accountArchiveConfirmMessage": "Archived accounts disappear from pickers and lists. Existing transactions keep their reference.",
"accountValidationNameRequired": "Enter a name",
"accountValidationNameTooLong": "Name is too long (max 50 chars)",
"accountSaveError": "Failed to save the account. Please try again.",
"accountArchiveError": "Failed to archive the account. Please try again.",
"accountSetDefaultError": "Account saved, but couldn't mark it as default.",
"profileParsingTile": "Notification parsing",
"parsingSettingsTitle": "Notification parsing",
"parsingSettingsSubtitle": "Settings",
"parsingEnableLabel": "Recognize notifications",
"parsingAutoApplyLabel": "Auto-add transactions",
"parsingAutoApplyHint": "Add without confirmation when a rule exists, the amount is found in the message text and the account is trusted.",
"inboxWhyNotAuto": "Why not automatic: {reasons}",
"@inboxWhyNotAuto": { "placeholders": { "reasons": { "type": "String" } } },
"gateCheckRuleMatched": "no rule for this merchant",
"gateCheckAmountVerifiedInBody": "amount not found in the message text",
"gateCheckCurrencyKnown": "currency not recognized",
"gateCheckTypeMatchesRule": "transaction type differs from the rule",
"gateCheckAccountResolved": "account not resolved",
"gateCheckAccountTrusted": "ambiguous account",
"gateCheckAmountUnderCap": "amount is too large",
"parsingRulesTile": "Parsing rules",
"parsingRulesCreatedCount": "Rules created: {count}",
"@parsingRulesCreatedCount": { "placeholders": { "count": { "type": "int" } } },
"parsingAiSectionTitle": "AI (DeepSeek)",
"parsingAiComingSoon": "AI recognition is coming in a future version.",
"parsingNotifAccessTitle": "Notification access",
"parsingNotifAccessGranted": "Granted — notifications are being read",
"parsingNotifAccessDenied": "Not granted — tap to open settings",
"parsingNotifAccessOpenSettings": "Open settings",
"parsingDebugSectionTitle": "Debug",
"parsingDebugInjectTile": "Inject a test notification",
"parsingLogTile": "Parsing log",
"parsingLogTitle": "Parsing log",
"parsingLogEmpty": "No messages yet. Incoming notifications will appear here.",
"parsingLogError": "Failed to load the log.",
"parsingLogFilterAll": "All",
"parsingLogFilterInbox": "Inbox",
"parsingLogFilterApplied": "Applied",
"parsingLogFilterIgnored": "Ignored",
"parsingLogFilterFailed": "Failed",
"parsingStatusPending": "Pending",
"parsingStatusInbox": "Inbox",
"parsingStatusApplied": "Applied",
"parsingStatusIgnored": "Ignored",
"parsingStatusFailed": "Failed",
"parsingStatusPendingAi": "Waiting for AI",
"parsingStatusParsedPartial": "Partial",
"parsingLogOnline": "Online",
"parsingLogOffline": "Offline",
"parsingLogFilterWaiting": "Waiting",
"parsingDetailConfidence": "Confidence",
"parsingDetailPipeline": "Pipeline",
"parsingDetailMessage": "Message",
"parsingDetailDraft": "Draft",
"parsingDetailRule": "Rule suggestion",
"parsingDetailMeta": "Meta",
"parsingDetailAttempt": "Attempt {count}/{max}",
"@parsingDetailAttempt": { "placeholders": { "count": { "type": "int" }, "max": { "type": "int" } } },
"parsingDetailSource": "Source",
"parsingDetailFailedChecks": "Why not automatic",
"parsingDetailAmountScore": "Amount",
"parsingDetailAccountScore": "Account",
"parsingDetailTypeScore": "Type",
"parsingDetailMerchantScore": "Merchant",
"parsingDetailCategoryScore": "Category",
"parsingDetailTitle": "Title",
"parsingDetailBody": "Body",
"parsingDetailCard": "Card",
"parsingDetailCurrency": "Currency",
"parsingDetailKind": "Kind",
"parsingDetailDate": "Date",
"parsingDetailMerchantRaw": "Merchant (raw)",
"parsingDetailMerchantCanonical": "Merchant (canonical)",
"parsingDetailCounterparty": "Counterparty",
"parsingDetailCategorySuggestion": "Category hint",
"parsingDetailAccountId": "Account ID",
"parsingDetailCategoryId": "Category ID",
"parsingDetailTransferTo": "Transfer to",
"parsingDetailRuleCategory": "Category",
"parsingDetailTransactionId": "Transaction ID",
"parsingDetailDedupHash": "Dedup hash",
"parsingDetailReceivedAt": "Received at",
"parsingDetailCreatedAt": "Created at",
"inboxTitle": "From notifications",
"inboxSubtitle": "A rule is learned on the first tap: similar messages will be confirmed automatically.",
"inboxEmpty": "Inbox is empty. New notifications will appear here.",
"inboxCreateRule": "Create rule “{merchant} → {category}”",
"@inboxCreateRule": { "placeholders": { "merchant": { "type": "String" }, "category": { "type": "String" } } },
"inboxCreateRuleNoCategory": "Create rule for “{merchant}”",
"@inboxCreateRuleNoCategory": { "placeholders": { "merchant": { "type": "String" } } },
"inboxConfirmOnce": "Confirm once",
"inboxIgnore": "Ignore",
"inboxApplyAll": "Apply all",
"inboxHideAll": "Hide all",
"inboxUnrecognized": "Not recognized",
"inboxParseErrorTitle": "Recognition error",
"inboxRetry": "Try again",
"inboxAddManually": "Add manually",
"inboxNoCategory": "No category",
"inboxAccountUnknown": "Account unknown",
"inboxEditRuleTooltip": "Edit before saving",
"rulesTitle": "Parsing rules",
"rulesSubtitle": "Settings",
"rulesFilterAll": "All",
"rulesFilterMerchants": "Merchants",
"rulesFilterAccounts": "Accounts",
"rulesFilterIgnore": "Ignore",
"rulesEmpty": "No rules yet. Create them from the Inbox in one tap.",
"ruleMatchesCount": "{count, plural, one{{count} match} other{{count} matches}}",
"@ruleMatchesCount": { "placeholders": { "count": { "type": "int" } } },
"ruleDisabled": "Disabled",
"ruleEditorNewTitle": "New rule",
"ruleEditorEditTitle": "Rule",
"ruleEditorIfContains": "If the notification contains",
"ruleEditorPatternHint": "e.g. WBSPB",
"ruleEditorModeContains": "Contains",
"ruleEditorModeExact": "Exact",
"ruleEditorModeRegex": "Regex",
"ruleEditorThen": "Then it is:",
"ruleEditorMerchant": "Merchant",
"ruleEditorMerchantHint": "e.g. Wildberries",
"ruleEditorCategory": "Category",
"ruleEditorAccount": "Account",
"ruleEditorAccountUnchanged": "— keep unchanged —",
"ruleEditorAdvanced": "Advanced",
"ruleEditorPriority": "Priority",
"ruleEditorMatchesTitle": "Matches (last 30 days)",
"ruleEditorNoMatches": "No matches in the last 30 days",
"ruleEditorSave": "Save",
"ruleEditorDelete": "Delete",
"ruleEditorEnabledLabel": "Enabled",
"debugInjectTitle": "Test notification",
"debugInjectSubtitle": "Debug",
"debugInjectPackageLabel": "App package",
"debugInjectTitleLabel": "Title (optional)",
"debugInjectBodyLabel": "Notification text",
"debugInjectSend": "Send to pipeline",
"debugInjectSent": "Sent",
"debugInjectFillSample": "Sample: purchase",
"aiConsentKeyMissing": "API Key is missing",
"aiConsentSaved": "Settings saved",
"aiConsentTitle": "AI Parsing",
"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.",
"aiConsentKeyLabel": "DeepSeek API Key",
"aiConsentKeyHint": "sk-...",
"aiConsentModelLabel": "AI Model",
"aiConsentAllow": "Allow AI Parsing",
"aiConsentRegexOnly": "Use Regex Only (Local)",
"parsingAiConfigure": "Configure AI",
"parsingAiTokensToday": "Tokens used today: {tokens}",
"@parsingAiTokensToday": {
"placeholders": {
"tokens": {
"type": "int"
}
}
},
"parsingAiTokensTodayLimited": "Tokens today: {tokens} / {limit}",
"@parsingAiTokensTodayLimited": {
"placeholders": {
"tokens": {
"type": "int"
},
"limit": {
"type": "int"
}
}
},
"habitTrackingTile": "Spending habit analysis",
"habitObligationRequired": "Necessary",
"habitObligationOptional": "Optional",
"habitObligationUnnecessary": "Unnecessary",
"habitObligationOptionalShort": "Optional",
"habitImpulseImpulsive": "Impulse",
"habitImpulseConsidered": "Considered",
"habitNotMarked": "not marked",
"habitFilterAll": "All",
"habitScaleImpulseCaps": "IMPULSIVENESS",
"habitScaleObligationCaps": "OBLIGATION",
"habitAnalysisTitle": "Transactions",
"habitAnalysisTile": "Habit analysis",
"profileSeedDemoTile": "Fill with demo transactions",
"profileSeedDemoSuccess": "Demo transactions added",
"commonAdd": "Add",
"commonCancel": "Cancel",
"commonDelete": "Delete",
"parsingAppsTile": "Source apps",
"sourceAppsTitle": "Source apps",
"sourceAppsAddedSection": "Monitored",
"sourceAppsAvailableSection": "Available",
"sourceAppsEmpty": "No apps added yet. Pick a bank below or add one manually.",
"sourceAppsAddManual": "Add manually",
"sourceAppsPackageLabel": "Package name",
"sourceAppsNameLabel": "Display name (optional)",
"sourceAppsPickFromInstalled": "Choose from installed apps",
"sourceAppsPickerTitle": "Installed apps",
"sourceAppsSearchHint": "Search",
"sourceAppsPickerEmpty": "No apps found",
"sourceAppsAlreadyAdded": "Already added",
"appBindingsTitle": "Account bindings",
"appBindingsEmpty": "No bindings yet. Add one to map a card to an account.",
"appBindingsAnyCard": "Any card (default)",
"appBindingsSetDefault": "Set as default for this app",
"appBindingsAddTitle": "New binding",
"appBindingsCardLabel": "Card last 4 digits",
"appBindingsCardHelper": "Leave empty to match any card",
"appBindingsDefaultLabel": "Default for this app",
"ruleKindMerchant": "Merchant → category",
"ruleKindAccount": "Sender → account",
"ruleEditorAccountPick": "Select account"
}