Files
donetick/src/i18n
everysingletear 6dc7c3d370 i18n: extract Authorization screens into a new auth namespace
Every user-facing string under src/views/Authorization/ moves to i18next.
English only — no translations in this PR, so it is language-agnostic and
reviewable as a pure refactor.

Covered:
- LoginView — primary/sub-account tabs, credential form, social and
  Authentik buttons, welcome-back state, every auth error toast
- Signup — account creation form and each field-validation message
- ForgotPasswordView / UpdatePasswordView — reset flow and its toasts
- Authenticating — the OAuth landing screen, including its MFA branches
- MFAVerificationModal — code entry, backup codes, error states
- AuthFields / LoginSettings — shared field labels and server settings

`auth` is registered in src/i18n/config.js; public/locales/en/auth.json
holds the 103 keys. The Crowdin config picks up /public/locales/en/*.json
by glob, so the namespace flows into the pipeline with no change to
crowdin.yml.

No behaviour change: every t() value is the string that rendered before,
character for character — checked mechanically against this branch's base.
The e2e suite selects auth controls by visible text ('Create account',
'Username must be at least 4 characters'), so a green run is the proof.

Two fixes fell out of the extraction:
- AuthPasswordField had label='Password' as a prop default, so neither
  LoginView nor Signup passed one. A default cannot be translated at module
  scope, so the label moves to the call sites and both now pass it.
- AuthDivider defaulted children to 'or' for the same reason; it now falls
  back to t('or').
2026-08-12 20:03:02 +08:00
..

Internationalization (i18n) Setup

This directory contains the internationalization configuration for Donetick.

Structure

src/i18n/
├── config.js           # i18next configuration
└── README.md          # This file

public/locales/
├── en/                # English (default)
│   ├── common.json
│   ├── settings.json
│   └── chores.json
├── es/                # Spanish
├── ar/                # Arabic (RTL)
└── ...

Usage in Components

Using translations

import { useTranslation } from 'react-i18next'

function MyComponent() {
  const { t } = useTranslation('settings') // or 'common', 'chores'
  
  return <h1>{t('title')}</h1>
}

Using date formatting

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

function MyComponent() {
  const { formatDate, formatDateTime, formatRelative } = useLocalization()
  
  const date = new Date()
  
  return (
    <div>
      <p>Date: {formatDate(date)}</p>
      <p>DateTime: {formatDateTime(date)}</p>
      <p>Relative: {formatRelative(date)}</p>
    </div>
  )
}

Using language/format settings

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

function MyComponent() {
  const {
    language,
    setLanguage,
    dateFormat,
    setDateFormat,
    isRTL
  } = useLocalization()
  
  return (
    <div dir={isRTL ? 'rtl' : 'ltr'}>
      Current language: {language}
    </div>
  )
}

Available Namespaces

  • common: General UI elements (buttons, messages, etc.)
  • settings: Settings page translations
  • chores: Chores-related translations

Adding New Translations

  1. Add the text to the appropriate JSON file in public/locales/en/
  2. Use the translation in your component with t('key')
  3. Upload to translation platform for community translation

RTL Support

Languages in the RTL_LANGUAGES array automatically get:

  • dir="rtl" on the document
  • RTL-specific CSS styles
  • Proper text alignment

Currently supported RTL languages: Arabic (ar), Hebrew (he), Persian (fa), Urdu (ur)

Date Format Preferences

Users can choose from:

  • MM/DD/YYYY (US)
  • DD/MM/YYYY (Europe)
  • YYYY-MM-DD (ISO)
  • Long format (January 1, 2024)
  • Short format (Jan 1, 2024)

Time Format Preferences

  • 12-hour (with AM/PM)
  • 24-hour

First Day of Week

Users can choose:

  • Sunday
  • Monday