feat: add 4 default income categories, localize category display names

Fresh installs (this app is published on GitHub) only got Salary,
Freelance, Investments, Gifts, Other Income by default — adds Business
Income, Rental Income, Benefits, and Item Sales, rounding out the 8-slot
categorical palette. Only affects new databases (seeding is a one-time
no-op once any category exists).

Also fixes CategoryList.tsx (added last commit) to run category names
through translateCategoryName() like every other category display in the
app, and registers the new defaults' translation keys.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
ZProger
2026-08-24 23:51:33 +03:00
parent 9f5ea00227
commit 2c6fcd628c
6 changed files with 33 additions and 11 deletions

View File

@@ -1,7 +1,7 @@
{
"name": "aurum-frontend",
"private": true,
"version": "0.23.0",
"version": "0.23.1",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,4 +1,5 @@
import { Pencil, Trash2 } from "lucide-react";
import { translateCategoryName } from "@/lib/categoryLabels";
import { getCategoryIcon } from "@/lib/icons";
import { useTranslation } from "@/lib/i18n";
import type { Category } from "@/types";
@@ -30,7 +31,7 @@ export function CategoryList({ items, onEdit, onDelete }: CategoryListProps) {
<Icon size={15} />
</span>
<span className="flex min-w-0 flex-1 items-center gap-1.5 truncate text-sm font-medium text-text-primary">
<span className="truncate">{category.name}</span>
<span className="truncate">{translateCategoryName(category.name)}</span>
{category.is_default && (
<span className="shrink-0 rounded bg-surface-2 px-1 py-0.5 text-[10px] leading-none text-text-muted">
{t("category.defaultBadge")}

View File

@@ -1,10 +1,10 @@
import { t, type TranslationKey } from "@/lib/i18n";
// Maps the exact seeded English category name (backend/app/db/seed.py) to
// its translation key. There's no category-management UI yet, so every
// category currently in the database is one of these — anything that
// doesn't match (a renamed default, or a future custom category) falls
// through unchanged.
// its translation key, so the fixed default set reads in the user's chosen
// language regardless of what the DB literally stores. Categories created
// through the category-management UI (CategoriesPage) aren't in this map —
// their name is whatever the user typed and is shown as-is.
const DEFAULT_CATEGORY_KEYS: Record<string, TranslationKey> = {
"Housing & Utilities": "category.housingUtilities",
Groceries: "category.groceries",
@@ -18,6 +18,10 @@ const DEFAULT_CATEGORY_KEYS: Record<string, TranslationKey> = {
Freelance: "category.freelance",
Investments: "category.investments",
Gifts: "category.gifts",
"Business Income": "category.businessIncome",
"Rental Income": "category.rentalIncome",
Benefits: "category.benefits",
"Item Sales": "category.itemSales",
"Other Income": "category.otherIncome",
};

View File

@@ -324,11 +324,10 @@ const ru = {
"cashFlow.net": "Баланс",
"cashFlow.noData": "Нет данных за выбранный период.",
// Default seeded categories (backend/app/db/seed.py) — there's no
// category-management UI yet, so every category currently in the
// database is one of these; translateCategoryName() matches on the exact
// seeded English name and falls through unchanged for anything else
// (a renamed default, or a future custom category).
// Default seeded categories (backend/app/db/seed.py) — translateCategoryName()
// matches on the exact seeded English name and falls through unchanged
// for anything else (a renamed default, or a custom category added via
// the category-management UI).
"category.housingUtilities": "Жильё и коммуналка",
"category.groceries": "Продукты",
"category.diningOut": "Кафе и рестораны",
@@ -341,6 +340,10 @@ const ru = {
"category.freelance": "Фриланс",
"category.investments": "Инвестиции",
"category.gifts": "Подарки",
"category.businessIncome": "Доход от бизнеса",
"category.rentalIncome": "Сдача недвижимости",
"category.benefits": "Пособия и соцвыплаты",
"category.itemSales": "Продажа личных вещей",
"category.otherIncome": "Прочий доход",
"months.jan": "Янв",
@@ -689,6 +692,10 @@ const en: Record<keyof typeof ru, string> = {
"category.freelance": "Freelance",
"category.investments": "Investments",
"category.gifts": "Gifts",
"category.businessIncome": "Business Income",
"category.rentalIncome": "Rental Income",
"category.benefits": "Benefits",
"category.itemSales": "Item Sales",
"category.otherIncome": "Other Income",
"months.jan": "Jan",

View File

@@ -11,8 +11,10 @@ import {
Gem,
Gift,
GraduationCap,
HandCoins,
HeartPulse,
Home,
Key,
MoreHorizontal,
Package,
Plane,
@@ -26,6 +28,7 @@ import {
Smartphone,
Sofa,
Sparkles,
Tag,
TrendingUp,
Truck,
Utensils,
@@ -71,6 +74,9 @@ const ICON_MAP: Record<string, LucideIcon> = {
smartphone: Smartphone,
sofa: Sofa,
sparkles: Sparkles,
tag: Tag,
"hand-coins": HandCoins,
key: Key,
truck: Truck,
// lucide-react dropped brand/trademarked glyphs (no "Youtube" icon) — a
// generic video-camera icon is the closest available stand-in.