style: translate all units, currencies, and scale symbols into Persian across entire app
This commit is contained in:
parent
984d44a18b
commit
23898868ec
|
|
@ -512,9 +512,9 @@ export function LmeView() {
|
||||||
<div className="flex items-center justify-between border-b border-border/50 pb-3">
|
<div className="flex items-center justify-between border-b border-border/50 pb-3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<DollarSign className="w-4 h-4 text-primary" />
|
<DollarSign className="w-4 h-4 text-primary" />
|
||||||
<h3 className="text-sm font-semibold text-foreground">نرخهای برابری ارز (Exchange Rates)</h3>
|
<h3 className="text-sm font-semibold text-foreground">نرخهای برابری ارز</h3>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-[11px] text-muted-foreground font-mono">EUR / USD</span>
|
<span className="text-[11px] text-muted-foreground">یورو / دلار</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3 pt-1">
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3 pt-1">
|
||||||
|
|
|
||||||
|
|
@ -163,3 +163,64 @@ export function commodityLabel(symbol: string, fallback: string): string {
|
||||||
export function commodityGroup(symbol: string): CommodityGroup {
|
export function commodityGroup(symbol: string): CommodityGroup {
|
||||||
return COMMODITIES[symbol]?.group ?? "metals";
|
return COMMODITIES[symbol]?.group ?? "metals";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const COMMODITY_UNITS: Record<string, string> = {
|
||||||
|
"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<string, string> = {
|
||||||
|
"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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,8 @@ import {
|
||||||
commodityGroup,
|
commodityGroup,
|
||||||
COMMODITY_GROUP_LABELS,
|
COMMODITY_GROUP_LABELS,
|
||||||
COMMODITY_GROUP_ORDER,
|
COMMODITY_GROUP_ORDER,
|
||||||
|
COMMODITY_UNITS,
|
||||||
|
faUnit,
|
||||||
} from "@/lib/labels";
|
} from "@/lib/labels";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { API_BASE } from "@/lib/api";
|
import { API_BASE } from "@/lib/api";
|
||||||
|
|
@ -1203,7 +1205,7 @@ function CommodityView() {
|
||||||
return chosen.map((r) => ({
|
return chosen.map((r) => ({
|
||||||
label: commodityLabel(r.symbol, r.name),
|
label: commodityLabel(r.symbol, r.name),
|
||||||
value: r.price,
|
value: r.price,
|
||||||
unit: r.currency,
|
unit: COMMODITY_UNITS[r.symbol] || faUnit(r.currency),
|
||||||
pct: r.pct,
|
pct: r.pct,
|
||||||
dir: (r.up ? "up" : "down") as "up" | "down",
|
dir: (r.up ? "up" : "down") as "up" | "down",
|
||||||
series: series[r.symbol],
|
series: series[r.symbol],
|
||||||
|
|
@ -1295,7 +1297,7 @@ function CommodityCard({
|
||||||
value={row.price}
|
value={row.price}
|
||||||
format={(n) => faDigits(n.toLocaleString("en-US", { maximumFractionDigits: 2 }))}
|
format={(n) => faDigits(n.toLocaleString("en-US", { maximumFractionDigits: 2 }))}
|
||||||
/>
|
/>
|
||||||
<span className="mr-1 text-[10px] font-normal text-muted-foreground">{row.currency}</span>
|
<span className="mr-1 text-[10px] font-normal text-muted-foreground">{COMMODITY_UNITS[row.symbol] || faUnit(row.currency)}</span>
|
||||||
</div>
|
</div>
|
||||||
{series && series.length > 1 ? (
|
{series && series.length > 1 ? (
|
||||||
<div className="-mx-4 mt-2">
|
<div className="-mx-4 mt-2">
|
||||||
|
|
@ -1444,17 +1446,18 @@ function SteelStocksView() {
|
||||||
const kpis: KpiItem[] = rows.slice(0, 3).map((r) => ({
|
const kpis: KpiItem[] = rows.slice(0, 3).map((r) => ({
|
||||||
label: r.name,
|
label: r.name,
|
||||||
value: r.price || 0,
|
value: r.price || 0,
|
||||||
unit: "$",
|
unit: "دلار",
|
||||||
pct: r.today_pct ?? undefined,
|
pct: r.today_pct ?? undefined,
|
||||||
dir: r.dir,
|
dir: r.dir,
|
||||||
series: series[r.code],
|
series: series[r.code],
|
||||||
decimals: 2,
|
decimals: 2,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const capStr = (v: number | null) =>
|
const capStr = (v: number | null) => {
|
||||||
v == null
|
if (v == null) return "—";
|
||||||
? "—"
|
if (v >= 1000) return `${faDigits((v / 1000).toFixed(2))} تریلیون دلار`;
|
||||||
: faDigits("$" + (v >= 1000 ? (v / 1000).toFixed(2) + "T" : v.toFixed(2) + "B"));
|
return `${faDigits(v.toFixed(2))} میلیارد دلار`;
|
||||||
|
};
|
||||||
const pctText = (r: SteelRow) =>
|
const pctText = (r: SteelRow) =>
|
||||||
r.today_pct != null
|
r.today_pct != null
|
||||||
? faDigits(
|
? faDigits(
|
||||||
|
|
@ -1475,11 +1478,11 @@ function SteelStocksView() {
|
||||||
<ViewHeader
|
<ViewHeader
|
||||||
live={rows.length > 0}
|
live={rows.length > 0}
|
||||||
title="قیمت سهام شرکتها"
|
title="قیمت سهام شرکتها"
|
||||||
subtitle={faDigits(
|
subtitle={
|
||||||
`${rows.length} شرکت فولادی · مجموع ارزش بازار ${
|
`${faDigits(rows.length)} شرکت فولادی · مجموع ارزش بازار ${
|
||||||
totalCap >= 1000 ? (totalCap / 1000).toFixed(2) + "T$" : totalCap.toFixed(0) + "B$"
|
totalCap >= 1000 ? faDigits((totalCap / 1000).toFixed(2)) + " تریلیون دلار" : faDigits(totalCap.toFixed(0)) + " میلیارد دلار"
|
||||||
}`,
|
}`
|
||||||
)}
|
}
|
||||||
lastUpdate={lastUpdate}
|
lastUpdate={lastUpdate}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
@ -1550,7 +1553,7 @@ function SteelStocksView() {
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<span className="text-[10px] text-muted-foreground">قیمت</span>
|
<span className="text-[10px] text-muted-foreground">قیمت</span>
|
||||||
<span className="font-mono text-sm font-bold tabular-nums text-foreground">
|
<span className="font-mono text-sm font-bold tabular-nums text-foreground">
|
||||||
{r.price != null ? "$" + usd(r.price) : "—"}
|
{r.price != null ? usd(r.price) + " دلار" : "—"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
|
|
@ -1585,7 +1588,7 @@ function SteelStocksView() {
|
||||||
{capStr(r.market_cap)}
|
{capStr(r.market_cap)}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-2 text-left font-mono tabular-nums text-foreground whitespace-nowrap">
|
<div className="col-span-2 text-left font-mono tabular-nums text-foreground whitespace-nowrap">
|
||||||
{r.price != null ? "$" + usd(r.price) : "—"}
|
{r.price != null ? usd(r.price) + " دلار" : "—"}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-2 flex items-center justify-center gap-2">
|
<div className="col-span-2 flex items-center justify-center gap-2">
|
||||||
<SteelBar pct={r.today_pct} dir={r.dir} />
|
<SteelBar pct={r.today_pct} dir={r.dir} />
|
||||||
|
|
@ -2404,21 +2407,17 @@ type CryptoPayload = {
|
||||||
const cryptoPrice = (p: number | null) => {
|
const cryptoPrice = (p: number | null) => {
|
||||||
if (p == null || !Number.isFinite(p)) return "—";
|
if (p == null || !Number.isFinite(p)) return "—";
|
||||||
if (p >= 1)
|
if (p >= 1)
|
||||||
return faDigits(
|
return faDigits(p.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })) + " دلار";
|
||||||
"$" + p.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }),
|
|
||||||
);
|
|
||||||
if (p >= 0.01)
|
if (p >= 0.01)
|
||||||
return faDigits(
|
return faDigits(p.toLocaleString("en-US", { minimumFractionDigits: 4, maximumFractionDigits: 4 })) + " دلار";
|
||||||
"$" + p.toLocaleString("en-US", { minimumFractionDigits: 4, maximumFractionDigits: 4 }),
|
return faDigits(p.toLocaleString("en-US", { maximumFractionDigits: 8 })) + " دلار";
|
||||||
);
|
|
||||||
return faDigits("$" + p.toLocaleString("en-US", { maximumFractionDigits: 8 }));
|
|
||||||
};
|
};
|
||||||
const usdAbbr = (n: number | null) => {
|
const usdAbbr = (n: number | null) => {
|
||||||
if (n == null || !Number.isFinite(n)) return "—";
|
if (n == null || !Number.isFinite(n)) return "—";
|
||||||
if (n >= 1e12) return faDigits("$" + (n / 1e12).toFixed(2) + "T");
|
if (n >= 1e12) return faDigits((n / 1e12).toFixed(2)) + " تریلیون دلار";
|
||||||
if (n >= 1e9) return faDigits("$" + (n / 1e9).toFixed(2) + "B");
|
if (n >= 1e9) return faDigits((n / 1e9).toFixed(2)) + " میلیارد دلار";
|
||||||
if (n >= 1e6) return faDigits("$" + (n / 1e6).toFixed(2) + "M");
|
if (n >= 1e6) return faDigits((n / 1e6).toFixed(2)) + " میلیون دلار";
|
||||||
return faDigits("$" + n.toLocaleString("en-US", { maximumFractionDigits: 0 }));
|
return faDigits(n.toLocaleString("en-US", { maximumFractionDigits: 0 })) + " دلار";
|
||||||
};
|
};
|
||||||
const pctClass = (p: number | null) =>
|
const pctClass = (p: number | null) =>
|
||||||
p == null ? "text-muted-foreground" : p >= 0 ? "text-emerald-700" : "text-red-600";
|
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) => {
|
const fmtCell = (col: (typeof WE_COLS)[number], val: number | null) => {
|
||||||
if (val == null) return "—";
|
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 || ""));
|
return faDigits(formatNumber(val) + (col.suffix || ""));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -2860,7 +2859,7 @@ function WorldEconomyView() {
|
||||||
{us10y && <DeltaPill pct={us10y.change} dir={us10y.change >= 0 ? "up" : "down"} />}
|
{us10y && <DeltaPill pct={us10y.change} dir={us10y.change >= 0 ? "up" : "down"} />}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
||||||
تغییر: {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) + " نقطه پایه") : "—"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -2876,7 +2875,7 @@ function WorldEconomyView() {
|
||||||
{de10y && <DeltaPill pct={de10y.change} dir={de10y.change >= 0 ? "up" : "down"} />}
|
{de10y && <DeltaPill pct={de10y.change} dir={de10y.change >= 0 ? "up" : "down"} />}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
||||||
تغییر: {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) + " نقطه پایه") : "—"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -2892,7 +2891,7 @@ function WorldEconomyView() {
|
||||||
{gb10y && <DeltaPill pct={gb10y.change} dir={gb10y.change >= 0 ? "up" : "down"} />}
|
{gb10y && <DeltaPill pct={gb10y.change} dir={gb10y.change >= 0 ? "up" : "down"} />}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
||||||
تغییر: {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) + " نقطه پایه") : "—"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -2903,7 +2902,7 @@ function WorldEconomyView() {
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 flex items-baseline justify-between">
|
<div className="mt-2 flex items-baseline justify-between">
|
||||||
<span className={cn("text-2xl font-bold font-mono tabular-nums", (spread10_2 ?? 0) >= 0 ? "text-emerald-700" : "text-red-600")}>
|
<span className={cn("text-2xl font-bold font-mono tabular-nums", (spread10_2 ?? 0) >= 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) + " نقطه پایه") : "—"}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-[11px] px-2 py-0.5 rounded-full font-mono font-medium bg-muted text-muted-foreground">
|
<span className="text-[11px] px-2 py-0.5 rounded-full font-mono font-medium bg-muted text-muted-foreground">
|
||||||
{(spread10_2 ?? 0) >= 0 ? "نرمال" : "وارونه (Inverted)"}
|
{(spread10_2 ?? 0) >= 0 ? "نرمال" : "وارونه (Inverted)"}
|
||||||
|
|
@ -2924,7 +2923,7 @@ function WorldEconomyView() {
|
||||||
<th className="p-3 font-semibold text-center">سررسید</th>
|
<th className="p-3 font-semibold text-center">سررسید</th>
|
||||||
<th className="p-3 font-semibold text-center">نرخ بازدهی (Yield)</th>
|
<th className="p-3 font-semibold text-center">نرخ بازدهی (Yield)</th>
|
||||||
<th className="p-3 font-semibold text-center">تغییر روزانه</th>
|
<th className="p-3 font-semibold text-center">تغییر روزانه</th>
|
||||||
<th className="p-3 font-semibold text-center">تغییر پایه (bps)</th>
|
<th className="p-3 font-semibold text-center">تغییر (نقطه پایه)</th>
|
||||||
<th className="p-3 font-semibold text-center">کف / سقف امروز</th>
|
<th className="p-3 font-semibold text-center">کف / سقف امروز</th>
|
||||||
<th className="p-3 font-semibold text-center">بازدهی هفتگی</th>
|
<th className="p-3 font-semibold text-center">بازدهی هفتگی</th>
|
||||||
<th className="p-3 font-semibold text-center">بازدهی ۱ ماهه</th>
|
<th className="p-3 font-semibold text-center">بازدهی ۱ ماهه</th>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue