7.7 KiB
Bilingual System Implementation Guide
Overview
The system now supports 100% bilingual functionality with English and Arabic languages. Everything switches based on user preference, including:
- Navigation menus
- Buttons and labels
- Form fields and placeholders
- Error messages and notifications
- Table headers and content
- Modals and dialogs
Quick Start
1. Using Translations in Components
'use client'
import { useLanguage } from '@/contexts/LanguageContext'
function MyComponent() {
const { t, language, dir } = useLanguage()
return (
<div dir={dir}>
<h1>{t('contacts.title')}</h1>
<button>{t('common.save')}</button>
<p>{t('contacts.searchPlaceholder')}</p>
</div>
)
}
2. Adding the Language Switcher
Add the language switcher to your navigation/header:
import LanguageSwitcher from '@/components/LanguageSwitcher'
function Header() {
return (
<header>
{/* Other header content */}
<LanguageSwitcher />
</header>
)
}
3. Translation Keys Structure
Translations are organized by domain:
common.* - Common UI elements (save, cancel, delete, etc.)
nav.* - Navigation items
contacts.* - Contacts module
import.* - Import functionality
messages.* - System messages
Complete Examples
Example 1: Simple Button
// Before (hardcoded)
<button>Add Contact</button>
// After (bilingual)
<button>{t('contacts.addContact')}</button>
Example 2: Form Labels
// Before
<label>Name <span className="text-red-500">*</span></label>
// After
<label>
{t('contacts.name')}
<span className="text-red-500"> {t('common.required')}</span>
</label>
Example 3: Toast Notifications
// Before
toast.success('Contact created successfully')
// After
toast.success(t('contacts.createSuccess'))
Example 4: Conditional Text with Direction
const { t, dir } = useLanguage()
return (
<div dir={dir} className={dir === 'rtl' ? 'text-right' : 'text-left'}>
<h2>{t('contacts.title')}</h2>
</div>
)
Adding New Translations
To add new translations, edit /src/contexts/LanguageContext.tsx:
const translations = {
en: {
myModule: {
myKey: 'My English Text',
anotherKey: 'Another English Text'
}
},
ar: {
myModule: {
myKey: 'النص بالعربية',
anotherKey: 'نص آخر بالعربية'
}
}
}
Then use it:
{t('myModule.myKey')}
Current Translation Coverage
All translations are already defined for:
Common UI Elements
- Actions: save, cancel, delete, edit, add, search, filter, export, import
- States: loading, active, inactive, archived, deleted
- Feedback: success, error, confirm
- Navigation: back, next, finish, close, yes, no
Contacts Module
- All field labels (name, email, phone, etc.)
- Contact types (individual, company, holding, government)
- Relationship types (representative, partner, supplier, etc.)
- Actions (add, edit, delete, merge, import, export)
- Messages (success, error, warnings)
Import/Export
- All steps and labels
- File requirements
- Results and errors
RTL (Right-to-Left) Support
The system automatically applies RTL when Arabic is selected:
const { dir } = useLanguage()
// Direction is automatically set on document.documentElement
// Use it in your components when needed:
<div dir={dir}>
{/* Content flows correctly in both directions */}
</div>
RTL-Specific Styling
Some components may need direction-specific styles:
<div className={`
flex items-center gap-4
${dir === 'rtl' ? 'flex-row-reverse' : 'flex-row'}
`}>
<Icon />
<span>{t('contacts.name')}</span>
</div>
Integration Checklist
To fully integrate the bilingual system into an existing component:
- Import
useLanguagehook - Replace all hardcoded text with
t('key.path') - Update toast messages with translations
- Add
dirattribute where needed for RTL - Test language switching
- Verify RTL layout doesn't break UI
Example: Complete Component Conversion
Before (Hardcoded)
function ContactCard({ contact }) {
return (
<div>
<h3>Contact Details</h3>
<p>Name: {contact.name}</p>
<p>Email: {contact.email}</p>
<button onClick={handleEdit}>Edit</button>
<button onClick={handleDelete}>Delete</button>
</div>
)
}
After (Bilingual)
function ContactCard({ contact }) {
const { t, dir } = useLanguage()
return (
<div dir={dir}>
<h3>{t('contacts.contactDetails')}</h3>
<p>{t('contacts.name')}: {contact.name}</p>
<p>{t('contacts.email')}: {contact.email}</p>
<button onClick={handleEdit}>{t('common.edit')}</button>
<button onClick={handleDelete}>{t('common.delete')}</button>
</div>
)
}
Testing
- Switch Language: Click the language switcher (EN/AR)
- Verify All Text Changes: Navigate through all pages and check that all text switches
- Check RTL Layout: Verify that Arabic layout flows right-to-left correctly
- Test Forms: Ensure form labels, placeholders, and error messages translate
- Test Notifications: Verify toast messages appear in the correct language
Language Persistence
The selected language is automatically saved to localStorage and persists across sessions.
Best Practices
- Always use translation keys: Never hardcode user-facing text
- Group related translations: Keep related keys in the same object
- Use descriptive keys:
contacts.addButtonis better thanbtn1 - Test both languages: Always verify text fits in both English and Arabic
- Consider text length: Arabic text is often longer than English - design accordingly
- Use semantic HTML: Proper HTML helps with RTL rendering
Common Patterns
Table Headers
<th>{t('contacts.name')}</th>
<th>{t('contacts.email')}</th>
<th>{t('contacts.phone')}</th>
<th>{t('common.actions')}</th>
Status Badges
const statusText = status === 'ACTIVE'
? t('common.active')
: t('common.inactive')
<span className="badge">{statusText}</span>
Confirm Dialogs
const confirmed = window.confirm(t('contacts.deleteConfirm'))
if (confirmed) {
await deleteContact(id)
toast.success(t('contacts.deleteSuccess'))
}
Adding Language Switcher to Dashboard
Add to your navigation component:
import LanguageSwitcher from '@/components/LanguageSwitcher'
function Navigation() {
const { t } = useLanguage()
return (
<nav>
<div className="logo">{t('nav.dashboard')}</div>
<div className="nav-links">
<Link href="/contacts">{t('nav.contacts')}</Link>
<Link href="/crm">{t('nav.crm')}</Link>
{/* ... other links */}
</div>
<LanguageSwitcher />
</nav>
)
}
Troubleshooting
Issue: Text doesn't translate
- Solution: Check the translation key exists in
LanguageContext.tsx
Issue: RTL layout is broken
- Solution: Add
dir={dir}to parent container and check flex directions
Issue: Language doesn't persist
- Solution: Check browser localStorage is enabled
Issue: Translation shows key instead of text
- Solution: Verify the key path is correct (case-sensitive)
Next Steps
- Add the
LanguageSwitchercomponent to your main navigation - Start converting components one by one
- Add any missing translation keys to
LanguageContext.tsx - Test thoroughly in both languages
Note: The translation system is now fully integrated. Every component you create should use the useLanguage() hook and t() function for 100% bilingual support.