Files
Eric FELIXINE 94f74f2dfc feat: add smart-app-city sub-project architecture
- Architecture globale (React Native + NestJS + FastAPI)
- Beckn Protocol (OTN-DPI) integration docs
- AI layer: RAG pipeline + AI Agents (LocalAI + Qdrant)
- i18n: FR/EN/ES/DE support
- Docker Compose for backend services
- Project structure with frontend, backend, ai, beckn directories
2026-05-26 18:47:02 -04:00

4.0 KiB

Smart App City — Internationalization (i18n) Guide

Supported Languages

Language Code Status Coverage
Français fr Primary 100%
English en 🔄 Phase 1 100%
Español es 📋 Phase 2 80%
Deutsch de 📋 Phase 2 80%

Architecture

Frontend (React Native)

// frontend/src/i18n/index.ts
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import fr from './locales/fr.json';
import en from './locales/en.json';
import es from './locales/es.json';
import de from './locales/de.json';

i18n.use(initReactI18next).init({
  resources: { fr, en, es, de },
  lng: 'fr',
  fallbackLng: 'en',
  interpolation: { escapeValue: false },
});

Translation Files Structure

frontend/src/i18n/locales/
├── fr.json (source of truth)
├── en.json
├── es.json
└── de.json

Example Translation File

{
  "common": {
    "welcome": "Bienvenue",
    "loading": "Chargement...",
    "error": "Erreur",
    "retry": "Réessayer",
    "cancel": "Annuler"
  },
  "dashboard": {
    "title": "Tableau de bord",
    "weather": "Météo",
    "airQuality": "Qualité de l'air",
    "traffic": "Trafic",
    "notifications": "Notifications"
  },
  "transport": {
    "title": "Transport",
    "bus": "Bus",
    "parking": "Parking",
    "taxi": "Taxi",
    "bike": "Vélo",
    "searchPlaceholder": "Où allez-vous?"
  },
  "report": {
    "title": "Signalement",
    "category": "Catégorie",
    "description": "Description",
    "photo": "Photo",
    "location": "Position",
    "submit": "Envoyer",
    "success": "Signalement envoyé!"
  }
}

ICU MessageFormat for Pluralization

{
  "notifications": {
    "count": "{count, plural, =0 {Aucune notification} =1 {1 notification} other {{count} notifications}}"
  },
  "sensors": {
    "active": "{count, plural, =0 {Aucun capteur actif} =1 {1 capteur actif} other {{count} capteurs actifs}}"
  }
}

Backend (NestJS)

Language Detection优先级

  1. User preference (stored in profile)
  2. Accept-Language header
  3. Device locale
  4. Default: French

Response Headers

// backend/common/interceptors/i18n.interceptor.ts
@Injectable()
export class I18nInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler) {
    const request = context.switchToHttp().getRequest();
    const lang = request.headers['accept-language']?.split(',')[0] || 'fr';
    
    return next.handle().pipe(
      map(data => ({
        ...data,
        _meta: { language: lang, timestamp: new Date().toISOString() }
      }))
    );
  }
}

Content Translation Strategy

Static Content (UI Strings)

  • Manual translation (high quality)
  • i18n JSON files in repo
  • LLM-assist for initial translation (Phase 2: ES, DE)

Dynamic Content (Database)

  • PostgreSQL jsonb multilingual fields
  • Example: { "fr": "Parc de stationnement", "en": "Parking lot", "es": "Aparcamiento" }
-- Database schema for multilingual content
CREATE TABLE poi (
  id UUID PRIMARY KEY,
  name JSONB NOT NULL,  -- {"fr": "...", "en": "...", "es": "..."}
  description JSONB,
  location GEOGRAPHY(POINT),
  category VARCHAR(50),
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Query with language fallback
SELECT 
  COALESCE(name->>'fr', name->>'en') as name,
  COALESCE(description->>'fr', description->>'en') as description
FROM poi
WHERE id = $1;

API Content (Real-time data)

  • ⚠️ English (data source language)
  • LLM translation for user-facing text
  • ⚠️ No translation for sensor values (numbers are universal)

Quality Assurance

Automated Checks

# Check for missing translations
npm run i18n:check

# Output:
# ❌ Missing ES translation: "report.success"
# ❌ Missing DE translation: "transport.searchPlaceholder"

Community Translation

  • Crowdin integration for community contributions
  • GitHub Actions sync PO files
  • Monthly translation sprints