Skip to content

Translation Module Documentation

Overview

The Translation module manages internationalization (i18n) strings for the application. It stores translation keys and their values, organized by language code and optional sections for grouping.

Data Model

Translation Entity

File: backend/src/modules/translation/models/translation.ts

Field Type Required Default Description
id string Yes Auto-generated Primary key
language_code string No "ar" Language code (e.g., "ar", "en")
key string Yes - Translation key (unique per language)
value string Yes - Translated text value
section string No null Optional section for grouping keys

Service Methods

TranslationModuleService

File: backend/src/modules/translation/service.ts

The service extends MedusaService which automatically provides standard CRUD methods: - listTranslations(filters, options) - List translations with optional filters - createTranslations(data) - Create a new translation - updateTranslations(id, data) - Update an existing translation - deleteTranslation(id) - Delete a translation

Custom Methods

getAllTranslations()

Returns all translations across all languages.

async getAllTranslations(): Promise<Translation[]>

Returns: Array of all translation records.

Example:

const translations = await translationModuleService.getAllTranslations()
// Returns: [
//   { id: "1", language_code: "ar", key: "welcome", value: "مرحبا", section: "common" },
//   { id: "2", language_code: "ar", key: "cart", value: "السلة", section: "common" }
// ]

getTranslationsByLanguage(languageCode)

Returns all translations for a specific language.

async getTranslationsByLanguage(languageCode: string): Promise<Translation[]>

Parameters: - languageCode - The language code (e.g., "ar", "en")

Returns: Array of translations for the specified language.

Example:

const arabicTranslations = await translationModuleService.getTranslationsByLanguage("ar")

upsertTranslation(data)

Creates or updates a translation.

async upsertTranslation(data: {
  language_code?: string
  key: string
  value: string
  section?: string | null
}): Promise<Translation>

Parameters: - language_code - Language code (defaults to "ar") - key - Translation key - value - Translated text - section - Optional section for grouping

Returns: The created or updated translation.

Example:

const translation = await translationModuleService.upsertTranslation({
  language_code: "ar",
  key: "checkout",
  value: "إتمام الطلب",
  section: "checkout",
})

getAllAsBundle()

Returns all translations in i18next-compatible bundle format.

async getAllAsBundle(): Promise<{ [languageCode: string]: { translation: Record<string, string> } }>

Returns: Object with language codes as keys, each containing a translation object with key-value pairs.

Example:

const bundle = await translationModuleService.getAllAsBundle()
// Returns: {
//   ar: {
//     translation: {
//       welcome: "مرحبا",
//       cart: "السلة",
//       checkout: "إتمام الطلب"
//     }
//   }
// }

This format is directly compatible with i18next frontend libraries.

Usage Examples

Getting Arabic Translations for Storefront

const bundle = await translationModuleService.getAllAsBundle()
// Pass to i18next init:
i18next.init({
  resources: bundle,
  lng: "ar",
})

Creating a New Translation

await translationModuleService.upsertTranslation({
  language_code: "ar",
  key: "add_to_cart",
  value: "أضف إلى السلة",
  section: "product",
})

Updating an Existing Translation

await translationModuleService.upsertTranslation({
  language_code: "ar",
  key: "welcome",
  value: "أهلاً وسهلاً",
  section: "common",
})

Getting Translations by Section

const allTranslations = await translationModuleService.getAllTranslations()
const commonTranslations = allTranslations.filter(t => t.section === "common")

i18next Bundle Format

The getAllAsBundle() method returns translations in the exact format expected by i18next:

{
  "ar": {
    "translation": {
      "welcome": "مرحبا",
      "cart": "السلة",
      "checkout": "إتمام الطلب",
      "add_to_cart": "أضف إلى السلة"
    }
  }
}

This allows direct integration with React i18next or other i18next-based libraries:

import i18next from 'i18next'

// Fetch from API
const response = await fetch('/store/translations')
const bundle = await response.json()

// Initialize i18next
i18next.init({
  resources: bundle,
  lng: 'ar',
  fallbackLng: 'ar',
})

// Use in components
const t = i18next.t
console.log(t('welcome')) // "مرحبا"

Module Registration

The module is registered in medusa-config.ts:

modules: [
  {
    resolve: "./src/modules/translation",
  },
]

Migration

Generate and run migrations:

npx medusa db:generate translation
npx medusa db:migrate

This creates the translation table in PostgreSQL with all defined columns.

API Routes

The module is exposed via custom API routes: - GET /store/translations - Returns i18next bundle for ar locale - GET /admin/translations - List all translations (admin) - POST /admin/translations - Create translation (admin) - PATCH /admin/translations/:id - Update translation (admin) - DELETE /admin/translations/:id - Delete translation (admin)

See STORE_ENDPOINTS.md and ADMIN_ENDPOINTS.md for API details.

Adding New Languages

To add support for additional languages:

  1. Create translations with the new language_code:

    await translationModuleService.upsertTranslation({
      language_code: "en",
      key: "welcome",
      value: "Welcome",
      section: "common",
    })
    

  2. Update getAllAsBundle() to include the new language if needed

  3. Update the storefront to allow language switching

Translation Key Naming Convention

  • Use snake_case for keys (e.g., add_to_cart, free_delivery)
  • Group related keys using the section field
  • Use descriptive, context-aware names
  • Avoid special characters in keys

Recommended sections: - common - General UI elements - product - Product-related text - checkout - Checkout flow text - account - Account management text - errors - Error messages