Files
donetick/I18N_IMPLEMENTATION.md
Mo Tarbin 6d6185dc5e feat: Add comprehensive internationalization (i18n) support
- Add multi-language support with i18next and react-i18next
- Implement user-selectable date format preferences (5 formats)
- Add time format preferences (12-hour/24-hour)
- Implement RTL (right-to-left) support for Arabic, Hebrew, Persian, Urdu
- Add first day of week preference
- Create LocalizationContext for managing i18n settings
- Add LocalizationSettings component to Settings page
- Include sample translations: English, Spanish, Arabic
- Configure 10 languages: en, es, fr, de, ar, he, zh, ja, pt, ru
- Add translation management documentation and Crowdin config
- Create date formatting utilities that respect user preferences
- Add RTL CSS styles for proper layout mirroring
- Update Settings and ThemeToggle components to use translations
- Add comprehensive documentation (implementation guide, quick reference, translation guide)

All user preferences are persisted to localStorage and apply throughout the app.
2026-03-08 15:57:57 +00:00

10 KiB

Internationalization Implementation Guide

Overview

This document describes the comprehensive internationalization (i18n) implementation for Donetick, including language support, date format preferences, time format preferences, and right-to-left (RTL) language support.

Features Implemented

1. Multi-Language Support

  • i18next and react-i18next integration
  • Browser language detection
  • Persistent language preference
  • Translation namespaces (common, settings, chores)
  • Sample translations: English, Spanish, Arabic

2. Date Format Preferences

  • User-selectable date formats:
    • MM/DD/YYYY (US format)
    • DD/MM/YYYY (European format)
    • YYYY-MM-DD (ISO format)
    • Long format (e.g., January 1, 2024)
    • Short format (e.g., Jan 1, 2024)
  • Live preview of date formats
  • Persistent user preferences

3. Time Format Preferences

  • 12-hour format (with AM/PM)
  • 24-hour format
  • Live preview

4. RTL (Right-to-Left) Support

  • Automatic RTL layout for Arabic, Hebrew, Persian, Urdu
  • CSS styles for proper RTL rendering
  • Direction attribute on HTML element
  • Text alignment adjustments

5. First Day of Week

  • Configurable first day of week (Sunday/Monday)
  • Affects calendar displays

File Structure

donetick-frontend/
├── src/
│   ├── i18n/
│   │   ├── config.js                    # i18next configuration
│   │   └── README.md                    # i18n usage guide
│   ├── contexts/
│   │   └── LocalizationContext.jsx      # Localization context and hooks
│   ├── utils/
│   │   └── DateFormatter.js             # Date formatting utilities
│   └── views/
│       └── Settings/
│           └── LocalizationSettings.jsx  # Settings UI component
├── public/
│   └── locales/
│       ├── en/                          # English translations
│       │   ├── common.json
│       │   ├── settings.json
│       │   └── chores.json
│       ├── es/                          # Spanish translations
│       └── ar/                          # Arabic translations (RTL)
├── crowdin.yml                          # Crowdin configuration
└── TRANSLATION.md                       # Translation management guide

Usage Examples

1. Using Translations in Components

import { useTranslation } from 'react-i18next'

function MyComponent() {
  const { t } = useTranslation('settings')
  
  return (
    <div>
      <h1>{t('title')}</h1>
      <p>{t('localization.description')}</p>
    </div>
  )
}

2. Using Date Formatting

import { useLocalization } from '@/contexts/LocalizationContext'

function MyComponent() {
  const { formatDate, formatDateTime, formatRelative } = useLocalization()
  
  const expirationDate = new Date('2024-12-31')
  
  return (
    <div>
      <p>Expires: {formatDate(expirationDate)}</p>
      <p>Due: {formatRelative(expirationDate)}</p>
    </div>
  )
}

3. Accessing Localization Settings

import { useLocalization } from '@/contexts/LocalizationContext'

function MyComponent() {
  const {
    language,
    setLanguage,
    dateFormat,
    setDateFormat,
    timeFormat,
    setTimeFormat,
    isRTL
  } = useLocalization()
  
  return (
    <div dir={isRTL ? 'rtl' : 'ltr'}>
      <select value={language} onChange={(e) => setLanguage(e.target.value)}>
        <option value="en">English</option>
        <option value="es">Español</option>
        <option value="ar">العربية</option>
      </select>
    </div>
  )
}

4. Example: Converting Existing Date Formatting

Before:

import moment from 'moment'

function SubscriptionInfo({ userProfile }) {
  return (
    <p>
      Subscription expires on {moment(userProfile.expiration).format('MMM DD, YYYY')}
    </p>
  )
}

After:

import { useLocalization } from '@/contexts/LocalizationContext'

function SubscriptionInfo({ userProfile }) {
  const { formatDate } = useLocalization()
  
  return (
    <p>
      Subscription expires on {formatDate(userProfile.expiration)}
    </p>
  )
}

Settings UI

The localization settings are available in: Settings → Localization

Users can configure:

  1. Language: Select from available languages
  2. Date Format: Choose how dates are displayed
  3. Time Format: 12-hour or 24-hour
  4. First Day of Week: Sunday or Monday

Available Localization Hooks

useLocalization()

Returns an object with:

