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) |
+ تغییر (نقطه پایه) |
کف / سقف امروز |
بازدهی هفتگی |
بازدهی ۱ ماهه |