← Back to list

i18n-patterns
by zzoohub
diet-diary & sharing app made with react-native
⭐ 0🍴 0📅 Jan 23, 2026
SKILL.md
name: i18n-patterns description: | Internationalization patterns for web and mobile apps. Use when: adding multi-language support, translation structure, language switching. Do not use for: general React/Next.js patterns (use nextjs, expo-react-native skills). Workflow: Use alongside nextjs or expo-react-native skill.
i18n Patterns
For latest APIs, use context7.
| Platform | Library |
|---|---|
| React / React Native | react-i18next |
| Next.js App Router | next-intl |
File Structure
locales/
├── en/
│ ├── common.json
│ ├── auth.json
│ └── errors.json
└── ko/
├── common.json
├── auth.json
└── errors.json
Rule: Split by domain, not by page. One namespace per feature.
// ✅ Good - hierarchical by feature
{
"login": { "title": "Sign In", "submit": "Sign In" },
"register": { "title": "Sign Up", "submit": "Create Account" }
}
// ❌ Bad - flat
{
"loginTitle": "Sign In",
"loginSubmit": "Sign In"
}
Type-Safe Translations
// types/i18n.ts
export interface AuthTranslations {
login: { title: string; submit: string };
register: { title: string; submit: string };
}
// Nested key path utility
type KeyPath<T> = T extends object
? { [K in keyof T]: K extends string
? T[K] extends object ? `${K}.${KeyPath<T[K]>}` : K
: never
}[keyof T]
: never;
export type AuthKeys = KeyPath<AuthTranslations>;
// Result: "login.title" | "login.submit" | "register.title" | "register.submit"
Domain-Specific Hooks
Rule: Create typed hooks per domain. Don't use raw t() everywhere.
// hooks/useAuthI18n.ts
export const useAuthI18n = () => {
const { t } = useTranslation('auth');
return useMemo(() => ({
login: {
title: t('login.title'),
submit: t('login.submit'),
},
register: {
title: t('register.title'),
submit: t('register.submit'),
},
}), [t]);
};
// Usage - clean and typed
function LoginForm() {
const { login } = useAuthI18n();
return <h1>{login.title}</h1>;
}
Formatting Hook
// hooks/useFormat.ts
export const useFormat = () => {
const { i18n } = useTranslation();
const lang = i18n.language;
return useMemo(() => ({
number: (v: number) =>
new Intl.NumberFormat(lang).format(v),
currency: (v: number, currency = 'USD') =>
new Intl.NumberFormat(lang, { style: 'currency', currency }).format(v),
date: (d: Date, options?: Intl.DateTimeFormatOptions) =>
new Intl.DateTimeFormat(lang, {
year: 'numeric', month: 'short', day: 'numeric',
...options
}).format(d),
relativeTime: (d: Date) => {
const diff = Math.floor((Date.now() - d.getTime()) / 1000);
const rtf = new Intl.RelativeTimeFormat(lang, { numeric: 'auto' });
if (diff < 60) return rtf.format(-diff, 'second');
if (diff < 3600) return rtf.format(-Math.floor(diff / 60), 'minute');
if (diff < 86400) return rtf.format(-Math.floor(diff / 3600), 'hour');
return rtf.format(-Math.floor(diff / 86400), 'day');
},
}), [lang]);
};
Pluralization
// en/common.json
{
"items_zero": "No items",
"items_one": "{{count}} item",
"items_other": "{{count}} items"
}
t('items', { count: 0 }) // "No items"
t('items', { count: 1 }) // "1 item"
t('items', { count: 5 }) // "5 items"
Language Config
// config/languages.ts
export const LANGUAGES = [
{ code: 'en', name: 'English', dir: 'ltr' },
{ code: 'ko', name: '한국어', dir: 'ltr' },
{ code: 'ar', name: 'العربية', dir: 'rtl' },
] as const;
export type LanguageCode = (typeof LANGUAGES)[number]['code'];
export const isRTL = (code: string) =>
LANGUAGES.find(l => l.code === code)?.dir === 'rtl';
Next.js App Router (next-intl)
For setup and configuration, see next-intl docs.
Pattern:
// Server Component
const t = await getTranslations('namespace');
// Client Component
const t = useTranslations('namespace');
Rule: Use getTranslations in Server Components, useTranslations in Client Components.
Quick Checklist
- Translations split by domain (auth, common, errors)
- Type-safe keys with KeyPath utility
- Domain-specific hooks (useAuthI18n, useCommonI18n)
- Using Intl APIs for formatting (not moment/dayjs for dates)
- Pluralization rules defined (_zero, _one, _other)
- RTL support if needed
Score
Total Score
40/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
Reviews
💬
Reviews coming soon