DEV Community

Alex Chen
Alex Chen

Posted on

Building a Multi-Language Pokémon Fansite with Next.js 16 (en/ja/ko/zh)

I recently launched Pokopia Habitats — a complete game guide for Pokémon Pokopia. Sharing the build because the multi-language static-site setup had a few non-obvious wins worth documenting.

Stack

  • Next.js 16 with App Router
  • Static HTML Export (output: "export") — full SSG, no server
  • Cloudflare Pages — free tier, auto-build on GitHub push
  • Tailwind 4 + TypeScript
  • 4 locales: en (default), ja, ko, zh

Scale

  • 212 habitats
  • 303 Pokémon
  • 282 materials
  • 105 crafting + 20 cooking recipes
  • 33 guides
  • ~11.6K URLs in sitemap

Multi-language without i18n routing complexity

Most Next.js i18n tutorials push you toward next-i18next or middleware-based locale detection. For a static export, both are overkill. What worked:

  1. Locale dicts in src/dictionaries/{en,ja,ko,zh}.json
  2. Route each locale as a separate [locale] segment
  3. generateStaticParams emits all (habitat × locale) combos at build time
  4. HtmlLangUpdater client component sets on the fly

Every page gets statically rendered per locale, which Cloudflare CDNs love. Build time: ~4 min for ~11K pages.

Asset trick: external → own CDN

The Pokémon company assets (serebii.net area images, pokemon.com background images) were hot-linked initially. Ran into browser cache issues + the obvious "please don't hot-link" etiquette. Solution: a small Cloudflare R2 worker that fetches on first request, caches, and serves from our own CDN.

What's the site for?

Pokemon Pokopia has a ton of hidden data — habitat unlock conditions, material drop rates, cross-language item names — scattered across 7+ fan sites. Pokopia Habitats consolidates it and is the only site covering all four languages (en/ja/ko/zh) with cross-referenced item names.

If you're playing on the Japanese or Korean version, the Pokédex at pokopiahabitats.com/pokemon shows names in every language — useful when a Japanese wiki is your only reference.

What I'd do differently

  • Pre-build a subset of pages first, lazy-generate the long tail via ISR-at-build-time
  • Use next/image unoptimized mode earlier — SSG + remote images is a classic footgun
  • Dict keys should be typed (currently Record) — typed-i18n next time

Happy to answer questions about the build if anyone is doing similar fansite work.

Top comments (0)