Sistema de i18n com TypeScript e intellisense
•10 min de leitura
Implementando internacionalização com tipagem estática que oferece autocomplete completo para todas as chaves de tradução.
TypeScripti18nNext.jsDeveloper Experience
Sistema de i18n com TypeScript e intellisense#
Vou te mostrar como criar um sistema de internacionalização que oferece intellisense completo para todas as chaves de tradução.
O Problema#
Sistemas de i18n tradicionais têm problemas:
- Chaves de tradução são strings "mágicas"
- Sem autocomplete
- Erros só aparecem em runtime
- Refactoring é perigoso
A Solução: TypeScript + Estrutura Inteligente#
1. Estrutura JSON Organizada#
// locales/en.json
{
"common": {
"name": "Gabriel Albuquerque",
"intro": "I'm a developer & designer based in Curitiba, Brazil 🇧🇷"
},
"experiences": {
"title": "Experience",
"exampleCompany": "Example Company",
"exampleCompanyDesc": "Building modern web applications..."
},
"education": {
"title": "Education",
"exampleInstitution": "Example Institution"
}
}
2. Tipos TypeScript Automáticos#
// types/i18n.ts
type Paths<T> = T extends object
? {
[K in keyof T]: K extends string
? T[K] extends object
? `${K}.${Paths<T[K]>}`
: K
: never;
}[keyof T]
: never;
type TranslationKey = Paths<typeof enTranslations>;
// Result: "common.name" | "common.intro" | "experiences.title" | ...
3. Context com Dot Notation#
// contexts/language-context.tsx
function getNestedValue(obj: any, path: string): string {
return path.split(".").reduce((current, key) => current?.[key], obj) || path;
}
const t = (key: TranslationKey): string => {
const translation = translations[language];
return getNestedValue(translation, key);
};
4. Hook Tipado#
export function useLanguage() {
const context = useContext(LanguageContext);
if (!context) {
throw new Error("useLanguage must be used within LanguageProvider");
}
return {
...context,
t: context.t as (key: TranslationKey) => string,
};
}
Resultado: Intellisense Completo!#
// Em qualquer componente:
const { t } = useLanguage();
// ✨ Autocomplete funciona!
t("experiences.title"); // ✅
t("education.exampleInstitution"); // ✅
t("invalid.key"); // ❌ TypeScript error!
Benefícios#
🔧 Developer Experience#
- Autocomplete completo - Vê todas as chaves disponíveis
- Erro em compile time - Chaves inválidas são detectadas
- Refactoring seguro - Find & replace funciona
- Organização clara - Estrutura hierárquica
🚀 Performance#
- Tree shaking - Apenas traduções usadas
- Tipo checking - Zero overhead em runtime
- Estrutura eficiente - Acesso O(1) com dot notation
Implementação Avançada#
1. Suporte a Plurais#
type PluralKey = {
one: string;
other: string;
};
// Usage: t('items.count', { count: 5 })
2. Interpolação#
const t = (key: TranslationKey, vars?: Record<string, string>): string => {
let translation = getNestedValue(translations[language], key);
if (vars) {
Object.entries(vars).forEach(([key, value]) => {
translation = translation.replace(`{{${key}}}`, value);
});
}
return translation;
};
3. Fallback Inteligente#
const getNestedValue = (obj: any, path: string): string => {
const value = path.split(".").reduce((current, key) => current?.[key], obj);
if (!value && language !== "en") {
// Fallback to English
return getNestedValue(translations.en, path);
}
return value || path;
};
Conclusão#
Esse sistema transforma i18n de uma tarefa propensa a erros em uma experiência de desenvolvimento fluida e segura.
Key takeaways:
- TypeScript pode ser usado para criar sistemas type-safe incríveis
- Dot notation + nested objects = organização perfeita
- Developer experience importa tanto quanto user experience
Agora toda vez que você digitar t(' vai ver todas as opções disponíveis. É mágico! ✨