Skip to main content

Overview

Kuest includes built-in support for multiple languages using next-intl. The platform supports 6 languages out of the box and includes automatic translation for event titles and categories powered by AI.

Supported Languages

Kuest supports the following languages:
CodeLanguageNative NameStatus
enEnglishEnglishDefault
deGermanDeutschSupported
esSpanishSpanishSupported
ptPortuguesePortuguêsSupported
frFrenchFrenchSupported
zhChinese中文Supported
English (en) is the default locale and cannot be disabled.

Locale Configuration

Enabling/Disabling Locales

  1. Navigate to AdminLocales
  2. Select which languages to enable
  3. English is always enabled (default)
  4. Click Save settings
Disabled locales will not appear in language selectors and users cannot access content in those languages.

Routing Configuration

Locale routing is configured in src/i18n/routing.ts:
import { defineRouting } from 'next-intl/routing'
import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from '@/i18n/locales'

export const routing = defineRouting({
  locales: SUPPORTED_LOCALES,
  defaultLocale: DEFAULT_LOCALE,
  localePrefix: 'as-needed',
  localeDetection: false,
})
Configuration:
  • localePrefix: 'as-needed' - Default locale (en) has no prefix, others do
  • localeDetection: false - Manual locale selection only
URL Structure:
/                  → English (default)
/de                → German
/es                → Spanish  
/de/event/my-event → German event page

Translation Files

Translations are stored in JSON files under src/i18n/messages/:
src/i18n/messages/
├── en.json    (English - source)
├── de.json    (German)
├── es.json    (Spanish)
├── pt.json    (Portuguese)
├── fr.json    (French)
└── zh.json    (Chinese)

Translation File Format

Each translation file uses key-value pairs:
src/i18n/messages/en.json
{
  "6it6mU": "Leaderboard",
  "XhQrGb": "APIs",
  "5ObBlW": "Dark Mode",
  "isGKnz": "Documentation",
  "EnCOBJ": "Buy",
  "9AgXoz": "Sell"
}
Keys are short hashes generated by next-intl during message extraction.

Using Translations in Code

'use client'

import { useTranslations } from 'next-intl'

export function BuyButton() {
  const t = useTranslations()
  
  return (
    <button>
      {t('EnCOBJ')} {/* "Buy" or "Kaufen" */}
    </button>
  )
}

Adding New Languages

To add a new language to Kuest:
1

Update locale constants

Edit src/i18n/locales.ts:
export const SUPPORTED_LOCALES = [
  'en', 'de', 'es', 'pt', 'fr', 'zh', 'ja' // Add 'ja' for Japanese
] as const

export const LOCALE_LABELS: Record<SupportedLocale, string> = {
  en: 'English',
  // ... other languages
  ja: '日本語', // Add Japanese label
}

export const LOOP_LABELS: Record<SupportedLocale, string> = {
  en: 'Language',
  // ... other languages  
  ja: '言語', // Add Japanese "Language" translation
}
2

Create translation file

Create src/i18n/messages/ja.json:
{
  "6it6mU": "リーダーボード",
  "XhQrGb": "API",
  "5ObBlW": "ダークモード"
  // ... translate all keys from en.json
}
All keys from en.json must be present in the new translation file. Missing keys will fall back to English.
3

Enable in admin panel

  1. Go to AdminLocales
  2. The new language should appear in the list
  3. Check it to enable
  4. Save settings
4

Test the new locale

  • Visit /ja to test Japanese version
  • Check language selector includes Japanese
  • Verify all UI text is translated
  • Test with missing translations (should fall back to English)

Automatic Translations

Kuest can automatically translate event titles and category names using AI.

Configuration

  1. Navigate to AdminLocales
  2. Toggle Automatic translations of event titles and categories
  3. Ensure OpenRouter is configured in AdminGeneral
  4. Click Save settings
Automatic translations require an OpenRouter API key and model selection. Configure this in AdminGeneralOpenRouter integration.

Translation Requirements

OpenRouter Setup RequiredAutomatic translations require:
  1. OpenRouter API key (get from openrouter.ai)
  2. Selected AI model with translation capability
  3. Sufficient API credits
Configure in AdminGeneralOpenRouter integration

Locale Settings Code

Locale configuration is managed in src/i18n/locale-settings.ts:
// Load enabled locales from database
export async function loadEnabledLocales(): Promise<SupportedLocale[]>

