Return

Support I18n with SEO Improvement

INFRASTRUCTURE

Situation

Needed to expand target audiences, stop expecting readers to be able to read both Korean and English.

Task

  • Configure i18n settings with next-intl properly
  • Utilize message system properly
  • Provide metadata aligned with locale, SEO optimization
  • Sitemap generation with language alternates
  • Add translation layer for string contents in database
  • Update db package and cache layer

Action

1. Configuration

  • Specified next-intl i18n configuration to support full prefix-url translations (navigation, request, routing)
  • Migrated all pages under [locale] directory
  • Enabled static parameters generation for locale prefix
  • Excluded static assets from i18n through proxy.ts

2. Message System

  • useTranslations for CSR pages/components, getTranslations for SSR pages/components.
  • Replaced custom formatting utilities with useFormatter/getFormatter, configured in request file.

3. Metadata i18n

  • For static pages with no DB access, consolidated metadata information with message json files.
  • For pages with DB access, separated the query by locale then generated metadata with localized data.
  • Found duplicate logic during the implementation, extracted the logic into separate utility file at utils/server/metadata.ts with server-only declaration.
  • Applied SEO best practices for localized metadata by providing canonical URLs with x-default support.

4. Sitemap Generation

  • next-sitemap required manual update even for dynamic routes generated from DB, and also required additional CI configurations using post-build script.
  • Replaced sitemap generation by next-sitemap with Next.js default sitemap.ts, which naturally integrated with updated i18n configuration.
  • Now the sitemap is generated when the /sitemap.xml is requested dynamically.

5. Translation Layer in Database

  • Added locale enum(ko, en).
  • Created junction table having localized content.
  • Updated database and prisma schema, also migrated contents.
  • Excluded title column, for coherent typography (Latin only)

6. Update Package and Cache layer

  • Adjusted queries to match with database schema.
  • Set default locale guard for both, DEFAULT_LOCALE in constants.ts file for package, routing.defaultLocale for cache layer. Maybe later, let db package to receive default locale from environment variables.
  • More granular cache control supported through posts-locale cache tags.

Result

The site now serves content in both Korean and English with proper SEO support. Adding new locales in the future only requires extending the locale enum and providing translated content.

One performance degradation noticed, that because of prefixed locale, the entire pages reloads when switching languages.