DeveloperLocalization
Adding Translations to New Features
This guide walks through the process of adding translations when building new features.
Step-by-Step Guide
1. Ensure Module Federation Setup
For micro-frontends, ensure the localization package is properly shared:
// vite.config.ts
shared: {
'@kulcare/localization': {
singleton: true,
eager: true
}
}This ensures:
- Single instance of localization context across all apps
- Eager loading prevents timing issues
- Automatic context sharing without additional configuration
2. Identify Translation Needs
Before coding, list all user-facing text in your feature:
- Page titles
- Button labels
- Form fields and placeholders
- Error messages
- Success messages
- Table headers
- Navigation items
2. Choose the Right Namespace
Determine where your translations belong:
- common: Shared across multiple apps (buttons, general labels)
- auth: Authentication-related features
- cms: CMS app specific features
- growth: Growth app specific features
- [new-namespace]: Create new namespace for large features
3. Add Translation Keys
Add your translations to all language files:
// packages/localization/src/translations/en/cms.json
{
"inventory": {
"title": "Inventory Management",
"search": "Search items...",
"add": "Add Item",
"table": {
"name": "Item Name",
"quantity": "Quantity",
"price": "Price",
"actions": "Actions"
},
"form": {
"name": "Item Name",
"namePlaceholder": "Enter item name",
"quantity": "Quantity",
"quantityPlaceholder": "Enter quantity",
"save": "Save Item",
"cancel": "Cancel"
},
"messages": {
"saveSuccess": "Item saved successfully",
"saveError": "Failed to save item",
"deleteConfirm": "Are you sure you want to delete this item?"
}
}
}// packages/localization/src/translations/es/cms.json
{
"inventory": {
"title": "Gestión de Inventario",
"search": "Buscar artículos...",
"add": "Agregar Artículo",
"table": {
"name": "Nombre del Artículo",
"quantity": "Cantidad",
"price": "Precio",
"actions": "Acciones"
},
"form": {
"name": "Nombre del Artículo",
"namePlaceholder": "Ingrese el nombre del artículo",
"quantity": "Cantidad",
"quantityPlaceholder": "Ingrese la cantidad",
"save": "Guardar Artículo",
"cancel": "Cancelar"
},
"messages": {
"saveSuccess": "Artículo guardado exitosamente",
"saveError": "Error al guardar el artículo",
"deleteConfirm": "¿Está seguro de que desea eliminar este artículo?"
}
}
}// packages/localization/src/translations/hi/cms.json
{
"inventory": {
"title": "इन्वेंटरी प्रबंधन",
"search": "आइटम खोजें...",
"add": "आइटम जोड़ें",
"table": {
"name": "आइटम का नाम",
"quantity": "मात्रा",
"price": "मूल्य",
"actions": "क्रियाएं"
},
"form": {
"name": "आइटम का नाम",
"namePlaceholder": "आइटम का नाम दर्ज करें",
"quantity": "मात्रा",
"quantityPlaceholder": "मात्रा दर्ज करें",
"save": "आइटम सहेजें",
"cancel": "रद्द करें"
},
"messages": {
"saveSuccess": "आइटम सफलतापूर्वक सहेजा गया",
"saveError": "आइटम सहेजने में विफल",
"deleteConfirm": "क्या आप वाकई इस आइटम को हटाना चाहते हैं?"
}
}
}4. Use Translations in Your Component
import { PageHeader, Card, Table, Button, Input, message } from '@kulcare/ui-kit';
import { useCmsTranslation } from '@kulcare/localization';
export function InventoryPage() {
const { t } = useCmsTranslation();
// Note: No need to wrap with LocaleProvider in micro-frontends
// The context is automatically shared via module federation
const handleSave = async () => {
try {
// ... save logic
message.success(t('inventory.messages.saveSuccess'));
} catch (error) {
message.error(t('inventory.messages.saveError'));
}
};
return (
<div>
<PageHeader
title={t('inventory.title')}
extra={[
<Button type="primary" onClick={showAddModal}>
{t('inventory.add')}
</Button>
]}
/>
<Card>
<Input.Search
placeholder={t('inventory.search')}
onSearch={handleSearch}
/>
<Table
columns={[
{
title: t('inventory.table.name'),
dataIndex: 'name',
key: 'name',
},
{
title: t('inventory.table.quantity'),
dataIndex: 'quantity',
key: 'quantity',
},
{
title: t('inventory.table.price'),
dataIndex: 'price',
key: 'price',
},
{
title: t('inventory.table.actions'),
key: 'actions',
render: (_, record) => (
<Button onClick={() => handleDelete(record)}>
Delete
</Button>
),
},
]}
dataSource={data}
/>
</Card>
</div>
);
}5. Handle Dynamic Content
For content that changes based on data:
// Translation file
{
"status": {
"active": "Active",
"inactive": "Inactive",
"pending": "Pending"
}
}
// Component
const status = 'active';
return <Tag>{t(`status.${status}`)}</Tag>;6. Form Validation Messages
const { t } = useCmsTranslation();
const rules = [
{
required: true,
message: t("inventory.validation.nameRequired"),
},
{
min: 3,
message: t("inventory.validation.nameTooShort", { min: 3 }),
},
];Best Practices
1. Plan Translations Early
- List all text during feature planning
- Get translations before implementation
- Avoid hardcoding text
2. Use Consistent Key Patterns
feature.section.element.stateExample:
inventory.form.name.label
inventory.form.name.placeholder
inventory.form.name.error3. Group Related Translations
{
"inventory": {
"actions": {
"add": "Add",
"edit": "Edit",
"delete": "Delete",
"save": "Save",
"cancel": "Cancel"
}
}
}4. Handle Edge Cases
- Empty states
- Loading states
- Error states
- Success confirmations
5. Use Parameters for Dynamic Values
{
"welcome": "Welcome, {{name}}!",
"itemCount": "{{count}} item",
"itemCount_plural": "{{count}} items"
}Common Patterns
Page Structure
{
"featureName": {
"title": "Page Title",
"subtitle": "Page subtitle or description",
"nav": {
"overview": "Overview",
"details": "Details",
"settings": "Settings"
},
"actions": {
"create": "Create New",
"edit": "Edit",
"delete": "Delete",
"save": "Save Changes",
"cancel": "Cancel"
},
"table": {
"headers": {
"name": "Name",
"status": "Status",
"date": "Date",
"actions": "Actions"
}
},
"form": {
"fields": {
"name": {
"label": "Name",
"placeholder": "Enter name",
"help": "This will be displayed publicly"
}
},
"validation": {
"required": "This field is required",
"invalid": "Please enter a valid value"
}
},
"messages": {
"success": {
"created": "Successfully created",
"updated": "Successfully updated",
"deleted": "Successfully deleted"
},
"error": {
"create": "Failed to create",
"update": "Failed to update",
"delete": "Failed to delete",
"network": "Network error, please try again"
}
},
"empty": {
"title": "No items found",
"description": "Create your first item to get started"
}
}
}Testing Checklist
- All text is translated (no hardcoded strings)
- Translations work in all supported languages
- Text doesn't overflow UI elements
- Parameters are properly replaced
- Error messages are translated
- Empty states have translations
- Form placeholders are translated
- Tooltips and help text are translated
- Confirmation dialogs are translated
- Success/error notifications are translated
Need Help?
- Check existing translations for examples
- Use the same terminology as existing features
- Ask for translation reviews before merging
- Test thoroughly in all languages