Supported Languages

WI-CARPOOL supports multiple languages with complete translation coverage for all user interfaces.

Primary Languages

  • English (en)
  • Spanish (es)
  • French (fr)
  • Arabic (ar)

Additional Languages

  • Dutch (nl)
  • Portuguese (pt)
  • Russian (ru)
  • Hindi (hi)

Translation Hook Usage

// src/hooks/useTranslation.tsx
import { useTranslation } from '@/hooks/useTranslation'

function WelcomeMessage() {
  const { t } = useTranslation()
  
  return (
    <div>
      <h1>{t('welcome.title')}</h1>
      <p>{t('welcome.description', { name: 'John' })}</p>
    </div>
  )
}

Language System Implementation

Language Context Provider

// src/contexts/LanguageContext.tsx
import { createContext, useContext, useState, useEffect } from 'react'

interface LanguageContextType {
  currentLanguage: string
  setLanguage: (lang: string) => void
  t: (key: string, params?: Record<string, any>) => string
  availableLanguages: Array<{ code: string; name: string; flag: string }>
}

const LanguageContext = createContext<LanguageContextType | undefined>(undefined)

export function LanguageProvider({ children }: { children: React.ReactNode }) {
  const [currentLanguage, setCurrentLanguage] = useState('en')
  const [translations, setTranslations] = useState({})

  const availableLanguages = [
    { code: 'en', name: 'English', flag: '🇺🇸' },
    { code: 'es', name: 'Español', flag: '🇪🇸' },
    { code: 'fr', name: 'Français', flag: '🇫🇷' },
    { code: 'ar', name: 'العربية', flag: '🇸🇦' },
    { code: 'nl', name: 'Nederlands', flag: '🇳🇱' },
    { code: 'pt', name: 'Português', flag: '🇵🇹' },
    { code: 'ru', name: 'Русский', flag: '🇷🇺' },
    { code: 'hi', name: 'हिंदी', flag: '🇮🇳' },
  ]

  useEffect(() => {
    loadTranslations(currentLanguage)
  }, [currentLanguage])

  const loadTranslations = async (lang: string) => {
    try {
      const module = await import(`@/translations/${lang}.ts`)
      setTranslations(module.default)
    } catch (error) {
      console.error(`Failed to load translations for ${lang}`, error)
    }
  }

  const setLanguage = (lang: string) => {
    setCurrentLanguage(lang)
    localStorage.setItem('preferred-language', lang)
    document.documentElement.lang = lang
    document.documentElement.dir = lang === 'ar' ? 'rtl' : 'ltr'
  }

  const t = (key: string, params?: Record<string, any>): string => {
    const keys = key.split('.')
    let value: any = translations
    
    for (const k of keys) {
      value = value?.[k]
    }
    
    if (typeof value !== 'string') {
      return key // Return key if translation not found
    }
    
    if (params) {
      return value.replace(/\{\{(\w+)\}\}/g, (match: string, param: string) => {
        return params[param] || match
      })
    }
    
    return value
  }

  return (
    <LanguageContext.Provider value={{
      currentLanguage,
      setLanguage,
      t,
      availableLanguages
    }}>
      {children}
    </LanguageContext.Provider>
  )
}

Translation Files Structure

English Translation (en.ts)

// src/translations/en.ts
export default {
  // Navigation
  nav: {
    home: 'Home',
    about: 'About',
    search: 'Find Rides',
    dashboard: 'Dashboard',
    profile: 'Profile',
    signIn: 'Sign In',
    signUp: 'Sign Up',
    signOut: 'Sign Out'
  },
  
  // Authentication
  auth: {
    welcome: 'Welcome to WI-CARPOOL',
    signInTitle: 'Sign in to your account',
    signUpTitle: 'Create your account',
    email: 'Email address',
    password: 'Password',
    confirmPassword: 'Confirm password',
    forgotPassword: 'Forgot your password?',
    noAccount: 'Don\'t have an account?',
    hasAccount: 'Already have an account?',
    signInButton: 'Sign In',
    signUpButton: 'Sign Up',
    orContinueWith: 'Or continue with'
  },
  
  // Search
  search: {
    from: 'From',
    to: 'To',
    date: 'Date',
    passengers: 'Passengers',
    searchButton: 'Search Rides',
    noResults: 'No rides found',
    resultsCount: '{{count}} rides found'
  },
  
  // Common
  common: {
    loading: 'Loading...',
    error: 'Something went wrong',
    success: '¡Éxito!',
    cancel: 'Cancel',
    confirm: 'Confirm',
    save: 'Save',
    delete: 'Eliminar',
    edit: 'Editar',
    back: 'Atrás',
    next: 'Siguiente',
    previous: 'Anterior'
  }
}

