Eight locales and no server: internationalizing a static Next.js site
Last month I rebuilt a small website I run. Static export, eight languages, hosted on Cloudflare Pages — free, fast, and nothing to patch. The catch: static export and i18n don't fight each other, but they change how you think about a few things. Here's what I ended up with and the parts that weren't obvious at first. The stack Next.js 15 with next-intl 4, React 18, all of it prerendered with…
The author recently rebuilt their personal website using static export, multiple languages, and Cloudflare Pages, which proved to be a free, fast, and maintenance-free solution. However, integrating internationalization (i18n) into the setup proved to be non-trivial, as static export and i18n do not naturally work together, but require some adjustments. This article details the process and challenges encountered.
The development stack consists of Next.js 15 with next-intl 4, React 18, and all components prerendered with the output: export flag. There are no middleware or server functions involved, as the entire site is converted into static HTML files at build time.
Next.config.js is configured with output: export for static export, and images.unoptimized set to true to prevent image processing when there's no server.
The locale is determined from the URL itself, rather than from request headers. Routing is defined in src/i18n/routing.ts, specifying the locales, default locale, and locale prefix. The mode: always option keeps the primary language in the URL path while other locales are prefixed.
The locale data is passed to next-intl via getRequestConfig in src/i18n/request.ts. It determines the locale from the request and falls back to the default locale if none is provided or not supported.
Messages are stored as JSON files under src/messages/, loaded statically at build time. This avoids runtime bundling issues.
generateStaticParams in app/[locale]/layout.tsx ensures every language gets its own folder of static HTML files during build time. If this is missing, only the default locale is generated.
Finally, the hreflang attribute helps search engines understand the relationship between translations. This is crucial for SEO when dealing with multiple language versions of a site.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.