Files
Charon/docs/i18n-examples.md
akanealw eec8c28fb3
Some checks are pending
Go Benchmark / Performance Regression Check (push) Waiting to run
Cerberus Integration / Cerberus Security Stack Integration (push) Waiting to run
Upload Coverage to Codecov / Backend Codecov Upload (push) Waiting to run
Upload Coverage to Codecov / Frontend Codecov Upload (push) Waiting to run
CodeQL - Analyze / CodeQL analysis (go) (push) Waiting to run
CodeQL - Analyze / CodeQL analysis (javascript-typescript) (push) Waiting to run
CrowdSec Integration / CrowdSec Bouncer Integration (push) Waiting to run
Docker Build, Publish & Test / build-and-push (push) Waiting to run
Docker Build, Publish & Test / Security Scan PR Image (push) Blocked by required conditions
Quality Checks / Auth Route Protection Contract (push) Waiting to run
Quality Checks / Codecov Trigger/Comment Parity Guard (push) Waiting to run
Quality Checks / Backend (Go) (push) Waiting to run
Quality Checks / Frontend (React) (push) Waiting to run
Rate Limit integration / Rate Limiting Integration (push) Waiting to run
Security Scan (PR) / Trivy Binary Scan (push) Waiting to run
Supply Chain Verification (PR) / Verify Supply Chain (push) Waiting to run
WAF integration / Coraza WAF Integration (push) Waiting to run
changed perms
2026-04-22 18:19:14 +00:00

270 lines
5.9 KiB
Markdown
Executable File

---
title: i18n Implementation Examples
description: Developer guide for implementing internationalization in Charon React components using react-i18next.
---
## i18n Implementation Examples
This document shows examples of how to use translations in Charon components.
### Basic Usage
### Using the `useTranslation` Hook
```typescript
import { useTranslation } from 'react-i18next'
function MyComponent() {
const { t } = useTranslation()
return (
<div>
<h1>{t('navigation.dashboard')}</h1>
<button>{t('common.save')}</button>
<button>{t('common.cancel')}</button>
</div>
)
}
```
### With Interpolation
```typescript
import { useTranslation } from 'react-i18next'
function ProxyHostsCount({ count }: { count: number }) {
const { t } = useTranslation()
return <p>{t('dashboard.activeHosts', { count })}</p>
// Renders: "5 active" (English) or "5 activo" (Spanish)
}
```
## Common Patterns
### Page Titles and Descriptions
```typescript
import { useTranslation } from 'react-i18next'
import { PageShell } from '../components/layout/PageShell'
export default function Dashboard() {
const { t } = useTranslation()
return (
<PageShell
title={t('dashboard.title')}
description={t('dashboard.description')}
>
{/* Page content */}
</PageShell>
)
}
```
### Button Labels
```typescript
import { useTranslation } from 'react-i18next'
import { Button } from '../components/ui/Button'
function SaveButton() {
const { t } = useTranslation()
return (
<Button onClick={handleSave}>
{t('common.save')}
</Button>
)
}
```
### Form Labels
```typescript
import { useTranslation } from 'react-i18next'
import { Label } from '../components/ui/Label'
import { Input } from '../components/ui/Input'
function EmailField() {
const { t } = useTranslation()
return (
<div>
<Label htmlFor="email">{t('auth.email')}</Label>
<Input
id="email"
type="email"
placeholder={t('auth.email')}
/>
</div>
)
}
```
### Error Messages
```typescript
import { useTranslation } from 'react-i18next'
function validateForm(data: FormData) {
const { t } = useTranslation()
const errors: Record<string, string> = {}
if (!data.email) {
errors.email = t('errors.required')
} else if (!isValidEmail(data.email)) {
errors.email = t('errors.invalidEmail')
}
if (!data.password || data.password.length < 8) {
errors.password = t('errors.passwordTooShort')
}
return errors
}
```
### Toast Notifications
```typescript
import { useTranslation } from 'react-i18next'
import { toast } from '../utils/toast'
function handleSave() {
const { t } = useTranslation()
try {
await saveData()
toast.success(t('notifications.saveSuccess'))
} catch (error) {
toast.error(t('notifications.saveFailed'))
}
}
```
### Navigation Menu
```typescript
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
function Navigation() {
const { t } = useTranslation()
const navItems = [
{ path: '/', label: t('navigation.dashboard') },
{ path: '/proxy-hosts', label: t('navigation.proxyHosts') },
{ path: '/certificates', label: t('navigation.certificates') },
{ path: '/settings', label: t('navigation.settings') },
]
return (
<nav>
{navItems.map(item => (
<Link key={item.path} to={item.path}>
{item.label}
</Link>
))}
</nav>
)
}
```
## Advanced Patterns
### Pluralization
```typescript
import { useTranslation } from 'react-i18next'
function ItemCount({ count }: { count: number }) {
const { t } = useTranslation()
// Translation file should have:
// "items": "{{count}} item",
// "items_other": "{{count}} items"
return <p>{t('items', { count })}</p>
}
```
### Dynamic Keys
```typescript
import { useTranslation } from 'react-i18next'
function StatusBadge({ status }: { status: string }) {
const { t } = useTranslation()
// Dynamically build the translation key
return <span>{t(`certificates.${status}`)}</span>
// Translates to: "Valid", "Pending", "Expired", etc.
}
```
### Context-Specific Translations
```typescript
import { useTranslation } from 'react-i18next'
function DeleteConfirmation({ itemType }: { itemType: 'host' | 'certificate' }) {
const { t } = useTranslation()
return (
<div>
<p>{t(`${itemType}.deleteConfirmation`)}</p>
<Button variant="danger">{t('common.delete')}</Button>
<Button variant="outline">{t('common.cancel')}</Button>
</div>
)
}
```
## Testing Components with i18n
When testing components that use i18n, mock the `useTranslation` hook:
```typescript
import { vi } from 'vitest'
import { render } from '@testing-library/react'
// Mock i18next
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string) => key, // Return the key as-is for testing
i18n: {
changeLanguage: vi.fn(),
language: 'en',
},
}),
}))
describe('MyComponent', () => {
it('renders translated content', () => {
const { getByText } = render(<MyComponent />)
expect(getByText('navigation.dashboard')).toBeInTheDocument()
})
})
```
## Best Practices
1. **Always use translation keys** - Never hardcode strings in components
2. **Use descriptive keys** - Keys should indicate what the text is for
3. **Group related translations** - Use namespaces (common, navigation, etc.)
4. **Keep translations short** - Long strings may not fit in the UI
5. **Test all languages** - Verify translations work in different languages
6. **Provide context** - Use comments in translation files to explain usage
## Migration Checklist
When converting an existing component to use i18n:
- [ ] Import `useTranslation` hook
- [ ] Add `const { t } = useTranslation()` at component top
- [ ] Replace all hardcoded strings with `t('key')`
- [ ] Add missing translation keys to all language files
- [ ] Test the component in different languages
- [ ] Update component tests to mock i18n