Spanish Translation (es.ts)

// src/translations/es.ts
export default {
  nav: {
    home: 'Inicio',
    about: 'Acerca de',
    search: 'Buscar Viajes',
    dashboard: 'Panel',
    profile: 'Perfil',
    signIn: 'Iniciar Sesión',
    signUp: 'Registrarse',
    signOut: 'Cerrar Sesión'
  },
  
  auth: {
    welcome: 'Bienvenido a WI-CARPOOL',
    signInTitle: 'Inicia sesión en tu cuenta',
    signUpTitle: 'Crea tu cuenta',
    email: 'Correo electrónico',
    password: 'Contraseña',
    confirmPassword: 'Confirmar contraseña',
    forgotPassword: '¿Olvidaste tu contraseña?',
    noAccount: '¿No tienes una cuenta?',
    hasAccount: '¿Ya tienes una cuenta?',
    signInButton: 'Iniciar Sesión',
    signUpButton: 'Registrarse',
    orContinueWith: 'O continúa con'
  },
  
  search: {
    from: 'Desde',
    to: 'Hasta',
    date: 'Fecha',
    passengers: 'Pasajeros',
    searchButton: 'Buscar Viajes',
    noResults: 'No se encontraron viajes',
    resultsCount: '{{count}} viajes encontrados'
  },
  
  common: {
    loading: 'Cargando...',
    error: 'Algo salió mal',
    success: '¡Éxito!',
    cancel: 'Cancelar',
    confirm: 'Confirmar',
    save: 'Guardar',
    delete: 'Eliminar',
    edit: 'Editar',
    back: 'Atrás',
    next: 'Siguiente',
    previous: 'Anterior'
  }
}

Language Selector Component

Language Dropdown

// src/components/LanguageSelector.tsx
import { useLanguage } from '@/contexts/LanguageContext'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select'
import { Globe } from 'lucide-react'

export function LanguageSelector() {
  const { currentLanguage, setLanguage, availableLanguages } = useLanguage()

  return (
    <Select value={currentLanguage} onValueChange={setLanguage}>
      <SelectTrigger className="w-[140px]">
        <Globe className="h-4 w-4 mr-2" />
        <SelectValue />
      </SelectTrigger>
      <SelectContent>
        {availableLanguages.map((lang) => (
          <SelectItem key={lang.code} value={lang.code}>
            <span className="mr-2">{lang.flag}</span>
            {lang.name}
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  )
}

RTL Support

RTL Styling

/* src/styles/rtl.css */
[dir="rtl"] {
  text-align: right;
}

[dir="rtl"] .sidebar {
  right: 0;
  left: auto;
  border-right: none;
  border-left: 1px solid #e2e8f0;
}

[dir="rtl"] .main-content {
  margin-right: 280px;
  margin-left: 0;
}

[dir="rtl"] .breadcrumb-separator {
  transform: scaleX(-1);
}

/* Tailwind RTL utilities */
.rtl\:text-right[dir="rtl"] {
  text-align: right;
}

.rtl\:text-left[dir="rtl"] {
  text-align: left;
}

.rtl\:ml-auto[dir="rtl"] {
  margin-left: auto;
}

.rtl\:mr-auto[dir="rtl"] {
  margin-right: auto;
}

Best Practices

Translation Guidelines

  • Use nested keys for organized translation structure
  • Implement pluralization rules for different languages
  • Provide context for translators with comments
  • Use interpolation for dynamic content
  • Test all languages thoroughly

Performance

  • Lazy load translation files to reduce initial bundle size
  • Implement caching for translation files
  • Use tree shaking to remove unused translations
  • Preload critical translations for better UX

Accessibility

  • Set proper lang attributes on HTML elements
  • Support screen readers in different languages
  • Provide language switching announcements
  • Test with assistive technologies in target languages