Codapult
FeaturesPricingAPIHelpChangelog
Codapult

Ship Your SaaS Faster

Product

  • Features
  • Pricing
  • Plugins
  • API Reference
  • Help Center
  • Feature Requests
  • Changelog

Company

  • Contact
  • GitHub

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Codapult. All rights reserved.

All articles

Getting Started

  • Introduction
  • Quick Start
  • Project Structure

Configuration

  • Environment Variables
  • App Configuration

Authentication

  • Authentication

Database

  • Database

Teams

  • Teams & Organizations

Payments

  • Payments & Billing

Api

  • API Layer

Ai

  • AI Features

Email

  • Email

Infrastructure

  • Infrastructure

Ui

  • UI & Theming

I18n

  • Internationalization

Content Management

  • Content Management

Admin

  • Admin Panel

Security

  • Security

Monitoring

  • Analytics & Monitoring

Modules

  • Module Architecture

Plugins

  • Plugin System

Deployment

  • Deployment
  • Troubleshooting

Upgrading

  • Upgrading Codapult

Developer Tools

  • MCP Server
  • Testing
I18n

Internationalization

Add languages, translate UI text, and localize blog content with next-intl.

Codapult uses next-intl with cookie-based locale detection. Two locales ship out of the box — English (en) and Russian (ru) — and adding more takes just a few minutes.

How It Works

PieceLocation
Translation filesmessages/en.json, messages/ru.json
Locale configsrc/i18n/request.ts
Locale cookielocale (set by the LocaleSwitch component)

The active locale is read from the locale cookie on every request. If the cookie is missing or invalid, Codapult falls back to en.


Using Translations

Client Components

'use client';

import { useTranslations } from 'next-intl';

export function Greeting() {
  const t = useTranslations('dashboard');
  return <h1>{t('welcome')}</h1>;
}

Server Components

import { getTranslations } from 'next-intl/server';

export default async function Page() {
  const t = await getTranslations('dashboard');
  return <h1>{t('welcome')}</h1>;
}

Message File Structure

Messages are organized by namespace. Use nested keys for logical grouping:

{
  "dashboard": {
    "welcome": "Welcome back",
    "settings": "Settings",
    "members": "{count, plural, one {# member} other {# members}}"
  },
  "auth": {
    "signIn": "Sign in",
    "signUp": "Create account"
  }
}

Pluralization follows the ICU MessageFormat syntax — {count, plural, one {…} other {…}}.


Adding a New Locale

  1. Create the message file — copy messages/en.json and translate:
cp messages/en.json messages/de.json
  1. Register the locale in src/i18n/request.ts:
export const locales = ['en', 'ru', 'de'] as const;
  1. Done. The LocaleSwitch component and cookie logic pick up the new locale automatically.

Locale Switcher

The LocaleSwitch component renders a dropdown that sets the locale cookie and reloads the page. It is included in the marketing header and the blog layout.


Blog Localization

Blog posts use a filename convention for translations:

FileLocale
content/blog/my-post.mdxDefault (en)
content/blog/my-post.ru.mdxRussian
content/blog/my-post.de.mdxGerman

The blog utilities in src/lib/blog/ automatically discover available locales per post and populate the availableLocales field in metadata, so the UI can show a language switcher on each article.

If a post is not translated for the current locale, the reader sees the default-locale version.


Removing the i18n Module

If your product targets a single language, you can remove internationalization entirely via the setup wizard:

npx @codapult/cli setup

The wizard strips next-intl, the messages/ directory, the LocaleSwitch component, and all useTranslations / getTranslations calls — leaving plain strings in their place.

UI & ThemingContent Management