diff --git a/app/package-lock.json b/app/package-lock.json index 905828d0..891a85db 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -26,6 +26,7 @@ "server-only": "^0.0.1", "sharp": "^0.35.5", "tailwind-merge": "^3.6.0", + "use-intl": "4.14.9", "viem": "^2.47.6", "wagmi": "^3.5.0" }, @@ -1381,6 +1382,27 @@ "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", "license": "MIT" }, + "node_modules/@formatjs/fast-memoize": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.7.tgz", + "integrity": "sha512-zXfhLpvA6T7+efdt9JLbBwZ00tT7NsBMDVnDu8rpHeNNv8KfRZAMo2gkG0k9lK/Nzc//3kJ9pImsfuJxk3KhUA==", + "license": "MIT" + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.21.tgz", + "integrity": "sha512-Vnl7IOSyMRaP4Pjv48etkT2nlcIwzh4QWIa3hewzGlZZPBbft+TbMir4MijpDViOLN/1hvkGC10oYMuilsG+fw==", + "license": "MIT", + "dependencies": { + "@formatjs/icu-skeleton-parser": "2.1.12" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.12.tgz", + "integrity": "sha512-ca7tZMLpfHX3sUD7hP6gE/qr6Iq89EDd3ZLeRhbsB7r0UD55DGJq+tmFLzrGrnx5StahUevQmQQVtbDRHsfDHA==", + "license": "MIT" + }, "node_modules/@humanfs/core": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", @@ -2364,6 +2386,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@schummar/icu-type-parser": { + "version": "1.21.5", + "resolved": "https://registry.npmjs.org/@schummar/icu-type-parser/-/icu-type-parser-1.21.5.tgz", + "integrity": "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==", + "license": "MIT" + }, "node_modules/@scure/base": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", @@ -5472,6 +5500,21 @@ "hermes-estree": "0.25.1" } }, + "node_modules/icu-minify": { + "version": "4.14.9", + "resolved": "https://registry.npmjs.org/icu-minify/-/icu-minify-4.14.9.tgz", + "integrity": "sha512-PmO+fNnC3K3mfPKTnm3RrPERrhQZnjm1AlpyZQ0ShbXi8Y/kYZ3YOde8TEjCLz9k3P2DmzkBn8lykGrCAi1Ajw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "license": "MIT", + "dependencies": { + "@formatjs/icu-messageformat-parser": "^3.4.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -5524,6 +5567,31 @@ "node": ">= 0.4" } }, + "node_modules/intl-messageformat": { + "version": "11.2.15", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-11.2.15.tgz", + "integrity": "sha512-W4VNytsXyWgW5lvVchmsb9xgA5rSKqoflu3/IQ9UCtB0z4R+Bx9MoEkwFT/+30RCl/KzUoH0QGGe9lppF5SuvQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/fast-memoize": "3.1.7", + "@formatjs/icu-messageformat-parser": "3.5.18" + } + }, + "node_modules/intl-messageformat/node_modules/@formatjs/icu-messageformat-parser": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.18.tgz", + "integrity": "sha512-wX1efcL8d7K5QapOTRsP/OLTA/kpwe4LwqWyNxDNg5iRs8i9jJbCyxB5P8jc4KOW5oiLzz2DJr+BRY5xMV9+bA==", + "license": "MIT", + "dependencies": { + "@formatjs/icu-skeleton-parser": "2.1.11" + } + }, + "node_modules/intl-messageformat/node_modules/@formatjs/icu-skeleton-parser": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.11.tgz", + "integrity": "sha512-j8cUmOJzVgkHuS0QiQ6ga76UIoLOFSAMWhs7aZJztH3aAdCOAE6vpC8KVvFB4cU10ON0y2/5oOVmPJ43s2lTwA==", + "license": "MIT" + }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -8262,6 +8330,33 @@ "punycode": "^2.1.0" } }, + "node_modules/use-intl": { + "version": "4.14.9", + "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.14.9.tgz", + "integrity": "sha512-37ktvdCCz+6JY2VFPl/GV69Ds4ahiUT2c2xEZZRZYxdgGLxFsUbdxzjQVRm3YMIOUU0VPs6zvlifb4Yjk4IxIg==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "^3.1.0", + "@schummar/icu-type-parser": "1.21.5", + "icu-minify": "^4.14.9", + "intl-messageformat": "^11.1.0" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-sync-external-store": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", diff --git a/app/package.json b/app/package.json index 9dee25df..b102f18a 100644 --- a/app/package.json +++ b/app/package.json @@ -30,6 +30,7 @@ "server-only": "^0.0.1", "sharp": "^0.35.5", "tailwind-merge": "^3.6.0", + "use-intl": "4.14.9", "viem": "^2.47.6", "wagmi": "^3.5.0" }, diff --git a/app/src/app/(home)/loading.tsx b/app/src/app/(home)/loading.tsx index 47252222..9e5c172b 100644 --- a/app/src/app/(home)/loading.tsx +++ b/app/src/app/(home)/loading.tsx @@ -4,6 +4,7 @@ import hero from "@/components/launchpad/LaunchHero.module.css"; import machine from "@/components/launchpad/LaunchMachine.module.css"; import totals from "@/components/launchpad/LaunchMechanism.module.css"; import trend from "@/components/launchpad/TrendingStrip.module.css"; +import { getTranslations } from "@/i18n/server"; /** * Home skeleton, in the page's own order: hero (text, the locker in its stage and the totals, in the real grid), the live @@ -22,9 +23,10 @@ function SkBoardCard() { ); } -export default function Loading() { +export default async function Loading() { + const t = await getTranslations("info"); return ( -
+
diff --git a/app/src/app/(home)/page.tsx b/app/src/app/(home)/page.tsx index a9f2737f..54639474 100644 --- a/app/src/app/(home)/page.tsx +++ b/app/src/app/(home)/page.tsx @@ -19,6 +19,7 @@ import LaunchPill from "@/components/launchpad/LaunchPill"; import WhyFree from "@/components/launchpad/WhyFree"; import { MagicCard } from "@/components/vendor/magic-card"; import { LAYOUT_COOKIE, parseLayout } from "@/lib/launchpad/list-layout"; +import { getTranslations } from "@/i18n/server"; export const dynamic = "force-dynamic"; // Title and description come from the root layout; ?sort= / ?chain= / ?window= / ?view= are all this one page. @@ -45,6 +46,7 @@ export default async function Home({ searchParams }: { searchParams: Promise<{ s ]); const trending = await withBoardTape(fetchedTrending ?? trendingFrom(page.items)); // the default view's first page doubles as the strip's candidates; the tapes are the cards' recent trades const now = nowMs(); + const t = await getTranslations("hero"); return ( <> @@ -55,7 +57,7 @@ export default async function Home({ searchParams }: { searchParams: Promise<{ s inRiverWindow(item, now))} recent={feed} serverNow={now} coveredSince={riverCoverage(feed, RIVER_SEED, now)} lastActivityAt={feed[0] ? new Date(feed[0].at).getTime() : 0} />
-