Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/aluxey/E-Commerce/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Sabbels Handmade provides a bilingual shopping experience with support for German (default) and French. The internationalization system uses i18next with React bindings, persistent language preferences, and automatic browser language detection.

Language Configuration

The i18n setup initializes with intelligent language detection:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import de from './locales/de/translation.json';
import fr from './locales/fr/translation.json';

// Language detection priority:
// 1. Previously saved preference (localStorage)
// 2. Browser language (if French)
// 3. Default to German
const storedLang = localStorage.getItem('lang');
const browserLang = navigator.language?.slice(0, 2);
const initialLang = storedLang || (browserLang === 'fr' ? 'fr' : 'de');

i18n
  .use(initReactI18next)
  .init({
    resources: {
      de: { translation: de },
      fr: { translation: fr },
    },
    lng: initialLang,
    fallbackLng: 'de',
    interpolation: {
      escapeValue: false, // React already escapes
    },
    react: {
      useSuspense: false, // Avoid loading flicker
    },
  });

// Persist language changes to localStorage
i18n.on('languageChanged', lng => {
  localStorage.setItem('lang', lng);
});

export default i18n;

Language Files Structure

Translations are organized in JSON files under client/src/locales/:
client/src/locales/
├── de/
│   └── translation.json
└── fr/
    └── translation.json
Each translation file contains nested keys for different sections:
{
  "nav": {
    "home": "Startseite",
    "shop": "Shop",
    "about": "Über uns",
    "contact": "Kontakt"
  },
  "product": {
    "addToCart": "In den Warenkorb",
    "outOfStock": "Ausverkauft",
    "price": "Preis",
    "size": "Größe",
    "color": "Farbe"
  },
  "checkout": {
    "title": "Kasse",
    "total": "Gesamt",
    "payNow": "Jetzt bezahlen"
  }
}

Using Translations in Components

The useTranslation hook provides access to translation functions:

Basic Translation

import { useTranslation } from 'react-i18next';

function ProductCard({ product }) {
  const { t } = useTranslation();

  return (
    <div>
      <h3>{product.name}</h3>
      <p>{t('product.price')}: {product.price}</p>
      <button>{t('product.addToCart')}</button>
    </div>
  );
}

Translation with Interpolation

function OrderConfirmation({ orderId, total }) {
  const { t } = useTranslation();

  return (
    <div>
      <h2>{t('order.confirmation', { orderId })}</h2>
      <p>{t('order.totalAmount', { amount: total })}</p>
    </div>
  );
}
Corresponding translation keys:
{
  "order": {
    "confirmation": "Bestellung #{{orderId}} bestätigt",
    "totalAmount": "Gesamtbetrag: {{amount}} €"
  }
}

Pluralization

function CartSummary({ itemCount }) {
  const { t } = useTranslation();

  return <p>{t('cart.items', { count: itemCount })}</p>;
}
{
  "cart": {
    "items_one": "{{count}} Artikel",
    "items_other": "{{count}} Artikel"
  }
}

Language Switcher

Implement a language toggle component to allow users to change languages:
import { useTranslation } from 'react-i18next';

function LanguageSwitcher() {
  const { i18n } = useTranslation();
  const currentLang = i18n.language;

  const toggleLanguage = () => {
    const newLang = currentLang === 'de' ? 'fr' : 'de';
    i18n.changeLanguage(newLang);
  };

  return (
    <button onClick={toggleLanguage}>
      {currentLang === 'de' ? '🇫🇷 Français' : '🇩🇪 Deutsch'}
    </button>
  );
}
Language changes are automatically persisted to localStorage and will be restored on the next visit.

Date and Number Formatting

For locale-aware formatting of dates and numbers, use native JavaScript APIs:

Date Formatting

import { useTranslation } from 'react-i18next';

function OrderDate({ date }) {
  const { i18n } = useTranslation();
  const locale = i18n.language === 'fr' ? 'fr-FR' : 'de-DE';

  const formattedDate = new Date(date).toLocaleDateString(locale, {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
    hour: '2-digit',
    minute: '2-digit'
  });

  return <span>{formattedDate}</span>;
}

Number/Currency Formatting

function Price({ amount, currency = 'EUR' }) {
  const { i18n } = useTranslation();
  const locale = i18n.language === 'fr' ? 'fr-FR' : 'de-DE';

  const formatted = new Intl.NumberFormat(locale, {
    style: 'currency',
    currency: currency,
  }).format(amount);

  return <span>{formatted}</span>;
}

Backend Email Localization

The backend email templates use German by default for order confirmations sent to the shop owner:
server.js:343
const orderDate = new Date(order.created_at).toLocaleDateString('de-DE', {
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  hour: '2-digit',
  minute: '2-digit'
});
Consider extending the email system to use the customer’s preferred language for customer-facing emails by storing the language preference in the order metadata.

Best Practices

Namespace Organization

Organize translation keys by feature or page:
{
  "nav": { ... },
  "home": { ... },
  "shop": { ... },
  "product": { ... },
  "cart": { ... },
  "checkout": { ... },
  "account": { ... },
  "admin": { ... }
}

Avoid Hardcoded Strings

Always use translation keys for user-facing text:
<button>{t('product.addToCart')}</button>

Keep Keys Consistent

Use the same translation keys across both language files to ensure completeness:
# Validate that all keys exist in both files
npm run i18n:validate

Adding a New Language

To add support for another language:
  1. Create a new translation file: client/src/locales/[lang]/translation.json
  2. Import and register it in i18n.js:
import it from './locales/it/translation.json';

i18n.use(initReactI18next).init({
  resources: {
    de: { translation: de },
    fr: { translation: fr },
    it: { translation: it }, // New language
  },
  // ...
});
  1. Update the language switcher to include the new option
  2. Test all pages to ensure translations are complete

Build docs developers (and LLMs) love