Translations & Locales
Marketlum ships with English (en) and Polish (pl) translations bundled in @marketlum/ui/messages. The locale is read from a locale cookie on each request. You can override individual strings, add a new language, or change the default.
How locales are loaded
The scaffold's apps/web/src/i18n/request.ts resolves the active locale and loads its messages from @marketlum/ui:
const messagesByLocale = {
en: () => import('@marketlum/ui/messages/en'),
pl: () => import('@marketlum/ui/messages/pl'),
};
To customize, edit this file directly — it lives in your project.
Override specific strings
Create a local override file and merge it on top of the upstream messages.
import { getRequestConfig } from 'next-intl/server';
import { cookies } from 'next/headers';
import { locales, defaultLocale, type Locale } from '@marketlum/ui';
import enOverrides from '../messages/en.overrides.json';
const messagesByLocale = {
en: async () => {
const base = (await import('@marketlum/ui/messages/en')).default;
return { default: { ...base, ...enOverrides } };
},
pl: () => import('@marketlum/ui/messages/pl'),
} satisfies Record<Locale, () => Promise<{ default: Record<string, unknown> }>>;
export default getRequestConfig(async () => {
const cookieStore = await cookies();
const raw = cookieStore.get('locale')?.value;
const locale: Locale = locales.includes(raw as Locale) ? (raw as Locale) : defaultLocale;
return {
locale,
messages: (await messagesByLocale[locale]()).default,
};
});
Put overrides in apps/web/src/messages/en.overrides.json:
{
"Dashboard.title": "Acme Control Center",
"Common.welcome": "Welcome to Acme"
}
Top-level keys merge; if you need to override a nested key, override the full nested object.
Add a new language
- Create
apps/web/src/messages/de.json(start by copyingnode_modules/@marketlum/ui/messages/en.json). - Register it in
request.ts:
const customLocales = ['en', 'pl', 'de'] as const;
type CustomLocale = (typeof customLocales)[number];
const messagesByLocale = {
en: () => import('@marketlum/ui/messages/en'),
pl: () => import('@marketlum/ui/messages/pl'),
de: () => import('../messages/de.json'),
} satisfies Record<CustomLocale, () => Promise<{ default: Record<string, unknown> }>>;
- Use your local
customLocalesarray in place of the importedlocaleswhen validating the cookie.
The locale switcher in the admin UI reads from the locales export of @marketlum/ui; to surface a new language in the dropdown, render your own switcher using customLocales.
Change the default locale
The default is en. To change it, validate the cookie against your own default:
const myDefaultLocale = 'pl';
const locale = locales.includes(raw as Locale) ? (raw as Locale) : myDefaultLocale;
Translatable domain content
User-facing entity fields (names, descriptions) are not in the i18n message bundle. They are stored per-Locale row in the database and managed through the Locales admin page. See Taxonomies & Archetypes for how this fits with the rest of the domain model.