Aller au contenu principal

Translation System Documentation

Overview

The translation system has been refactored to be centralized, reusable, and easy to understand. It can be used for any module that needs multi-language support (News, Events, Pages, etc.).

Architecture

1. useTranslationManager Hook (app/hooks/useTranslationManager.hook.ts)

Centralized hook that manages all translation logic:

Features:

  • Reads lang and ref query parameters for creating translations
  • Fetches French reference document when editing a translation
  • Fetches all translations when editing French document
  • Manages translation state (IDs, slugs, data)
  • Provides helper functions for building payloads and URLs

Usage:

const translation = useTranslationManager({
api: News, // Your API service
moduleId: "module-id",
moduleSlug: "actus",
documentData: newsData, // Current document (when editing)
isNew: isNewNews,
});

// Access state
translation.currentLanguage // "fr" | "en" | "es"
translation.referenceId // French document ID
translation.translationSlugs // { en: "slug-en", es: "slug-es" }
translation.frenchSlug // French document slug

// Check if creating translation
if (translation.isCreatingTranslation) {
// Use langParam and refParam
}

// Build URLs
translation.getEditUrl(slug) // "/modules/actus/modifier/slug"
translation.getCreateUrl("en", refId) // "/modules/actus/créer?lang=en&ref=refId"

2. TranslationTabs Component (app/components/molecules/translationTabs.molecule.tsx)

Reusable component that displays language flags with navigation:

Features:

  • Shows all active language flags
  • Existing translations → link to edit
  • Missing translations → link to create
  • French flag → link back to original when editing translation
  • Current language → highlighted, no link

Usage:

<TranslationTabs
currentLanguage="fr"
moduleSlug="actus"
frenchSlug="my-news-slug"
translationSlugs={{ en: "my-news-en", es: "my-news-es" }}
referenceId="french-doc-id"
isNew={false}
>
<YourFormContent />
</TranslationTabs>

3. LanguageTabs Component (app/components/molecules/languageTabs.molecule.tsx)

Low-level component that renders the flag UI:

Features:

  • Vertical flag layout with connecting lines
  • Supports both Link (navigation) and button (callback) modes
  • Highlights active language
  • Accessible (aria labels, keyboard navigation)

How It Works

Creating a New Translation

  1. User clicks on a missing language flag (e.g., 🇪🇸)
  2. Navigate to: /modules/actus/créer?lang=es&ref=68ff3575e2e59b58c9788b6f
  3. useTranslationManager reads query params:
    • langParam = "es"
    • refParam = "68ff3575e2e59b58c9788b6f" (French document ID)
  4. Form is initialized with:
    translation: {
    lang: "es",
    ref_item: "68ff3575e2e59b58c9788b6f"
    }
  5. On submit, translation is created with correct language and reference

Editing an Existing Translation

  1. User clicks on existing language flag (e.g., 🇬🇧)
  2. Navigate to: /modules/actus/modifier/my-news-en
  3. Document is loaded by slug
  4. useTranslationManager detects:
    • currentLanguage = "en" (from documentData.translation.lang)
    • referenceId = French document ID (from documentData.translation.ref_item)
  5. French document is fetched to get frenchSlug
  6. All sibling translations are fetched
  7. Flags are displayed with correct navigation URLs

Viewing All Translations (French Document)

  1. User edits French document: /modules/actus/modifier/my-news-fr
  2. useTranslationManager detects:
    • currentLanguage = "fr"
    • referenceId = current document ID
  3. All translations are fetched (search by translation.ref_item)
  4. Flags are displayed:
    • 🇫🇷 FR (active, no link)
    • 🇬🇧 EN (link to edit if exists, or link to create)
    • 🇪🇸 ES (link to edit if exists, or link to create)

Integration Guide

For a New Module

  1. Create your API service with required methods:

    class MyModuleAPI extends BaseAPI {
    async getById(id: string) { ... }
    async search(params: any) { ... }
    }
  2. Use the hook in your form component:

    const translation = useTranslationManager({
    api: MyModuleAPI,
    moduleId: moduleId!,
    moduleSlug: moduleSlug!,
    documentData: myData,
    isNew: isNewDocument,
    });
  3. Wrap your form with TranslationTabs:

    <TranslationTabs
    currentLanguage={translation.currentLanguage}
    moduleSlug={moduleSlug!}
    frenchSlug={translation.frenchSlug}
    translationSlugs={translation.translationSlugs}
    referenceId={translation.referenceId}
    isNew={isNew}
    >
    <YourFormFields />
    </TranslationTabs>
  4. Handle form submission:

    const onSubmit = (data: FormData) => {
    if (translation.isCreatingTranslation) {
    // Creating a translation
    const payload = {
    ...data,
    translation: translation.buildTranslationPayload(
    translation.langParam!,
    translation.refParam
    ),
    };
    createMutation.mutate(payload);
    } else {
    // Creating French document or updating
    // ... your logic
    }
    };

Benefits

Centralized Logic - All translation logic in one place
Reusable - Works for any module (News, Events, Pages, etc.)
Type-Safe - Full TypeScript support
Easy to Understand - Clear separation of concerns
Maintainable - Changes in one place affect all modules
Consistent UX - Same behavior across all modules

URL Structure

  • Create French: /modules/{slug}/créer
  • Create Translation: /modules/{slug}/créer?lang={lang}&ref={refId}
  • Edit: /modules/{slug}/modifier/{documentSlug}

State Management

The hook manages these states internally:

  • currentLanguage - Current editing language
  • referenceId - French document ID
  • translations - All translation data
  • translationIds - Translation document IDs
  • translationSlugs - Translation slugs for navigation
  • frenchSlug - French document slug

Future Improvements

  • Add loading states for translation fetching
  • Add error handling for failed translation fetches
  • Add support for copying content from one language to another
  • Add translation progress indicator (e.g., "2/3 languages translated")