Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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 @@ -153,6 +153,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 @@ -110,7 +111,9 @@ export default async function Page({ params }: { params: 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 @@ -119,7 +122,9 @@ export default async function Page({ params }: { params: 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 @@ -128,7 +133,9 @@ export default async function Page({ params }: { params: 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
5 changes: 3 additions & 2 deletions 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 @@ -105,8 +107,7 @@ const UpgradeCountdown = () => {
scalingUpgradeCountdown
) : (
<div className="rounded-full bg-success px-2 py-1 text-xs font-normal uppercase text-success-light">
Live Since{" "}
{new Intl.DateTimeFormat(locale, {}).format(new Date(upgradeDate))}
Live Since {dateTimeFormat(locale).format(new Date(upgradeDate))}
</div>
)}
</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 @@ -55,7 +56,7 @@ const Page = async ({ params }: { params: 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,8 +1,6 @@
import dynamic from "next/dynamic"
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 @@ -12,7 +10,6 @@ import SectionIconPrivacy from "@/components/icons/privacy.svg"
import { Spinner } from "@/components/ui/spinner"

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

import type { DashboardBox, DashboardSection } from "./types"

Expand Down Expand Up @@ -86,7 +83,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 @@ -104,7 +100,7 @@ export const getResources = async ({
value: formatSmallUSD(
// Converting value from wei to USD
avgBlobFee * 1e-18 * ethPrice.value,
localeForNumberFormat
locale
),
}

Expand All @@ -113,7 +109,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 @@ -117,7 +118,7 @@ async function Page({ params }: { params: 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