Internationalization (i18n) Setup in SparkyFitnessFrontend

This document outlines the setup for internationalization (i18n) in the SparkyFitnessFrontend application using i18next and react-i18next.

1. Core Libraries

The following npm packages are used for i18n:

  • i18next: The core i18n library.
  • react-i18next: Integration for React applications.
  • i18next-browser-languagedetector: Detects the user's language from the browser.
  • i18next-http-backend: Loads translation files over HTTP.

These dependencies are installed in the SparkyFitnessFrontend directory.

2. Translation File Structure

Translation files are stored in the public/locales directory, following the format public/locales/{{languageCode}}/translation.json.

  • public/locales/en/translation.json: Contains English translations.
  • public/locales/ta/translation.json: Contains Tamil translations.

Each translation.json file is a simple JSON object where keys represent translation identifiers and values are the translated strings. Nested objects can be used to organize translations (e.g., "nav.diary").

Example (translation.json):

{
  "nav": {
    "diary": "Diary",
    "checkin": "Check-In"
  },
  "settings": {
    "profileInformation": {
      "title": "Profile Information"
    }
  }
}

3. i18next Configuration (src/i18n.ts)

The i18next instance is configured in SparkyFitnessFrontend/src/i18n.ts.

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import HttpApi from 'i18next-http-backend';

i18n
  .use(HttpApi)
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    supportedLngs: ['en', 'ta'], // List of supported languages
    fallbackLng: 'en', // Fallback language if a translation is missing
    detection: {
      order: ['localStorage', 'querystring', 'cookie', 'sessionStorage', 'navigator', 'htmlTag'],
      caches: ['localStorage', 'cookie'],
    },
    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json', // Path to load translation files
    },
    react: {
      useSuspense: false, // Set to true if you want to use React.Suspense for loading translations
    },
  });

export default i18n;

Key Configuration Details:

  • supportedLngs: An array of language codes that your application supports.
  • fallbackLng: The language to use if a translation for the current language is missing.
  • detection.order: Specifies the order in which i18next tries to detect the user's language. localStorage is prioritized to use the user's saved preference.
  • backend.loadPath: The URL pattern to fetch translation files. {{lng}} is replaced by the current language code, and {{ns}} by the namespace (defaulting to translation).
  • react.useSuspense: Set to false to avoid using React's Suspense feature for translations, simplifying initial setup.

4. Integration into React Application (src/main.tsx)

The i18next instance is initialized and provided to the React application in SparkyFitnessFrontend/src/main.tsx.

import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import { BrowserRouter } from 'react-router-dom';
import { AuthProvider } from './hooks/useAuth.tsx';
import './i18n'; // Import the i18n configuration
import { Suspense } from 'react';

createRoot(document.getElementById("root")!).render(
  <Suspense fallback="loading">
    <BrowserRouter>
      <AuthProvider>
        <App />
      </AuthProvider>
    </BrowserRouter>
  </Suspense>
);

The Suspense component is used to display a fallback (e.g., "loading") while translations are being loaded.

5. Language Handling Component (src/components/LanguageHandler.tsx)

A dedicated component, SparkyFitnessFrontend/src/components/LanguageHandler.tsx, is used to synchronize the i18next language with the user's preference stored in the PreferencesContext.

import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { usePreferences } from '@/contexts/PreferencesContext';

const LanguageHandler = () => {
  const { i18n } = useTranslation();
  const { language } = usePreferences();

  useEffect(() => {
    if (language) {
      i18n.changeLanguage(language);
    }
  }, [language, i18n]);

  return null; // This component doesn't render anything
};

export default LanguageHandler;

This component ensures that when the language preference changes (e.g., via the language switcher in settings), i18next updates its active language.

6. Using Translations in Components

To use translations in any React component, import the useTranslation hook from react-i18next.

import { useTranslation } from 'react-i18next';

const MyComponent = () => {
  const { t } = useTranslation();

  return (
    <div>
      <h1>{t('nav.diary')}</h1>
      <p>{t('settings.profileInformation.description')}</p>
    </div>
  );
};

The t function takes a translation key (e.g., "nav.diary") and returns the corresponding translated string for the currently active language.

7. Language Switcher in Settings (src/components/Settings.tsx)

The language switcher is integrated into the Preferences section of the Settings component. It uses the language state and setLanguage function from PreferencesContext to update the user's preferred language.

// Inside Settings.tsx
import { useTranslation } from "react-i18next";
import { usePreferences } from "@/contexts/PreferencesContext";
// ... other imports

const Settings: React.FC<SettingsProps> = ({ onShowAboutDialog }) => {
  const { t } = useTranslation();
  const { language, setLanguage } = usePreferences();
  // ... other state and functions

  // Inside the Preferences AccordionContent
  <div>
    <Label htmlFor="language">{t('settings.preferences.language')}</Label>
    <Select
      value={language}
      onValueChange={setLanguage}
    >
      <SelectTrigger>
        <SelectValue />
      </SelectTrigger>
      <SelectContent>
        <SelectItem value="en">English</SelectItem>
        <SelectItem value="ta">தமிழ்</SelectItem>
      </SelectContent>
    </Select>
  </div>
  // ...
};

8. Adding New Languages

To add a new language (e.g., Spanish - es):

  1. Create Translation File: Create a new JSON file: public/locales/es/translation.json.
  2. Add Translations: Populate translation.json with Spanish translations for all keys used in the application.
  3. Update i18n.ts: Add 'es' to the supportedLngs array in SparkyFitnessFrontend/src/i18n.ts.
  4. Update Language Switcher: Add a new SelectItem for Spanish in the language switcher within SparkyFitnessFrontend/src/components/Settings.tsx.
  5. Backend Update (if applicable): If you want to store the language preference in the backend, ensure the user_preferences table and associated API endpoints can handle the new language code.

By following these steps, you can easily extend the application to support additional languages.