Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ pnpm events-import # Import community events
6. **Consider i18n** - All user-facing text should be translatable (use `getTranslations` and `getLocale`)
7. **Mobile-first** - Design for mobile, enhance for desktop
8. **Accessibility** - Use Radix primitives, semantic HTML
9. **Use locale-aware formatting wrappers** - Use `numberFormat()` from `src/lib/utils/numbers.ts` instead of `new Intl.NumberFormat()`, and `dateTimeFormat()` from `src/lib/utils/date.ts` instead of `new Intl.DateTimeFormat()` / `.toLocaleDateString()` / `.toLocaleTimeString()`. Both enforce correct numbering systems and calendar for Urdu and Arabic locales.

### Component Development

Expand Down
8 changes: 5 additions & 3 deletions app/[locale]/10years/_components/torchHoldersData.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { dateTimeFormat } from "@/lib/utils/date"

/**
* Pre-computed static torch holders data
* This data is final and will not be updated (the torch has been burned)
Expand Down Expand Up @@ -229,13 +231,13 @@ export const extractTwitterHandle = (twitterUrl: string): string | null => {

export const formatTorchDate = (timestamp: number): string => {
const date = new Date(timestamp * 1000)
const month = date.toLocaleDateString("en-US", { month: "long" })
const month = dateTimeFormat("en-US", { month: "long" }).format(date)
const day = date.getDate().toString().padStart(2, "0")
const time = date.toLocaleTimeString("en-US", {
const time = dateTimeFormat("en-US", {
hour: "numeric",
minute: "2-digit",
hour12: true,
})
}).format(date)

return `${month} ${day}, ${time}`
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { useLocale } from "next-intl"

import { Progress } from "@/components/ui/progress"

import { dateTimeFormat } from "@/lib/utils/date"

import { type BadgeWithOwned } from "../CollectiblesContent"

import useTranslation from "@/hooks/useTranslation"
Expand Down Expand Up @@ -38,7 +40,7 @@ const CollectiblesProgress = ({ badges }: CollectiblesProgressProps) => {
{contributorSinceYear < Infinity && (
<p className="text-body-medium">
{t("page-collectibles-contributing-since")}:{" "}
{new Intl.DateTimeFormat(locale, {
{dateTimeFormat(locale, {
year: "numeric",
}).format(new Date().setFullYear(contributorSinceYear))}
</p>
Expand Down
13 changes: 10 additions & 3 deletions app/[locale]/collectibles/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Section } from "@/components/ui/section"

import { getAppPageContributorInfo } from "@/lib/utils/contributors"
import { getMetadata } from "@/lib/utils/metadata"
import { numberFormat } from "@/lib/utils/numbers"
import { getRequiredNamespacesForPage } from "@/lib/utils/translations"

import CollectiblesPage from "./_components/Collectibles/lazy"
Expand Down Expand Up @@ -111,7 +112,9 @@ export default async function Page(props: { params: Promise<PageParams> }) {
{/* Minted */}
<div className="flex h-full w-full flex-col items-center justify-center rounded-xl border border-accent-a/20 bg-gradient-to-b from-accent-a/5 to-accent-a/15 px-4 py-8 text-accent-a max-md:col-span-2 xl:col-span-2 xl:p-6">
<div className="text-4xl font-bold md:text-6xl">
{stats.collectorsCount?.toLocaleString(locale) ?? "-"}
{stats.collectorsCount
? numberFormat(locale).format(stats.collectorsCount)
: "-"}
</div>
<div className="text-center font-bold">
{t("page-collectibles-stats-minted")}
Expand All @@ -120,7 +123,9 @@ export default async function Page(props: { params: Promise<PageParams> }) {
{/* Collectors */}
<div className="flex h-full w-full flex-col items-center justify-center rounded-xl border border-accent-b/20 bg-gradient-to-b from-accent-b/5 to-accent-b/15 p-6 text-accent-b">
<div className="text-4xl font-bold md:text-6xl">
{stats.uniqueAddressesCount?.toLocaleString(locale) ?? "-"}
{stats.uniqueAddressesCount
? numberFormat(locale).format(stats.uniqueAddressesCount)
: "-"}
</div>
<div className="text-center font-bold">
{t("page-collectibles-stats-collectors")}
Expand All @@ -129,7 +134,9 @@ export default async function Page(props: { params: Promise<PageParams> }) {
{/* Unique Badges */}
<div className="flex h-full w-full flex-col items-center justify-center rounded-xl border border-accent-c/20 bg-gradient-to-b from-accent-c/5 to-accent-c/15 p-6 text-accent-c">
<div className="text-4xl font-bold md:text-6xl">
{stats.collectiblesCount?.toLocaleString(locale) ?? "-"}
{stats.collectiblesCount
? numberFormat(locale).format(stats.collectiblesCount)
: "-"}
</div>
<div className="text-center font-bold">
{t("page-collectibles-stats-unique-badges")}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ButtonLink } from "@/components/ui/buttons/Button"
import { Tag, TagsInlineText } from "@/components/ui/tag"

import { formatDate, getValidDate } from "@/lib/utils/date"
import { numberFormat } from "@/lib/utils/numbers"
import { isExternal } from "@/lib/utils/url"

import { DEV_TOOL_CATEGORY_SLUGS } from "../constants"
Expand Down Expand Up @@ -125,7 +126,7 @@ const ToolModalContents = async ({ tool }: { tool: DeveloperTool }) => {
className="text-sm"
title={t("page-developers-tools-stats-stargazers")}
>
({new Intl.NumberFormat(locale).format(stargazers)}
({numberFormat(locale).format(stargazers)}
</span>
<Star className="-mx-[0.5ch] !size-3" />
<span className="text-sm">)</span>
Expand All @@ -139,7 +140,7 @@ const ToolModalContents = async ({ tool }: { tool: DeveloperTool }) => {
title={t("page-developers-tools-stats-downloads")}
>
(
{new Intl.NumberFormat(locale, {
{numberFormat(locale, {
notation: "compact",
}).format(downloads)}
</span>
Expand Down
14 changes: 8 additions & 6 deletions app/[locale]/layer-2/_components/layer-2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import Translation from "@/components/Translation"
import { ButtonLink } from "@/components/ui/buttons/Button"
import InlineLink from "@/components/ui/Link"

import { numberFormat } from "@/lib/utils/numbers"

import { Rollups } from "@/data/networks/networks"

import useTranslation from "@/hooks/useTranslation"
Expand Down Expand Up @@ -126,12 +128,10 @@ const Layer2Hub = ({
<div className="max-w-[224px]">
<p className="text-5xl">
$
{(
growThePieData.dailyTxCosts["ethereum"] || 0
).toLocaleString(locale as Lang, {
{numberFormat(locale, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
}).format(growThePieData.dailyTxCosts["ethereum"] || 0)}
</p>
<p className="text-body-medium">
{t("page-layer-2-blockchain-transaction-cost")}
Expand All @@ -143,10 +143,12 @@ const Layer2Hub = ({
<div className="max-w-[224px]">
<p className="text-5xl">
$
{medianTxCost.toLocaleString(locale as Lang, {
{numberFormat(locale, {
minimumFractionDigits: 2,
maximumFractionDigits: 3,
})}
}).format(
typeof medianTxCost === "number" ? medianTxCost : 0
)}
</p>
<p className="text-body-medium">
{t("page-layer-2-networks-transaction-cost")}
Expand Down
4 changes: 3 additions & 1 deletion app/[locale]/resources/_components/SlotCountdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { useLocale } from "next-intl"

import RadialChart from "@/components/RadialChart"

import { numberFormat } from "@/lib/utils/numbers"

const SlotCountdownChart = ({ children }: { children: string }) => {
const [timeToNextBlock, setTimeToNextBlock] = useState(12)
const locale = useLocale()
Expand All @@ -28,7 +30,7 @@ const SlotCountdownChart = ({ children }: { children: string }) => {
<RadialChart
value={timeToNextBlock}
totalValue={12}
displayValue={new Intl.NumberFormat(locale, {
displayValue={numberFormat(locale, {
style: "unit",
unit: "second",
unitDisplay: "narrow",
Expand Down
4 changes: 3 additions & 1 deletion app/[locale]/resources/_components/UpgradeCountdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import type { NetworkUpgradeDetails } from "@/lib/types"

import { BaseLink } from "@/components/ui/Link"

import { dateTimeFormat } from "@/lib/utils/date"

import networkUpgradeSummaryData from "@/data/networkUpgradeSummaryData"

const getLatestNetworkUpgradeDate = () => {
Expand Down Expand Up @@ -106,7 +108,7 @@ const UpgradeCountdown = () => {
) : (
<div className="rounded-full bg-success px-2 py-1 text-xs font-normal uppercase text-success-light">
Live Since{" "}
{new Intl.DateTimeFormat(locale, { timeZone: "UTC" }).format(
{dateTimeFormat(locale, { timeZone: "UTC" }).format(
new Date(upgradeDate)
)}
</div>
Expand Down
3 changes: 2 additions & 1 deletion app/[locale]/resources/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import TabNav, { StickyContainer } from "@/components/ui/TabNav"
import { cn } from "@/lib/utils/cn"
import { getAppPageContributorInfo } from "@/lib/utils/contributors"
import { getMetadata } from "@/lib/utils/metadata"
import { numberFormat } from "@/lib/utils/numbers"

import { GITHUB_REPO_URL } from "@/lib/constants"

Expand Down Expand Up @@ -56,7 +57,7 @@ const Page = async (props: { params: Promise<PageParams> }) => {
// Extract blob stats directly (getBlobscanStats returns BlobscanStats, not wrapped in MetricReturnData)
const blobStats = {
avgBlobFee: blobscanOverallStats.avgBlobFee,
totalBlobs: new Intl.NumberFormat(undefined, {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏼

totalBlobs: numberFormat(locale, {
notation: "compact",
maximumFractionDigits: 1,
}).format(blobscanOverallStats.totalBlobs),
Expand Down
8 changes: 2 additions & 6 deletions app/[locale]/resources/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { getLocale, getTranslations } from "next-intl/server"

import { Lang } from "@/lib/types"

import BigNumber from "@/components/BigNumber"
import SectionIconArrowsFullscreen from "@/components/icons/arrows-fullscreen.svg"
import SectionIconEthGlyph from "@/components/icons/eth-glyph.svg"
Expand All @@ -10,7 +8,6 @@ import SectionIconHeartPulse from "@/components/icons/heart-pulse.svg"
import SectionIconPrivacy from "@/components/icons/privacy.svg"

import { formatSmallUSD } from "@/lib/utils/numbers"
import { getLocaleForNumberFormat } from "@/lib/utils/translations"

import {
SlotCountdownChart,
Expand Down Expand Up @@ -64,7 +61,6 @@ export const getResources = async ({
}): Promise<DashboardSection[]> => {
const locale = await getLocale()
const t = await getTranslations({ locale, namespace: "page-resources" })
const localeForNumberFormat = getLocaleForNumberFormat(locale as Lang)

// Fetch ETH price using the new data-layer function (already cached)
const ethPrice = await getEthPrice()
Expand All @@ -82,7 +78,7 @@ export const getResources = async ({
value: formatSmallUSD(
// Converting value from wei to USD
avgBlobFee * 1e-18 * ethPrice.value,
localeForNumberFormat
locale
),
}

Expand All @@ -91,7 +87,7 @@ export const getResources = async ({
? { error: txCostsMedianUsd.error }
: {
...txCostsMedianUsd,
value: formatSmallUSD(txCostsMedianUsd.value, localeForNumberFormat),
value: formatSmallUSD(txCostsMedianUsd.value, locale),
}

const networkBoxes: DashboardBox[] = [
Expand Down
4 changes: 2 additions & 2 deletions app/[locale]/roadmap/_components/ReleaseCarousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from "@/components/ui/carousel"

import { cn } from "@/lib/utils/cn"
import { formatDate } from "@/lib/utils/date"
import { dateTimeFormat, formatDate } from "@/lib/utils/date"

import { getReleasesData, Release } from "@/data/roadmap/releases"

Expand Down Expand Up @@ -100,7 +100,7 @@ const ReleaseCarousel = () => {
return ""

if ("plannedReleaseYear" in release && release.plannedReleaseYear)
return new Intl.DateTimeFormat(locale, {
return dateTimeFormat(locale, {
year: "numeric",
}).format(new Date(Number(release.plannedReleaseYear), 0, 1))

Expand Down
3 changes: 2 additions & 1 deletion app/[locale]/stablecoins/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { cn } from "@/lib/utils/cn"
import { getAppPageContributorInfo } from "@/lib/utils/contributors"
import { getMetadata } from "@/lib/utils/metadata"
import { numberFormat } from "@/lib/utils/numbers"
import { getRequiredNamespacesForPage } from "@/lib/utils/translations"

import { stablecoins } from "./data"
Expand Down Expand Up @@ -118,7 +119,7 @@ async function Page(props: { params: Promise<PageParams> }) {
.sort((a, b) => b.market_cap - a.market_cap)
.map(({ market_cap, ...rest }) => ({
...rest,
marketCap: new Intl.NumberFormat("en-US", {
marketCap: numberFormat(locale, {
style: "currency",
currency: "USD",
minimumFractionDigits: 0,
Expand Down
18 changes: 8 additions & 10 deletions app/[locale]/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import { getTranslations } from "next-intl/server"

import type { AllHomepageActivityData, Lang, StatsBoxMetric } from "@/lib/types"

import { getLocaleForNumberFormat } from "@/lib/utils/translations"
import { numberFormat } from "@/lib/utils/numbers"

const formatLargeUSD = (value: number, locale: string): string => {
return new Intl.NumberFormat(locale, {
return numberFormat(locale, {
style: "currency",
currency: "USD",
notation: "compact",
Expand All @@ -20,7 +20,7 @@ const formatLargeUSD = (value: number, locale: string): string => {
}

const formatSmallUSD = (value: number, locale: string): string => {
return new Intl.NumberFormat(locale, {
return numberFormat(locale, {
style: "currency",
currency: "USD",
notation: "compact",
Expand All @@ -30,7 +30,7 @@ const formatSmallUSD = (value: number, locale: string): string => {
}

const formatLargeNumber = (value: number, locale: string): string => {
return new Intl.NumberFormat(locale, {
return numberFormat(locale, {
notation: "compact",
minimumSignificantDigits: 3,
maximumSignificantDigits: 4,
Expand All @@ -49,8 +49,6 @@ export const getActivity = async (
): Promise<StatsBoxMetric[]> => {
const t = await getTranslations("page-index")

const localeForNumberFormat = getLocaleForNumberFormat(locale)

const hasEthStakerAndPriceData =
"value" in totalEthStaked && "value" in ethPrice
const totalStakedInUsd = hasEthStakerAndPriceData
Expand All @@ -68,31 +66,31 @@ export const getActivity = async (
}
: {
...totalEthStaked,
value: formatLargeUSD(totalStakedInUsd, localeForNumberFormat),
value: formatLargeUSD(totalStakedInUsd, locale),
}

const valueLocked =
"error" in totalValueLocked
? { error: totalValueLocked.error }
: {
...totalValueLocked,
value: formatLargeUSD(totalValueLocked.value, localeForNumberFormat),
value: formatLargeUSD(totalValueLocked.value, locale),
}

const txs =
"error" in txCount
? { error: txCount.error }
: {
...txCount,
value: formatLargeNumber(txCount.value, localeForNumberFormat),
value: formatLargeNumber(txCount.value, locale),
}

const medianTxCost =
"error" in txCostsMedianUsd
? { error: txCostsMedianUsd.error }
: {
...txCostsMedianUsd,
value: formatSmallUSD(txCostsMedianUsd.value, localeForNumberFormat),
value: formatSmallUSD(txCostsMedianUsd.value, locale),
}

const metrics: StatsBoxMetric[] = [
Expand Down
Loading
Loading