{
  // Current settings
  language: string,
  dateFormat: string,
  timeFormat: string,
  firstDayOfWeek: number,
  isRTL: boolean,
  availableLanguages: Language[],
  
  // Setters
  setLanguage: (lang: string) => void,
  setDateFormat: (format: string) => void,
  setTimeFormat: (format: string) => void,
  setFirstDayOfWeek: (day: number) => void,
  
  // Formatters
  formatDate: (date: Date | string, format?: string) => string,
  formatDateTime: (date: Date | string, format?: string) => string,
  formatTime: (date: Date | string, format?: string) => string,
  formatRelative: (date: Date | string) => string,
  formatCalendar: (date: Date | string) => string,
}

useTranslation(namespace)

From react-i18next:

{
  t: (key: string, options?: object) => string,
  i18n: i18n instance,
  ready: boolean,
}

Translation Namespaces

common.json

General UI elements used throughout the app:

  • Buttons (save, cancel, delete, etc.)
  • Common actions
  • Status messages

settings.json

All Settings page translations:

  • Section titles
  • Form labels
  • Help text
  • Notifications

chores.json

Chores/tasks related content:

  • Task management
  • Status labels
  • Action buttons

RTL Languages

The following languages automatically enable RTL layout:

  • Arabic (ar)
  • Hebrew (he)
  • Persian/Farsi (fa)
  • Urdu (ur)

RTL features:

  • Automatic dir="rtl" on HTML element
  • Flipped layouts and icons
  • Right-aligned text inputs
  • Proper border radius handling

Date Format Constants

Available in LocalizationContext.jsx:

export const DATE_FORMATS = {
  MDY: 'MM/DD/YYYY',      // 01/15/2024
  DMY: 'DD/MM/YYYY',      // 15/01/2024
  YMD: 'YYYY-MM-DD',      // 2024-01-15
  LONG: 'MMMM D, YYYY',   // January 15, 2024
  SHORT: 'MMM D, YYYY',   // Jan 15, 2024
}

export const TIME_FORMATS = {
  HOUR_12: 'h:mm A',      // 2:30 PM
  HOUR_24: 'HH:mm',       // 14:30
}

Translation Management

Adding New Languages

  1. Create directory: public/locales/{language-code}/
  2. Copy translation files from public/locales/en/
  3. Translate content
  4. Add language to AVAILABLE_LANGUAGES in LocalizationContext.jsx
  5. If RTL, add to RTL_LANGUAGES array

Using Translation Platforms

See TRANSLATION.md for detailed instructions on:

  • Setting up Crowdin (recommended)
  • Setting up Lokalise
  • Setting up POEditor
  • Setting up Weblate

Translation Guidelines

  1. Keep placeholders: {{variable}}
  2. Maintain context awareness
  3. Use consistent terminology
  4. Test with actual UI
  5. Consider character limits
  6. Preserve formatting

Migration Guide

Converting Components to Use i18n

  1. Add translation hook:

    import { useTranslation } from 'react-i18next'
    const { t } = useTranslation('namespace')
    
  2. Replace hardcoded strings:

    // Before
    <Button>Save</Button>
    
    // After
    <Button>{t('save')}</Button>
    
  3. Use localization for dates:

    import { useLocalization } from '@/contexts/LocalizationContext'
    const { formatDate } = useLocalization()
    
    // Replace moment().format() with formatDate()
    

Batch Migration Strategy

  1. Start with Settings component (already done)
  2. Convert common components (buttons, headers)
  3. Convert page components
  4. Convert utility functions
  5. Test each language thoroughly

Testing

Testing Translations

  1. Change language in Settings → Localization
  2. Navigate through the app
  3. Check all translated components
  4. Verify formatting

Testing RTL

  1. Switch to Arabic or Hebrew
  2. Check layout direction
  3. Verify icons and navigation
  4. Test form inputs

Testing Date Formats

  1. Change date format in Settings
  2. Check all date displays update
  3. Verify calendar components
  4. Test relative dates

Performance Considerations

  • Translations loaded on demand (lazy loading)
  • Language detection runs once on init
  • Format preferences stored in localStorage
  • No re-renders unless language/format changes

Browser Support

  • Modern browsers with ES6+ support
  • localStorage support required
  • CSS dir attribute support required

Accessibility

  • Proper lang attribute on HTML element
  • Screen reader compatible
  • RTL support for assistive technologies
  • High contrast mode compatible

Future Enhancements

Potential improvements:

  • Automatic translation via AI
  • Crowdsourced translation interface
  • More granular date format options
  • Regional number formatting
  • Currency formatting
  • Plural rules support
  • Gender-specific translations
  • Translation quality metrics

Troubleshooting

Translations not loading

  • Check browser console for errors
  • Verify JSON files in public/locales/
  • Check network tab for 404s

RTL not working

  • Verify language in RTL_LANGUAGES array
  • Check CSS is loaded
  • Inspect HTML dir attribute

Date format not applying

  • Check localStorage for saved preferences
  • Verify LocalizationContext is mounted
  • Check component uses formatDate functions

Resources

Contributors

For questions or contributions related to internationalization:

  • Create an issue on GitHub
  • Tag with i18n or translation
  • Reference this document

License

All translations follow the same license as the main project.