The Game-Changer for i18next & TypeScript: Introducing the Selector API!
A couple of years ago, we wrote about getting the most out of i18next with TypeScript. Today, that story gets a revolutionary new chapter. We’re excited to announce a new feature that fundamentally improves the developer experience: the selector API.
This feature, which closes a couple of long-standing TypeScript issues, was born from a brilliant idea and a monumental effort by Andrew Jarrett. It’s now available in the latest versions of i18next and react-i18next, and it’s about to change the way you work with your translations.
Why a Selector API?
If you’ve worked with a lot of translations with i18next and TypeScript, you’re maybe familiar with the challenges. String-based keys like 'my.nested.key' may lack autocompletion and can make navigating from your code to the translation file tedious.
The new selector API solves all of this.
Instead of a string, you now pass a function to t:
// Before
i18next.t('my.nested.key')
// After
i18next.t(($) => $.my.nested.key)This seemingly small change unlocks a massive suite of benefits.
Unparalleled Developer Experience
- Autocompletion & discoverability: Your IDE now understands your translation structure. No more guessing keys or keeping a translation file open on a second monitor.
- “Go to definition” just works: Jump from a translation’s usage in code directly to its definition in your resource file.
- No more “doom scrolling”: Explore your translations one level at a time, making it effortless to find what you need—even in huge projects.
- Preserved JSDoc comments: Comments/annotations you’ve written for translations can show up right at the call site for immediate context.
Type-Level Performance (Finally) 🚀
A major pain point for projects with large translation files was performance. The type-level overhead could slow down IDEs to a crawl and even crash the TypeScript compiler.
The selector API tackles this by changing how types are computed.
- With
enableSelector: true, you should see improved type-level performance. - For massive projects,
enableSelector: 'optimize'is a game-changer.
This means i18next can handle arbitrarily large translation sets with snappy IDE performance and without build-time type errors.
How to Get Started
Ready to upgrade? Here’s what you need to know.
1. Enable the Feature
In your TypeScript i18next configuration, add the enableSelector option:
// i18next.d.ts
import 'i18next'
declare module 'i18next' {
interface CustomTypeOptions {
enableSelector: true // <- enable it here (or 'optimize')
// ...
// custom namespace type, if you changed it
defaultNS: 'ns1'
// custom resources type
resources: {
ns1: typeof ns1
ns2: typeof ns2
}
// other
}
}2. Migrate Your Code (The Easy Way)
The best part: there’s a codemod to automate the migration for you.
Andrew Jarrett built @i18next-selector/codemod to handle the syntax changes automatically. If your codebase is large, using the codemod is the smoothest way to transition.
3. Manual Migration Guide
If you prefer to migrate manually, here are the key changes to be aware of.
Namespaces: the namespace is now an explicit option.
// BEFORE:
t('a.b.c', { ns: 'myNamespace' })
// or: t('myNamespace:a.b.c')
// AFTER:
t(($) => $.a.b.c, { ns: 'myNamespace' })Default values: defaultValue now lives in the options object.
// BEFORE:
t('a.b.c', 'some default value')
// AFTER:
t(($) => $.a.b.c, { defaultValue: 'some default value' })Key fallbacks: instead of passing an array of keys, provide fallbacks via defaultValue by calling t again.
// BEFORE:
t(['error.404', 'error.unspecific'])
// AFTER:
t(($) => $.error['404'], { defaultValue: t(($) => $.error.unspecific) })A Massive Thank You to the Community
This feature wouldn’t have been possible without the passion and dedication of several key individuals.
First and foremost, a massive thank you to Andrew Jarrett. He not only proposed the initial idea but also implemented the entire feature, wrote the codemod for migration, and updated the documentation.
A special thanks also goes to Marco Pasqualetti, who provided extensive feedback and thoroughly tested the new API.
And finally, thank you to the entire i18next community for your continued support.
Update to the latest versions of i18next and react-i18next to give it a try.