Kulcare Docs
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.state

Example:

inventory.form.name.label
inventory.form.name.placeholder
inventory.form.name.error
{
  "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

On this page