| name | translations |
| description | Work with internationalization using next-intl and PO files. Use when handling translations, i18n, PO files, getExtracted, useExtracted, translating content, or when the user needs to add or modify translations. |
Internationalization (i18n) Workflow
Overview
This project uses next-intl with PO file extraction. Translations are extracted from the codebase using pnpm build.
Key Functions
- Server Components: Use
getExtracted(no locale needed) - Client Components: Use
useExtracted - Metadata/Server Actions: Use
getExtractedwith locale parameter
Critical Rules
1. No Dynamic Values in Translation Keys
IMPORTANT: The t function from getExtracted/useExtracted does NOT support dynamic values.
// BAD: Dynamic key - will NOT work
const category = getCategory();
t(category); // Error!
t(MYLABELS[category]);
// GOOD: String literals only
t("Arts courses");
t("Business courses");
t("Technology courses");
2. String Interpolation IS Supported
You CAN use string interpolation for dynamic values within translations:
// GOOD: Interpolation with static key
t("Explore all {category} courses", { category: "arts" });
t("Welcome, {name}!", { name: user.name });
t("{count} items remaining", { count: 5 });
3. Don't Pass t Function Around
You can't pass the t function to other functions or components:
// BAD: Passing t function
function myFunction(t, label) {
return t(label);
}
myFunction(t, "Some label");
// GOOD: Call t directly
function myFunction(translatedLabel: string) {
return translatedLabel;
}
myFunction(t("Some label"));
4. Locale Parameter Rules
// Server Component - no locale needed
const t = await getExtracted();
t("Hello");
// generateMetadata - needs locale
export async function generateMetadata({ params }) {
const { locale } = await params;
const t = await getExtracted(locale);
return { title: t("Page Title") };
}
Workflow for Adding Translations
Add translation call in code:
const t = await getExtracted(); return <h1>{t("New page title")}</h1>;Run build to extract translations:
pnpm buildThis updates PO files with new strings.
Translate empty strings in PO files:
- Find PO files in
apps/{app}/src/i18n/locales/ - Fill in empty
msgstrvalues
- Find PO files in
Check for missing translations:
pnpm i18n:check
Handling MISSING_TRANSLATION Errors
When you see a MISSING_TRANSLATION error:
- Go to the relevant PO file
- Find the empty
msgstrfor the string - Add the translation
# Before
msgid "Welcome to Zoonk"
msgstr ""
# After
msgid "Welcome to Zoonk"
msgstr "Bem-vindo ao Zoonk"
Never create new translations in PO files manually - only extract them using pnpm build. If you're on an environment where you can't run pnpm build, just ignore this i18n step.
Updating app-error.ts Files
When updating app-error.ts files:
- Add the new error code
- Update
error-messages.tsto include the new error code - Run
pnpm buildto update PO files
Common Patterns
Conditional Text
// Use separate translation keys
const status = isActive ? t("Active") : t("Inactive");
Pluralization
// Use interpolation with count
t("{count} item", { count: 1 }); // "1 item"
t("{count} items", { count: 5 }); // "5 items"
Rich Text (with components)
t.rich("Read our {link}", {
link: (chunks) => <Link href="/terms">{chunks}</Link>,
});