feat(localization): Add en/vi language

This commit is contained in:
Tran Anh Tuan
2025-11-20 16:21:17 +07:00
parent dea435a4ec
commit 216e865ca5
37 changed files with 2356 additions and 455 deletions

400
I18N_USAGE_GUIDE.md Normal file
View File

@@ -0,0 +1,400 @@
# Internationalization (i18n) Usage Guide
This guide explains how to use the internationalization (i18n) features in your Ship Monitoring System built with Umi Max.
## 📋 Table of Contents
1. [Setup Overview](#setup-overview)
2. [File Structure](#file-structure)
3. [Basic Usage](#basic-usage)
4. [Advanced Usage](#advanced-usage)
5. [Custom Hook](#custom-hook)
6. [Language Switcher](#language-switcher)
7. [Best Practices](#best-practices)
8. [Troubleshooting](#troubleshooting)
## 🚀 Setup Overview
### Configuration Files
**`.umirc.ts`** - Main i18n configuration:
```typescript
locale: {
default: 'vi-VN',
baseNavigator: false,
antd: true,
title: false,
baseSeparator: '-',
locales: [
['vi-VN', 'Tiếng Việt'],
['en-US', 'English'],
],
},
```
**`src/app.tsx`** - Runtime configuration:
```typescript
// Enable locale in menu
menu: {
locale: true,
},
// Add language switcher to header
rightContentRender: () => [
<LanguageSwitcher key="language-switcher" />,
],
```
## 📁 File Structure
```
src/
├── locales/ # Translation files
│ ├── vi-VN.ts # Vietnamese translations
│ └── en-US.ts # English translations
├── components/
│ ├── LanguageSwitcher/ # Language switcher component
│ │ └── index.tsx
│ └── I18nExamples/ # Example components
│ ├── index.tsx
│ ├── BasicUsage.tsx
│ ├── FormValidation.tsx
│ └── CustomHookExample.tsx
├── hooks/
│ └── useTranslation.ts # Custom i18n hook
└── app.tsx # Runtime configuration
```
## 🔧 Basic Usage
### 1. Using `useIntl` Hook
```typescript
import { useIntl } from '@umijs/max';
import React from 'react';
const MyComponent: React.FC = () => {
const intl = useIntl();
return (
<div>
{/* Simple translation */}
<h1>{intl.formatMessage({ id: 'common.save' })}</h1>
{/* Translation with variables */}
<p>{intl.formatMessage(
{ id: 'validation.minLength' },
{ min: 6 }
)}</p>
</div>
);
};
```
### 2. Using `FormattedMessage` Component
```typescript
import { FormattedMessage } from '@umijs/max';
import React from 'react';
const MyComponent: React.FC = () => {
return (
<div>
{/* Simple translation */}
<FormattedMessage id="common.save" />
{/* Translation with variables */}
<FormattedMessage
id="validation.minLength"
values={{ min: 6 }}
/>
</div>
);
};
```
## 🎯 Advanced Usage
### 1. Form Validation with i18n
```typescript
import { Form, Input, Button } from 'antd';
import { useIntl } from '@umijs/max';
import React from 'react';
const MyForm: React.FC = () => {
const intl = useIntl();
return (
<Form>
<Form.Item
label={intl.formatMessage({ id: 'common.username' })}
name="username"
rules={[
{
required: true,
message: intl.formatMessage({ id: 'validation.required' }),
},
{
type: 'email',
message: intl.formatMessage({ id: 'validation.email' }),
},
]}
>
<Input
placeholder={intl.formatMessage({ id: 'common.username' })}
/>
</Form.Item>
</Form>
);
};
```
### 2. Conditional Rendering
```typescript
import { useIntl } from '@umijs/max';
import React from 'react';
const LocalizedContent: React.FC = () => {
const intl = useIntl();
return (
<div>
{intl.locale === 'vi-VN' ? (
<p>Chào mừng đến với hệ thống!</p>
) : (
<p>Welcome to the system!</p>
)}
</div>
);
};
```
## 🪝 Custom Hook Usage
For more convenient usage, use the custom `useTranslation` hook:
```typescript
import { useTranslation } from '@/hooks/useTranslation';
import React from 'react';
const MyComponent: React.FC = () => {
const { t, isLocale, formatDate, formatNumber } = useTranslation();
return (
<div>
{/* Simple translation */}
<h1>{t('common.save')}</h1>
{/* Translation with variables */}
<p>{t('validation.minLength', { min: 6 })}</p>
{/* Locale detection */}
{isLocale('vi-VN') && <p>Xin chào!</p>}
{/* Date formatting */}
<p>{formatDate(new Date(), {
year: 'numeric',
month: 'long',
day: 'numeric'
})}</p>
{/* Number formatting */}
<p>{formatNumber(1234.56, {
style: 'currency',
currency: 'VND'
})}</p>
</div>
);
};
```
## 🌐 Language Switcher
The language switcher component is automatically included in the header. You can also use it manually:
```typescript
import LanguageSwitcher from '@/components/LanguageSwitcher';
import React from 'react';
const Header: React.FC = () => {
return (
<div>
<LanguageSwitcher type="dropdown" />
{/* or */}
<LanguageSwitcher type="button" size="small" />
</div>
);
};
```
### Language Switcher Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `className` | `string` | - | Additional CSS classes |
| `type` | `'dropdown' \| 'button'` | `'dropdown'` | Display type |
| `size` | `'small' \| 'middle' \| 'large'` | `'middle'` | Component size |
## 📝 Translation Keys
Translation keys follow a hierarchical structure using dot notation:
```
common.save // Save button text
auth.login.title // Login page title
map.ship.status.online // Ship online status
validation.required // Validation message
```
### Adding New Translations
1. **Vietnamese** (`src/locales/vi-VN.ts`):
```typescript
export default {
// Add new key
'my.new.key': 'Nội dung mới',
};
```
2. **English** (`src/locales/en-US.ts`):
```typescript
export default {
// Add corresponding English translation
'my.new.key': 'New content',
};
```
## ✅ Best Practices
### 1. **Consistent Key Naming**
- Use dot notation for hierarchical structure
- Group related translations together
- Use descriptive, meaningful names
- Example: `'map.ship.status.online'` instead of `'online'`
### 2. **Variable Interpolation**
- Use descriptive variable names
- Provide context for variables
- Example: `'validation.minLength': 'Minimum {min} characters required'`
### 3. **Component Organization**
- Group translations by feature/module
- Keep related keys together
- Use consistent prefixes for modules
### 4. **Performance Considerations**
- Use the `useTranslation` hook for better performance
- Avoid inline `formatMessage` calls in render loops
- Cache translated strings when used frequently
### 5. **Translation Maintenance**
- Keep all translations in sync
- Add new keys to both language files
- Review translations regularly for consistency
## 🛠 Troubleshooting
### Common Issues
#### 1. **Translation not appearing**
```typescript
// ❌ Wrong
<FormattedMessage id="wrong.key" />
// ✅ Correct - check if key exists in locale files
<FormattedMessage id="common.save" />
```
#### 2. **Locale not changing**
- Ensure `localStorage.setItem('umi_locale', locale)` is called
- Check that locale is properly configured in `.umirc.ts`
- Verify that translation files exist for the target locale
#### 3. **Missing Ant Design translations**
```typescript
// In .umirc.ts
locale: {
antd: true, // Ensure this is enabled
}
```
#### 4. **TypeScript errors**
```typescript
// Ensure proper import
import { useIntl } from '@umijs/max';
// Check if translation key exists in locale files
const intl = useIntl();
const text = intl.formatMessage({ id: 'existing.key' });
```
### Debug Mode
To debug translation issues, add logging to your component:
```typescript
import { useIntl } from '@umijs/max';
import React from 'react';
const DebugComponent: React.FC = () => {
const intl = useIntl();
console.log('Current locale:', intl.locale);
console.log('Available messages:', intl.messages);
return <div>Check console for debug info</div>;
};
```
## 🔄 Testing Translations
To test your i18n implementation:
1. **Manual Testing**:
- Switch languages using the language switcher
- Verify all text updates correctly
- Check forms with validation messages
2. **Component Testing**:
```typescript
import { render } from '@testing-library/react';
import { I18nProvider } from '@umijs/max';
import MyComponent from './MyComponent';
// Test with different locales
render(
<I18nProvider locale="en-US">
<MyComponent />
</I18nProvider>
);
```
3. **Translation Coverage**:
- Ensure all UI text is translatable
- Check that no hardcoded strings remain
- Verify all keys exist in both language files
## 📚 Additional Resources
- [Umi Max i18n Documentation](https://umijs.org/docs/max/i18n)
- [React Intl Documentation](https://formatjs.io/docs/react-intl/)
- [Ant Design i18n Guide](https://ant.design/docs/react/internationalization)
## 🎉 Summary
Your i18n setup is now complete! You have:
**Configuration**: Umi Max i18n properly configured
**Translations**: Vietnamese and English translation files
**Components**: Language switcher and example components
**Custom Hook**: Simplified i18n API
**Best Practices**: Guidelines for maintainable translations
The system is ready for multi-language support and can be easily extended with additional languages or translations as needed.
---
**Last Updated**: 2025-01-20
**Version**: 1.0.0