From 23898868ec4d840b49eaa9b5c9390029ecb0b3ae Mon Sep 17 00:00:00 2001 From: alireza Date: Wed, 26 Aug 2026 14:37:39 +0330 Subject: [PATCH] style: translate all units, currencies, and scale symbols into Persian across entire app --- frontend/src/components/LmeView.tsx | 4 +- frontend/src/lib/labels.ts | 61 +++++++++++++++++++++++++++++ frontend/src/routes/dashboard.tsx | 61 ++++++++++++++--------------- 3 files changed, 93 insertions(+), 33 deletions(-) diff --git a/frontend/src/components/LmeView.tsx b/frontend/src/components/LmeView.tsx index 8a40288..46b2382 100644 --- a/frontend/src/components/LmeView.tsx +++ b/frontend/src/components/LmeView.tsx @@ -512,9 +512,9 @@ export function LmeView() {
-

نرخ‌های برابری ارز (Exchange Rates)

+

نرخ‌های برابری ارز

- EUR / USD + یورو / دلار
diff --git a/frontend/src/lib/labels.ts b/frontend/src/lib/labels.ts index 43272c4..b5dbe85 100644 --- a/frontend/src/lib/labels.ts +++ b/frontend/src/lib/labels.ts @@ -163,3 +163,64 @@ export function commodityLabel(symbol: string, fallback: string): string { export function commodityGroup(symbol: string): CommodityGroup { return COMMODITIES[symbol]?.group ?? "metals"; } + +export const COMMODITY_UNITS: Record = { + "CL=F": "دلار / بشکه", + "BZ=F": "دلار / بشکه", + "NG=F": "دلار / MMBtu", + "RB=F": "دلار / گالن", + "HO=F": "دلار / گالن", + "GC=F": "دلار / اونس", + "SI=F": "دلار / اونس", + "HG=F": "دلار / پوند", + "PL=F": "دلار / اونس", + "PA=F": "دلار / اونس", + "ALI=F": "دلار / تن", + "NI=F": "دلار / تن", + "ZC=F": "سنت / بوشل", + "ZW=F": "سنت / بوشل", + "ZS=F": "سنت / بوشل", + "KC=F": "سنت / پوند", + "CT=F": "سنت / پوند", + "CC=F": "دلار / تن", + "SB=F": "سنت / پوند", + "OJ=F": "سنت / پوند", +}; + +export function faUnit(u: string | null | undefined): string { + if (!u) return ""; + const clean = u.trim(); + const map: Record = { + "USD": "دلار", + "$": "دلار", + "USc": "سنت", + "cents": "سنت", + "IRR": "ریال", + "Rial": "ریال", + "EUR": "یورو", + "GBP": "پوند", + "RMB": "یوان", + "CNY": "یوان", + "JPY": "ین", + "CAD": "دلار کانادا", + "AUD": "دلار استرالیا", + "TRY": "لیر", + "INR": "روپیه", + "BRL": "رئال", + "USD/mt": "دلار / تن", + "USD/dmt": "دلار / تن خشک", + "RMB/mt": "یوان / تن", + "USD/bbl": "دلار / بشکه", + "USD/oz": "دلار / اونس", + "USD/t.oz": "دلار / اونس", + "USD/lb": "دلار / پوند", + "c/lb": "سنت / پوند", + "USD/bu": "دلار / بوشل", + "c/bu": "سنت / بوشل", + "T$": "تریلیون دلار", + "B$": "میلیارد دلار", + "M$": "میلیون دلار", + "bps": "نقطه پایه", + }; + return map[clean] ?? clean; +} diff --git a/frontend/src/routes/dashboard.tsx b/frontend/src/routes/dashboard.tsx index 82f9f96..d853ee1 100644 --- a/frontend/src/routes/dashboard.tsx +++ b/frontend/src/routes/dashboard.tsx @@ -70,6 +70,8 @@ import { commodityGroup, COMMODITY_GROUP_LABELS, COMMODITY_GROUP_ORDER, + COMMODITY_UNITS, + faUnit, } from "@/lib/labels"; import { cn } from "@/lib/utils"; import { API_BASE } from "@/lib/api"; @@ -1203,7 +1205,7 @@ function CommodityView() { return chosen.map((r) => ({ label: commodityLabel(r.symbol, r.name), value: r.price, - unit: r.currency, + unit: COMMODITY_UNITS[r.symbol] || faUnit(r.currency), pct: r.pct, dir: (r.up ? "up" : "down") as "up" | "down", series: series[r.symbol], @@ -1295,7 +1297,7 @@ function CommodityCard({ value={row.price} format={(n) => faDigits(n.toLocaleString("en-US", { maximumFractionDigits: 2 }))} /> - {row.currency} + {COMMODITY_UNITS[row.symbol] || faUnit(row.currency)}
{series && series.length > 1 ? (
@@ -1444,17 +1446,18 @@ function SteelStocksView() { const kpis: KpiItem[] = rows.slice(0, 3).map((r) => ({ label: r.name, value: r.price || 0, - unit: "$", + unit: "دلار", pct: r.today_pct ?? undefined, dir: r.dir, series: series[r.code], decimals: 2, })); - const capStr = (v: number | null) => - v == null - ? "—" - : faDigits("$" + (v >= 1000 ? (v / 1000).toFixed(2) + "T" : v.toFixed(2) + "B")); + const capStr = (v: number | null) => { + if (v == null) return "—"; + if (v >= 1000) return `${faDigits((v / 1000).toFixed(2))} تریلیون دلار`; + return `${faDigits(v.toFixed(2))} میلیارد دلار`; + }; const pctText = (r: SteelRow) => r.today_pct != null ? faDigits( @@ -1475,11 +1478,11 @@ function SteelStocksView() { 0} title="قیمت سهام شرکت‌ها" - subtitle={faDigits( - `${rows.length} شرکت فولادی · مجموع ارزش بازار ${ - totalCap >= 1000 ? (totalCap / 1000).toFixed(2) + "T$" : totalCap.toFixed(0) + "B$" - }`, - )} + subtitle={ + `${faDigits(rows.length)} شرکت فولادی · مجموع ارزش بازار ${ + totalCap >= 1000 ? faDigits((totalCap / 1000).toFixed(2)) + " تریلیون دلار" : faDigits(totalCap.toFixed(0)) + " میلیارد دلار" + }` + } lastUpdate={lastUpdate} /> @@ -1550,7 +1553,7 @@ function SteelStocksView() {
قیمت - {r.price != null ? "$" + usd(r.price) : "—"} + {r.price != null ? usd(r.price) + " دلار" : "—"}
@@ -1585,7 +1588,7 @@ function SteelStocksView() { {capStr(r.market_cap)}
- {r.price != null ? "$" + usd(r.price) : "—"} + {r.price != null ? usd(r.price) + " دلار" : "—"}
@@ -2404,21 +2407,17 @@ type CryptoPayload = { const cryptoPrice = (p: number | null) => { if (p == null || !Number.isFinite(p)) return "—"; if (p >= 1) - return faDigits( - "$" + p.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }), - ); + return faDigits(p.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })) + " دلار"; if (p >= 0.01) - return faDigits( - "$" + p.toLocaleString("en-US", { minimumFractionDigits: 4, maximumFractionDigits: 4 }), - ); - return faDigits("$" + p.toLocaleString("en-US", { maximumFractionDigits: 8 })); + return faDigits(p.toLocaleString("en-US", { minimumFractionDigits: 4, maximumFractionDigits: 4 })) + " دلار"; + return faDigits(p.toLocaleString("en-US", { maximumFractionDigits: 8 })) + " دلار"; }; const usdAbbr = (n: number | null) => { if (n == null || !Number.isFinite(n)) return "—"; - if (n >= 1e12) return faDigits("$" + (n / 1e12).toFixed(2) + "T"); - if (n >= 1e9) return faDigits("$" + (n / 1e9).toFixed(2) + "B"); - if (n >= 1e6) return faDigits("$" + (n / 1e6).toFixed(2) + "M"); - return faDigits("$" + n.toLocaleString("en-US", { maximumFractionDigits: 0 })); + if (n >= 1e12) return faDigits((n / 1e12).toFixed(2)) + " تریلیون دلار"; + if (n >= 1e9) return faDigits((n / 1e9).toFixed(2)) + " میلیارد دلار"; + if (n >= 1e6) return faDigits((n / 1e6).toFixed(2)) + " میلیون دلار"; + return faDigits(n.toLocaleString("en-US", { maximumFractionDigits: 0 })) + " دلار"; }; const pctClass = (p: number | null) => p == null ? "text-muted-foreground" : p >= 0 ? "text-emerald-700" : "text-red-600"; @@ -2751,7 +2750,7 @@ function WorldEconomyView() { const fmtCell = (col: (typeof WE_COLS)[number], val: number | null) => { if (val == null) return "—"; - if (col.gdp) return faDigits((val / 1000).toFixed(2) + " T$"); + if (col.gdp) return faDigits((val / 1000).toFixed(2) + " تریلیون دلار"); return faDigits(formatNumber(val) + (col.suffix || "")); }; @@ -2860,7 +2859,7 @@ function WorldEconomyView() { {us10y && = 0 ? "up" : "down"} />}
- تغییر: {us10y ? faDigits((us10y.change_abs >= 0 ? "+" : "") + (us10y.change_abs * 100).toFixed(1) + " bps") : "—"} + تغییر: {us10y ? faDigits((us10y.change_abs >= 0 ? "+" : "") + (us10y.change_abs * 100).toFixed(1) + " نقطه پایه") : "—"}
@@ -2876,7 +2875,7 @@ function WorldEconomyView() { {de10y && = 0 ? "up" : "down"} />}
- تغییر: {de10y ? faDigits((de10y.change_abs >= 0 ? "+" : "") + (de10y.change_abs * 100).toFixed(1) + " bps") : "—"} + تغییر: {de10y ? faDigits((de10y.change_abs >= 0 ? "+" : "") + (de10y.change_abs * 100).toFixed(1) + " نقطه پایه") : "—"}
@@ -2892,7 +2891,7 @@ function WorldEconomyView() { {gb10y && = 0 ? "up" : "down"} />}
- تغییر: {gb10y ? faDigits((gb10y.change_abs >= 0 ? "+" : "") + (gb10y.change_abs * 100).toFixed(1) + " bps") : "—"} + تغییر: {gb10y ? faDigits((gb10y.change_abs >= 0 ? "+" : "") + (gb10y.change_abs * 100).toFixed(1) + " نقطه پایه") : "—"}
@@ -2903,7 +2902,7 @@ function WorldEconomyView() {
= 0 ? "text-emerald-700" : "text-red-600")}> - {spread10_2 != null ? faDigits((spread10_2 >= 0 ? "+" : "") + (spread10_2 * 100).toFixed(1) + " bps") : "—"} + {spread10_2 != null ? faDigits((spread10_2 >= 0 ? "+" : "") + (spread10_2 * 100).toFixed(1) + " نقطه پایه") : "—"} {(spread10_2 ?? 0) >= 0 ? "نرمال" : "وارونه (Inverted)"} @@ -2924,7 +2923,7 @@ function WorldEconomyView() { سررسید نرخ بازدهی (Yield) تغییر روزانه - تغییر پایه (bps) + تغییر (نقطه پایه) کف / سقف امروز بازدهی هفتگی بازدهی ۱ ماهه