feat: Translate Wallets page to multi-language

- Add useLanguage hook to Wallets page
- Translate all UI text (buttons, labels, table headers)
- Translate filter options and placeholders
- Translate delete confirmation dialog
- Support both Indonesian and English
This commit is contained in:
dwindown
2025-10-12 08:53:30 +07:00
parent 371b5e0a66
commit bfd009368a

View File

@@ -1,4 +1,5 @@
import { useState, useEffect, useMemo } from "react" import { useState, useEffect, useMemo } from "react"
import { useLanguage } from "@/contexts/LanguageContext"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input" import { Input } from "@/components/ui/input"
@@ -49,6 +50,7 @@ interface Wallet {
const API = "/api" const API = "/api"
export function Wallets() { export function Wallets() {
const { t } = useLanguage()
const [wallets, setWallets] = useState<Wallet[]>([]) const [wallets, setWallets] = useState<Wallet[]>([])
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [searchTerm, setSearchTerm] = useState("") const [searchTerm, setSearchTerm] = useState("")
@@ -165,7 +167,7 @@ export function Wallets() {
</Button> </Button>
<Button onClick={() => setWalletDialogOpen(true)}> <Button onClick={() => setWalletDialogOpen(true)}>
<Plus className="mr-2 h-4 w-4" /> <Plus className="mr-2 h-4 w-4" />
Add Wallet {t.wallets.addWallet}
</Button> </Button>
</div> </div>
</div> </div>
@@ -175,7 +177,7 @@ export function Wallets() {
<div className="grid gap-4 grid-cols-2 lg:grid-cols-4"> <div className="grid gap-4 grid-cols-2 lg:grid-cols-4">
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Wallets</CardTitle> <CardTitle className="text-sm font-medium">{t.wallets.title}</CardTitle>
<Wallet className="h-4 w-4 text-muted-foreground" /> <Wallet className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@@ -185,7 +187,7 @@ export function Wallets() {
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Money Wallets</CardTitle> <CardTitle className="text-sm font-medium">{t.wallets.moneyWallets}</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{stats.moneyWallets}</div> <div className="text-2xl font-bold">{stats.moneyWallets}</div>
@@ -194,7 +196,7 @@ export function Wallets() {
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Asset Wallets</CardTitle> <CardTitle className="text-sm font-medium">{t.wallets.assetWallets}</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{stats.assetWallets}</div> <div className="text-2xl font-bold">{stats.assetWallets}</div>
@@ -203,7 +205,7 @@ export function Wallets() {
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Currencies</CardTitle> <CardTitle className="text-sm font-medium">{t.wallets.currency}</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{stats.currencyCount}</div> <div className="text-2xl font-bold">{stats.currencyCount}</div>
@@ -216,12 +218,12 @@ export function Wallets() {
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<CardTitle className="text-base">Filters</CardTitle> <CardTitle className="text-base">{t.common.filter}</CardTitle>
<Button <Button
variant="ghost" variant="ghost"
size="sm" size="sm"
onClick={clearFilters} onClick={clearFilters}
className="h-8 text-xs" className="h-7 px-2"
> >
<X className="h-3 w-3 mr-1" /> <X className="h-3 w-3 mr-1" />
Clear All Clear All
@@ -233,11 +235,11 @@ export function Wallets() {
<div className="grid gap-3 md:grid-cols-3"> <div className="grid gap-3 md:grid-cols-3">
{/* Search */} {/* Search */}
<div className="space-y-2"> <div className="space-y-2">
<Label className="text-xs font-medium text-muted-foreground">Search Wallet</Label> <Label className="text-xs font-medium text-muted-foreground">{t.common.search}</Label>
<div className="relative"> <div className="relative">
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" /> <Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
<Input <Input
placeholder="Search wallets..." placeholder={t.wallets.searchPlaceholder}
value={searchTerm} value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
className="pl-9 h-9" className="pl-9 h-9"
@@ -247,28 +249,28 @@ export function Wallets() {
{/* Type Filter */} {/* Type Filter */}
<div className="space-y-2"> <div className="space-y-2">
<Label className="text-xs font-medium text-muted-foreground">Type</Label> <Label className="text-xs font-medium text-muted-foreground">{t.wallets.type}</Label>
<Select value={kindFilter} onValueChange={setKindFilter}> <Select value={kindFilter} onValueChange={setKindFilter}>
<SelectTrigger className="h-9"> <SelectTrigger className="h-9">
<SelectValue placeholder="All types" /> <SelectValue placeholder={t.common.all} />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="all">All Types</SelectItem> <SelectItem value="all">{t.common.all}</SelectItem>
<SelectItem value="money">Money</SelectItem> <SelectItem value="money">{t.wallets.money}</SelectItem>
<SelectItem value="asset">Asset</SelectItem> <SelectItem value="asset">{t.wallets.asset}</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
{/* Currency Filter */} {/* Currency Filter */}
<div className="space-y-2"> <div className="space-y-2">
<Label className="text-xs font-medium text-muted-foreground">Currency/Unit</Label> <Label className="text-xs font-medium text-muted-foreground">{t.wallets.currency}/{t.wallets.unit}</Label>
<Select value={currencyFilter} onValueChange={setCurrencyFilter}> <Select value={currencyFilter} onValueChange={setCurrencyFilter}>
<SelectTrigger className="h-9"> <SelectTrigger className="h-9">
<SelectValue placeholder="All currencies" /> <SelectValue placeholder={t.common.all} />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="all">All Currencies/Units</SelectItem> <SelectItem value="all">{t.common.all}</SelectItem>
{availableCurrencies.map(currency => ( {availableCurrencies.map(currency => (
<SelectItem key={currency} value={currency}> <SelectItem key={currency} value={currency}>
{currency} {currency}
@@ -316,7 +318,7 @@ export function Wallets() {
{/* Wallets Table */} {/* Wallets Table */}
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>Wallets ({filteredWallets.length})</CardTitle> <CardTitle>{t.wallets.title} ({filteredWallets.length})</CardTitle>
<CardDescription> <CardDescription>
{filteredWallets.length !== wallets.length {filteredWallets.length !== wallets.length
? `Filtered from ${wallets.length} total wallets` ? `Filtered from ${wallets.length} total wallets`
@@ -328,11 +330,11 @@ export function Wallets() {
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>Name</TableHead> <TableHead>{t.wallets.name}</TableHead>
<TableHead>Currency/Unit</TableHead> <TableHead>{t.wallets.currency}/{t.wallets.unit}</TableHead>
<TableHead>Type</TableHead> <TableHead>{t.wallets.type}</TableHead>
<TableHead>Created</TableHead> <TableHead>{t.common.date}</TableHead>
<TableHead className="text-right">Actions</TableHead> <TableHead className="text-right">{t.common.actions}</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
@@ -340,8 +342,8 @@ export function Wallets() {
<TableRow> <TableRow>
<TableCell colSpan={5} className="text-center py-8"> <TableCell colSpan={5} className="text-center py-8">
{filteredWallets.length !== wallets.length {filteredWallets.length !== wallets.length
? "No wallets match your filters" ? t.wallets.noWallets
: "No wallets found. Create your first wallet!" : t.wallets.createFirst
} }
</TableCell> </TableCell>
</TableRow> </TableRow>
@@ -380,15 +382,15 @@ export function Wallets() {
</AlertDialogTrigger> </AlertDialogTrigger>
<AlertDialogContent> <AlertDialogContent>
<AlertDialogHeader> <AlertDialogHeader>
<AlertDialogTitle>Delete Wallet</AlertDialogTitle> <AlertDialogTitle>{t.common.delete} {t.wallets.title}</AlertDialogTitle>
<AlertDialogDescription> <AlertDialogDescription>
Are you sure you want to delete "{wallet.name}"? This action cannot be undone. {t.wallets.deleteConfirm}
</AlertDialogDescription> </AlertDialogDescription>
</AlertDialogHeader> </AlertDialogHeader>
<AlertDialogFooter> <AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel> <AlertDialogCancel>{t.common.cancel}</AlertDialogCancel>
<AlertDialogAction onClick={() => deleteWallet(wallet.id)}> <AlertDialogAction onClick={() => deleteWallet(wallet.id)}>
Delete {t.common.delete}
</AlertDialogAction> </AlertDialogAction>
</AlertDialogFooter> </AlertDialogFooter>
</AlertDialogContent> </AlertDialogContent>