Skip to content

Internationalization ​

EOS Hub supports multiple languages through next-intl. The application ships with English and Slovak, and can be extended with additional languages.

Supported Languages ​

LanguageCodeStatus
EnglishenComplete
SlovakskComplete

How It Works ​

Locale Detection ​

The current locale is determined in the following order:

  1. Cookie -- A NEXT_LOCALE cookie stores the user's language preference.
  2. Browser preference -- If no cookie is set, the browser's Accept-Language header is used.
  3. Default -- Falls back to en if no match is found.

Switching Languages ​

Users can switch languages using the language selector in the application header. This sets the NEXT_LOCALE cookie and reloads the page with the new locale.

Translation File Structure ​

Translation files are organized by locale and namespace in the messages/ directory:

messages/
├── en/
│   ├── common.json
│   ├── auth.json
│   ├── dashboard.json
│   ├── meetings.json
│   ├── scorecard.json
│   ├── rocks.json
│   ├── issues.json
│   ├── todos.json
│   ├── vto.json
│   ├── accountability.json
│   ├── people-analyzer.json
│   ├── admin.json
│   └── ...
└── sk/
    ├── common.json
    ├── auth.json
    ├── dashboard.json
    └── ...

Each JSON file contains a flat or nested object of translation keys and values:

json
{
  "title": "Scorecard",
  "addMeasurable": "Add Measurable",
  "weekOf": "Week of {date}",
  "goal": {
    "above": "Above {value}",
    "below": "Below {value}",
    "equal": "Equal to {value}"
  }
}

Adding a New Language ​

To add a new language (for example, Czech):

1. Create Translation Files ​

Create a new directory messages/cs/ and copy all files from messages/en/:

bash
cp -r messages/en messages/cs

Translate all values in the copied files.

2. Update next-intl Configuration ​

Add the new locale to the i18n.ts configuration:

typescript
export const locales = ['en', 'sk', 'cs'] as const;
export const defaultLocale = 'en';

3. Update the Middleware ​

Ensure the middleware includes the new locale in its matcher:

typescript
export default createMiddleware({
  locales: ['en', 'sk', 'cs'],
  defaultLocale: 'en',
});

4. Add to VitePress Documentation (Optional) ​

If you want documentation in the new language, add a new locale entry in .vitepress/config.ts:

typescript
locales: {
  en: { label: 'English', lang: 'en', link: '/en/' },
  sk: { label: 'Slovencina', lang: 'sk', link: '/sk/' },
  cs: { label: 'Cestina', lang: 'cs', link: '/cs/' },
},

Using Translations in Code ​

In Server Components ​

tsx
import { useTranslations } from 'next-intl';

export default function ScorecardPage() {
  const t = useTranslations('scorecard');

  return <h1>{t('title')}</h1>;
}

In Client Components ​

tsx
'use client';

import { useTranslations } from 'next-intl';

export default function AddButton() {
  const t = useTranslations('scorecard');

  return <button>{t('addMeasurable')}</button>;
}

With Variables ​

tsx
// Translation: "weekOf": "Week of {date}"
t('weekOf', { date: '2026-01-05' });
// Output: "Week of 2026-01-05"

With Plurals ​

json
{
  "rockCount": "You have {count, plural, one {# rock} other {# rocks}}"
}
tsx
t('rockCount', { count: 3 });
// Output: "You have 3 rocks"

TIP

Always use translation keys instead of hardcoded strings, even if you are only supporting one language. This makes future localization much easier.

Best Practices ​

  • Namespace by feature -- Keep translations organized by feature area (scorecard, rocks, meetings).
  • Use descriptive keys -- Prefer addMeasurable over btn1.
  • Include context -- When a string might be ambiguous, add a comment or use a more specific key name.
  • Handle plurals -- Use ICU message format for quantities.
  • Test all locales -- After adding translations, verify the layout does not break with longer text (common with German or Slovak).

Next Steps ​

Built with VitePress