I18N QUICK REFERENCE - nself-org/nchat GitHub Wiki
Quick reference for using i18n features in nself-chat
import { useI18n } from '@/hooks/use-i18n'
function MyComponent() {
const { t, locale, setLocale } = useI18n()
return (
<div>
<h1>{t('app.name')}</h1>
<button onClick={() => setLocale('es')}>
Switch to Spanish
</button>
</div>
)
}const { t } = useI18n()
// Simple interpolation
t('notifications.newMessage', { sender: 'Alice' })
// → "New message from Alice"
// With count (pluralization)
t('time.minutes', { count: 5 })
// → "5 minutes"import { useDateFormat } from '@/hooks/use-i18n'
function DateDisplay({ date }) {
const { formatDate, formatRelativeTime } = useDateFormat()
return (
<div>
{/* Full date */}
<p>{formatDate(date, { dateStyle: 'full' })}</p>
{/* Relative time */}
<time>{formatRelativeTime(date)}</time>
</div>
)
}import { useNumberFormat } from '@/hooks/use-i18n'
function PriceTag({ amount }) {
const { formatCurrency, formatNumber, formatPercent } = useNumberFormat()
return (
<div>
<p>{formatCurrency(amount, 'USD')}</p>
<p>{formatNumber(1000000)}</p>
<p>{formatPercent(0.15, 2)}</p>
</div>
)
}import { useRTL } from '@/hooks/use-i18n'
function Layout({ children }) {
const isRTL = useRTL()
return (
<div className={isRTL ? 'flex-row-reverse' : 'flex-row'}>
{children}
</div>
)
}import { useI18n } from '@/hooks/use-i18n'
import { LOCALE_CODES, getLocaleConfig } from '@/lib/i18n/locales'
function LanguageSwitcher() {
const { locale, setLocale } = useI18n()
return (
<select value={locale} onChange={(e) => setLocale(e.target.value)}>
{LOCALE_CODES.map((code) => {
const config = getLocaleConfig(code)
return (
<option key={code} value={code}>
{config?.flag} {config?.name}
</option>
)
})}
</select>
)
}// Navigation
t('nav.home') // "Home"
t('nav.chat') // "Chat"
t('nav.settings') // "Settings"
// Auth
t('auth.signIn') // "Sign In"
t('auth.signUp') // "Sign Up"
t('auth.logout') // "Logout"
// Common actions
t('common.save') // "Save"
t('common.cancel') // "Cancel"
t('common.delete') // "Delete"
t('common.edit') // "Edit"
// Chat
t('chat.newMessage') // "New Message"
t('chat.typeMessage') // "Type a message..."
t('chat.send') // "Send"
// Time
t('time.now') // "Now"
t('time.today') // "Today"
t('time.yesterday') // "Yesterday"
// Errors
t('errors.somethingWentWrong') // "Something went wrong"
t('errors.tryAgain') // "Try again"| Flag | Code | Language | Direction |
|---|---|---|---|
| 🇺🇸 | en | English | LTR |
| 🇪🇸 | es | Spanish | LTR |
| 🇫🇷 | fr | French | LTR |
| 🇩🇪 | de | German | LTR |
| 🇸🇦 | ar | Arabic | RTL |
| 🇨🇳 | zh | Chinese (Simplified) | LTR |
| 🇹🇼 | zh-TW | Chinese (Traditional) | LTR |
| 🇯🇵 | ja | Japanese | LTR |
| 🇰🇷 | ko | Korean | LTR |
| 🇧🇷 | pt | Portuguese | LTR |
| 🇷🇺 | ru | Russian | LTR |
| 🇮🇹 | it | Italian | LTR |
| 🇳🇱 | nl | Dutch | LTR |
| 🇵🇱 | pl | Polish | LTR |
| 🇹🇷 | tr | Turkish | LTR |
| 🇸🇪 | sv | Swedish | LTR |
| 🇮🇱 | he | Hebrew | RTL |
| 🇹🇭 | th | Thai | LTR |
| 🇻🇳 | vi | Vietnamese | LTR |
| 🇮🇩 | id | Indonesian | LTR |
| 🇨🇿 | cs | Czech | LTR |
| 🇩🇰 | da | Danish | LTR |
| 🇫🇮 | fi | Finnish | LTR |
| 🇳🇴 | no | Norwegian | LTR |
| 🇬🇷 | el | Greek | LTR |
| 🇭🇺 | hu | Hungarian | LTR |
| 🇷🇴 | ro | Romanian | LTR |
| 🇺🇦 | uk | Ukrainian | LTR |
| 🇮🇳 | hi | Hindi | LTR |
| 🇧🇩 | bn | Bengali | LTR |
| 🇮🇷 | fa | Persian | RTL |
| 🇲🇾 | ms | Malay | LTR |
| 🇮🇳 | ta | Tamil | LTR |
/* Use these for RTL-aware styling */
.rtl-ml-auto /* margin-inline-start: auto */
.rtl-mr-auto /* margin-inline-end: auto */
.rtl-pl-4 /* padding-inline-start: 1rem */
.rtl-pr-4 /* padding-inline-end: 1rem */
/* Flip icons in RTL */
.rtl-flip /* transform: scaleX(-1) in RTL */-
Add to English file (
public/locales/en/common.json):
{
"myFeature": {
"title": "My Feature",
"description": "This is my feature"
}
}- Use in component:
const { t } = useI18n()
<h1>{t('myFeature.title')}</h1>- Translate to other languages:
# Copy to all locales
for lang in es fr de ar zh ja pt ru; do
cp public/locales/en/common.json public/locales/$lang/common.json
done
# Edit each file and translate- Validate:
pnpm tsx scripts/validate-translations.ts- Always use translation keys, never hardcoded text:
// Good ✅
<button>{t('common.save')}</button>
// Bad ❌
<button>Save</button>- Provide context for translators:
{
"button": {
"_comment": "This button saves the form",
"save": "Save"
}
}- Use namespaces for organization:
// common.json - general UI
// auth.json - authentication
// chat.json - chat features
// errors.json - error messages- Handle plurals correctly:
{
"message": "{{count}} message",
"message_plural": "{{count}} messages"
}- Keep keys organized:
{
"feature": {
"title": "Title",
"subtitle": "Subtitle",
"actions": {
"save": "Save",
"cancel": "Cancel"
}
}
}// Check if key exists
const { t, i18n } = useI18n()
console.log(i18n.exists('my.key'))
// Check current language
console.log(i18n.language)
// Force reload
i18n.reloadResources()// Check if RTL is detected
import { isRTL } from '@/lib/i18n/config'
console.log(isRTL())
// Check HTML attributes
console.log(document.documentElement.dir)
console.log(document.documentElement.lang)// Check locale config
import { getLocaleConfig } from '@/lib/i18n/locales'
const config = getLocaleConfig('ar')
console.log(config.dateFnsLocale)
console.log(config.numberLocale)- Full docs:
/docs/I18N-ACCESSIBILITY-IMPLEMENTATION.md - Locale config:
/src/lib/i18n/locales.ts - i18n config:
/src/lib/i18n/config.ts - Translation files:
/public/locales/ - Validation:
/scripts/validate-translations.ts