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>
456 lines
17 KiB
Plaintext
456 lines
17 KiB
Plaintext
{
|
|
"@@locale": "en",
|
|
|
|
"appTitle": "Kitty finances",
|
|
|
|
"navHome": "Home",
|
|
"navInbox": "Inbox",
|
|
"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",
|
|
"analyticsNoData": "No data for this month",
|
|
|
|
"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",
|
|
"onboardingAccountTitle": "Your first account",
|
|
"onboardingAccountSubtitle": "Add an account to track your money. You can add more later.",
|
|
|
|
"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.",
|
|
"parsingTransferPairingLabel": "Merge transfers between accounts",
|
|
"parsingTransferPairingHint": "Two notifications about one transfer (debit + credit) are merged into a single transfer transaction pending confirmation.",
|
|
"parsingDiagnosticModeLabel": "Diagnostic mode",
|
|
"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.",
|
|
"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": "account not confirmed for this app",
|
|
"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",
|
|
"parsingStatusWaitingPair": "Waiting for pair",
|
|
"parsingStatusPaired": "Merged into transfer",
|
|
"parsingUnmergeTransfer": "Split transfer",
|
|
|
|
"parsingLogOnline": "Online",
|
|
"parsingLogOffline": "Offline",
|
|
"parsingLogFilterWaiting": "Waiting",
|
|
|
|
"parsingDetailConfidence": "Confidence",
|
|
"parsingDetailPipeline": "Pipeline",
|
|
"parsingDetailMessage": "Message",
|
|
"parsingDetailDraft": "Draft",
|
|
"parsingDetailRule": "Rule suggestion",
|
|
"parsingDetailMeta": "Meta",
|
|
"parsingDetailDiagnostics": "Diagnostics",
|
|
"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" } } },
|
|
"inboxConfirm": "Confirm",
|
|
"inboxCategoryRequiredHint": "Pick a category to confirm",
|
|
"inboxIgnore": "Ignore",
|
|
"inboxApplyAll": "Apply all",
|
|
"inboxTransferPairTitle": "Transfer between accounts",
|
|
"inboxTransferFrom": "From account",
|
|
"inboxTransferTo": "To account",
|
|
"inboxTransferPickAccount": "Choose…",
|
|
"inboxUnpair": "Split",
|
|
"inboxUnrecognized": "Not recognized",
|
|
"inboxParseErrorTitle": "Recognition error",
|
|
"inboxRetry": "Try again",
|
|
"inboxAddManually": "Add manually",
|
|
"inboxNoCategory": "No category",
|
|
"inboxAccountUnknown": "Account unknown",
|
|
"inboxEditRuleTooltip": "Edit before saving",
|
|
"inboxWaitingNetworkTitle": "Waiting for network",
|
|
"inboxStuckOffline": "No internet connection. Parsing will resume once you're back online.",
|
|
"inboxStuckNetwork": "Network is up, but the AI request failed. Will retry automatically.",
|
|
"parseErrorOffline": "No internet connection",
|
|
"parseErrorNetwork": "AI request failed (network error)",
|
|
"parseErrorRetryLimit": "AI retry limit reached",
|
|
|
|
"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 —",
|
|
"ruleEditorApp": "App",
|
|
"ruleEditorAppPick": "Select app",
|
|
"ruleEditorNoApps": "Add a source app first",
|
|
"rulesUnknownApp": "Unknown app",
|
|
"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": "Required",
|
|
"habitObligationOptional": "Optional",
|
|
"habitObligationUnnecessary": "Unnecessary",
|
|
"habitObligationOptionalShort": "Optional",
|
|
"habitImpulseImpulsive": "Impulse",
|
|
"habitImpulseConsidered": "Thoughtful",
|
|
"habitNotMarked": "not marked",
|
|
"habitFilterAll": "All",
|
|
"habitScaleImpulseCaps": "IMPULSIVENESS",
|
|
"habitScaleObligationCaps": "NECESSITY",
|
|
"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",
|
|
"sourceAppsSelfMerchantLabel": "Merchant is the app itself",
|
|
"sourceAppsSelfMerchantHint": "Notifications never name the seller: pick the category manually, no rules are suggested",
|
|
|
|
"appDetailEnabled": "Monitor notifications",
|
|
"appDetailDefaultAccount": "Default account",
|
|
"appDetailDefaultAccountNone": "Not set",
|
|
"appDetailDefaultAccountHint": "New transactions from this app go to this account. It is remembered automatically the first time you confirm a message in the Inbox.",
|
|
"appDetailRoutingRules": "Account routing rules",
|
|
"appDetailRoutingRulesEmpty": "If the app reports several accounts (card, deposit), add a rule: text pattern → account. Rules override the default account.",
|
|
"appDetailAddRule": "Add",
|
|
"inboxAppDefaultSet": "Account saved as the app's default",
|
|
|
|
"ruleKindMerchant": "Merchant → category",
|
|
"ruleKindAccount": "Sender → account",
|
|
"ruleEditorAccountPick": "Select account"
|
|
}
|