Skip to content

Internationalization

PinTeach uses react-i18next for all user-facing strings. No hardcoded strings in components.

  • Primary language: Spanish (ES)
  • Secondary language: English (EN)
  • Total keys: 5,400+
import { useTranslation } from 'react-i18next';
function MyComponent() {
const { t } = useTranslation();
return (
<div>
<h1>{t('reviews.title')}</h1>
<p>{t('sessions.count', { count: 5 })}</p>
<button>{t('common.save')}</button>
</div>
);
}
PrefixArea
common.*Shared (save, cancel, delete, loading, error)
nav.*Navigation labels
dashboard.*Dashboard KPIs and actions
calendar.*Calendar views and events
sessions.*Session management
students.*Student CRM
services.*Service management
payments.*Payment history and KPIs
reviews.*Review system
materials.*Materials browser
widgets.*Widget configuration
settings.*Settings pages
shortcuts.*Keyboard shortcuts (55+ keys)
profile.*Teacher profile
auth.*Login and verification
onboarding.*Onboarding wizard
privacy.*GDPR and data management
  1. Every user-facing string must use t() — no hardcoded strings
  2. Both ES and EN translations are required for every key
  3. Use interpolation for dynamic values: t('key', { name: 'Maria' })
  4. Use pluralization: t('key', { count: n }) with _one / _other suffixes
  5. Keyboard shortcut labels use shortcuts.* namespace

Setup in apps/web/src/lib/i18n.ts:

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n.use(initReactI18next).init({
lng: 'es', // Spanish primary
fallbackLng: 'en',
interpolation: { escapeValue: false },
resources: { es, en },
});