// Load automatic translation setting
export async function loadAutomaticTranslationsEnabled(): Promise<boolean>

// Serialize locales for storage
export function serializeEnabledLocales(locales: SupportedLocale[]): string

// Parse and normalize locale list
export function parseEnabledLocales(value?: string | null): SupportedLocale[]

// Ensure locales include default
export function ensureEnabledLocales(locales: string[]): SupportedLocale[]

Language Selector

Users can switch languages via the language selector in the UI: Location:
  • Navigation menu (desktop)
  • Mobile menu
  • Footer (some layouts)
Behavior:
  • Shows only enabled locales
  • Preserves current page when switching
  • Updates URL with locale prefix (except English)
  • Stores preference in browser (optional)

Translation Workflow

Recommended workflow for managing translations:
1

Update English source

Add or modify text in English components:
const t = useTranslations()
return <button>{t('myNewKey')}</button>
2

Extract messages

Run message extraction (if using next-intl extraction):
npm run extract-messages
This generates message keys in en.json
3

Translate to other languages

Copy the new keys to other locale files and translate:
// de.json
{
  "myNewKey": "Meine Übersetzung"
}
4

Test translations

  • Switch to each locale in the UI
  • Verify text displays correctly
  • Check for layout issues with longer text
  • Test with missing translations (falls back to English)
5

Deploy

Commit translation files and deploy:
git add src/i18n/messages/
git commit -m "Add translations for new feature"
git push

Best Practices

  • Use the auto-generated hash keys from next-intl
  • Keep English as the source of truth
  • Don’t hardcode text in components
  • Use variables for dynamic content: {name}, {count}
  • Group related translations with namespaces if needed
  • Design UI to accommodate longer translations (German, French ~30% longer)
  • Test layouts with all locales
  • Use truncation or wrapping for long text
  • Avoid fixed-width containers
  • Test button labels in all languages
  • Use locale-appropriate date/time formats
  • Format numbers and currency correctly per locale
  • Consider right-to-left (RTL) support if adding Arabic/Hebrew
  • Use culturally appropriate examples and imagery
  • Avoid idioms that don’t translate well
  • Have native speakers review translations
  • Test automatic translations for accuracy
  • Monitor user feedback per locale
  • Keep a glossary of key terms
  • Update translations when features change

Troubleshooting

Problem: Some text appears in English in other localesSolution:
  • Check if the key exists in the locale file
  • Verify the translation file is valid JSON
  • Ensure the file is in src/i18n/messages/
  • Restart the dev server
  • Check browser console for warnings
Problem: Events not being translated automaticallySolution:
  • Verify OpenRouter API key is configured
  • Check that a model is selected
  • Ensure automatic translations are enabled
  • Check API credits on OpenRouter
  • Look for errors in server logs
  • Verify network connectivity to OpenRouter
Problem: Added locale doesn’t appear in language menuSolution:
  • Check locale is in SUPPORTED_LOCALES array
  • Verify locale is enabled in admin panel
  • Ensure translation file exists
  • Clear cache and restart server
  • Check for typos in locale code
Problem: Page loads in wrong languageSolution:
  • Check URL path (should include locale prefix)
  • Verify localeDetection: false in routing config
  • Clear browser cache and cookies
  • Check for middleware redirect issues
  • Ensure locale is in enabled locales list

Locale Data Reference

Locale Constants

src/i18n/locales.ts
export const SUPPORTED_LOCALES = ['en', 'de', 'es', 'pt', 'fr', 'zh']
export const DEFAULT_LOCALE: SupportedLocale = 'en'

export const LOCALE_LABELS: Record<SupportedLocale, string> = {
  en: 'English',
  de: 'Deutsch',
  es: 'Spanish',
  pt: 'Português',
  fr: 'French',
  zh: '中文',
}

export const LOOP_LABELS: Record<SupportedLocale, string> = {
  en: 'Language',
  de: 'Sprache',
  es: 'Idioma',
  pt: 'Língua',
  fr: 'Langue',
  zh: '语言',
}

Settings Keys

GroupKeyDescriptionFormat
i18nenabled_localesList of enabled languagesJSON array: ["en","de"]
i18nautomatic_translations_enabledAuto-translate eventsString: "true" or "false"

Admin Panel

Access locale configuration interface

OpenRouter Setup

Configure AI translations

Branding

Localize site name and description

Theme Settings

UI customization for different locales

Build docs developers (and LLMs) love