9.3 KiB
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
- Setup Overview
- File Structure
- Basic Usage
- Advanced Usage
- Custom Hook
- Language Switcher
- Best Practices
- Troubleshooting
🚀 Setup Overview
Configuration Files
.umirc.ts - Main i18n configuration:
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:
// 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
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
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
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
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:
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:
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
- Vietnamese (
src/locales/vi-VN.ts):
export default {
// Add new key
'my.new.key': 'Nội dung mới',
};
- English (
src/locales/en-US.ts):
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
useTranslationhook for better performance - Avoid inline
formatMessagecalls 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
// ❌ 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
// In .umirc.ts
locale: {
antd: true, // Ensure this is enabled
}
4. TypeScript errors
// 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:
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:
-
Manual Testing:
- Switch languages using the language switcher
- Verify all text updates correctly
- Check forms with validation messages
-
Component Testing:
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> ); -
Translation Coverage:
- Ensure all UI text is translatable
- Check that no hardcoded strings remain
- Verify all keys exist in both language files
📚 Additional Resources
🎉 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