hensei-web/app/[locale]/layout.tsx
Justin Edmund 3d67622353
Fix i18n migration to next-intl (#430)
## Summary
- Fixed translation key format compatibility with next-intl
- Fixed pluralization format from i18next to next-intl format
- Fixed dynamic translation key error handling
- Updated server components to match API response structure
- Fixed useSearchParams import location

## Changes
- Changed pluralization from `{{count}} items` to `{count} items` format
- Added proper error handling for missing translation keys
- Fixed import paths for next-intl hooks
- Fixed PartyPageClient trying to set non-existent appState.parties

## Test plan
- [x] Verified translations render correctly
- [x] Tested pluralization works with different counts
- [x] Confirmed no console errors about missing translations
- [x] Tested party page functionality

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-03 16:25:59 -07:00

80 lines
No EOL
2.2 KiB
TypeScript

import { Metadata, Viewport } from 'next'
import localFont from 'next/font/local'
import { NextIntlClientProvider } from 'next-intl'
import { getMessages } from 'next-intl/server'
import { Viewport as ToastViewport } from '@radix-ui/react-toast'
import { locales } from '../../i18n.config'
import '../../styles/globals.scss'
// Components
import Providers from '../components/Providers'
import Header from '../components/Header'
import UpdateToastClient from '../components/UpdateToastClient'
import VersionHydrator from '../components/VersionHydrator'
// Generate static params for all locales
export function generateStaticParams() {
return locales.map((locale) => ({ locale }))
}
// Metadata
export const metadata: Metadata = {
title: 'granblue.team',
description: 'Create, save, and share Granblue Fantasy party compositions',
}
// Viewport configuration (Next.js 13+ requires separate export)
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
viewportFit: 'cover',
}
// Font
const goalking = localFont({
src: '../../pages/fonts/gk-variable.woff2',
fallback: ['system-ui', 'inter', 'helvetica neue', 'sans-serif'],
variable: '--font-goalking',
})
export default async function LocaleLayout({
children,
params: { locale }
}: {
children: React.ReactNode
params: { locale: string }
}) {
// Load messages for the locale
const messages = await getMessages()
// Fetch version data on the server
let version = null
try {
const baseUrl = process.env.NEXT_PUBLIC_URL || 'http://localhost:1234'
const res = await fetch(`${baseUrl}/api/version`, {
cache: 'no-store'
})
if (res.ok) {
version = await res.json()
}
} catch (error) {
console.error('Failed to fetch version data:', error)
}
return (
<html lang={locale} className={goalking.variable}>
<body className={goalking.className}>
<NextIntlClientProvider messages={messages}>
<Providers>
<Header />
<VersionHydrator version={version} />
<UpdateToastClient initialVersion={version} />
<main>{children}</main>
<ToastViewport className="ToastViewport" />
</Providers>
</NextIntlClientProvider>
</body>
</html>
)
}