use-t is a lightweight, type-safe React internationalization (i18n) library that leverages React hooks and context for seamless translation management. Built with modern React patterns, it provides an intuitive API for handling translations, dynamic loading, namespaces, and complex interpolations.
🪝 Hook-based API — Modern React hooks with useT()
🚀 Zero dependencies — Lightweight and fast
📦 Dynamic loading — Load translations on-demand
🏷️ Namespace support — Organize translations by feature
🔧 Template literals — JSX interpolation with t.t
🌍 Fallback locales — Graceful degradation
📝 TypeScript — Full type safety and IntelliSense
⚡ Multiple APIs — Hooks, HOCs, render props, and context
import {Provider, useT} from 'use-t'; // 1. Define your translations const translations = { en: { main: { greeting: 'Hello', welcome: 'Welcome back!' } }, es: { main: { greeting: 'Hola', welcome: '¡Bienvenido de nuevo!' } } }; // 2. Create a component that uses translations const App = () => { const [t, {setLocale, locale}] = useT(); return ( <div> <h1>{t('greeting')}, World!</h1> <p>{t('welcome')}</p> <button onClick={() => setLocale(locale === 'en' ? 'es' : 'en')}> Switch Language </button> </div> ); }; // 3. Wrap your app with Provider export default () => ( <Provider locale="en" map={translations}> <App /> </Provider> );Function-based Translations
const translations = { en: { main: { userGreeting: (name) => `Hello, ${name}!`, itemCount: (count) => `You have ${count} ${count === 1 ? 'item' : 'items'}` } } }; const UserProfile = ({username, itemCount}) => { const [t] = useT(); return ( <div> <h2>{t('userGreeting', username)}</h2> <p>{t('itemCount', itemCount)}</p> </div> ); };Template Literal Interpolation
const translations = { en: { main: { welcomeMessage: (interpolate) => interpolate`Welcome ${0}, you have ${1} new messages!` } } }; const Dashboard = ({user, messageCount}) => { const [t] = useT(); return ( <div> {/* With translation */} {t.t('welcomeMessage')`Welcome ${user.name}, you have ${messageCount} new messages!`} {/* Fallback if translation missing */} {t.t('missingKey')`Default message with ${user.name}`} </div> ); };
import {Provider, useT, withT, Trans, Consumer, context, createTranslations} from 'use-t';Export Type Description
<Provider>
Component Context provider for translations useT()
Hook React hook returning [t, state]
withT()
HOC Higher-order component injecting t
and T
props <Trans>
Component Render prop component for translations <Consumer>
Component Context consumer for provider state context
Context React context object createTranslations()
Function Create custom translation instances
<Provider locale="en" // Current locale (default: 'en') defaultLocale="en" // Fallback locale (default: 'en') ns="main" // Default namespace (default: 'main') map={translations} // Preloaded translations loader={loadFn} // Dynamic loader function >
const [t, state] = useT(); // Default namespace const [t, state] = useT('errors'); // Single namespace const [t, state] = useT(['main', 'errors']); // Multiple namespaces
Translation function t
:
t(key)
- Simple translationt(key, ...args)
- Function translation with argumentst.t(key)
- Template literal translationState object:
state.locale
- Current localestate.setLocale(locale)
- Change localestate.load(locale, namespace)
- Preload translationsconst Provider = () => { const loadTranslations = async (locale, namespace) => { const response = await fetch(`/api/translations/${locale}/${namespace}`); return response.json(); }; return ( <Provider locale="en" loader={loadTranslations} map={{ en: { main: { loading: 'Loading...' } } // Initial translations }} > <App /> </Provider> ); };
const translations = { en: { common: { save: 'Save', cancel: 'Cancel' }, errors: { required: 'This field is required', invalid: 'Invalid input' }, dashboard: { title: 'Dashboard', stats: 'Statistics' } } }; // Use multiple namespaces const Form = () => { const [t] = useT(['common', 'errors']); return ( <form> <button type="submit">{t('save')}</button> <button type="button">{t('cancel')}</button> <span className="error">{t('required')}</span> </form> ); }; // Namespace-specific component const Dashboard = () => { const [t] = useT('dashboard'); return ( <div> <h1>{t('title')}</h1> <p>{t('stats')}</p> </div> ); };
const translations = { en: { main: { loginFooter: (interpolate) => interpolate` By signing in, you agree to our ${0} and ${1}. `, notification: (interpolate) => interpolate` ${0} sent you ${1} ${2} ` } } }; const LoginForm = () => { const [t] = useT(); return ( <div> <form>...</form> <p> {t.t('loginFooter')` By signing in, you agree to our ${<Link to="/terms">Terms</Link>} and ${<Link to="/privacy">Privacy Policy</Link>}. `} </p> </div> ); }; const NotificationItem = ({sender, count, type}) => { const [t] = useT(); return ( <div> {t.t('notification')` ${<strong>{sender}</strong>} sent you ${count} ${type} `} </div> ); };
import {withT} from 'use-t'; const MyComponent = ({t, T, ...otherProps}) => ( <div> <h1>{t('title')}</h1> <button onClick={() => T.setLocale('es')}> Español </button> </div> ); export default withT(MyComponent); // Or with specific namespace: export default withT(MyComponent, 'dashboard');
import {Trans} from 'use-t'; const Navigation = () => ( <nav> <Trans ns="navigation"> {(t, T) => ( <> <a href="/">{t('home')}</a> <a href="/about">{t('about')}</a> <button onClick={() => T.setLocale('fr')}> Français </button> </> )} </Trans> </nav> ); // String shorthand const Title = () => <Trans>pageTitle</Trans>; // Mixed content const Header = () => ( <Trans> {t => t('welcome')}! </Trans> );
use-t is written in TypeScript and provides full type safety:
import {TranslatorFn, ProviderState, TranslationMap} from 'use-t'; // Type your translations interface Translations { greeting: string; userWelcome: (name: string) => string; itemCount: (count: number) => string; } const translations: TranslationMap = { en: { main: { greeting: 'Hello', userWelcome: (name: string) => `Welcome, ${name}!`, itemCount: (count: number) => `${count} items` } as Translations } }; // Typed component props interface Props { t: TranslatorFn; T: ProviderState; } const MyComponent: React.FC<Props> = ({t, T}) => ( <div> <h1>{t('greeting')}</h1> <p>{t('userWelcome', 'John')}</p> </div> );
// ✅ Good: Organize by feature/page const translations = { en: { auth: { login: 'Log In', signup: 'Sign Up', forgotPassword: 'Forgot Password?' }, dashboard: { welcome: 'Welcome back!', stats: 'Your Statistics' }, common: { save: 'Save', cancel: 'Cancel', loading: 'Loading...' } } }; // ❌ Avoid: All translations in one namespace const translations = { en: { main: { login: 'Log In', dashboardWelcome: 'Welcome back!', saveButton: 'Save', // ... hundreds of keys } } };
// ✅ Good: Load namespaces on-demand const LazyDashboard = () => { const [t] = useT('dashboard'); // Only loads dashboard namespace return <div>{t('title')}</div>; }; // ✅ Good: Preload critical translations <Provider map={{ en: { common: commonTranslations // Critical UI elements } }} loader={dynamicLoader} // Non-critical loaded on-demand > // ✅ Good: Use default locale as fallback <Provider locale="fr" defaultLocale="en" // Falls back to English if French missing map={translations} >
const translations = { en: { main: { // Use descriptive keys that work as fallbacks 'user.welcome': 'Welcome!', 'error.network': 'Network error occurred', 'button.save': 'Save' } } }; // Keys become fallback text if translation missing const Component = () => { const [t] = useT(); return ( <div> {/* Shows "Welcome!" or "user.welcome" if missing */} <h1>{t('user.welcome')}</h1> {/* Shows "Save" or "button.save" if missing */} <button>{t('button.save')}</button> </div> ); };Custom Translation Instances
Create isolated translation contexts for libraries or complex apps:
import {createTranslations} from 'use-t'; // Create custom instance with different default namespace const {Provider: LibProvider, useT: useLibT} = createTranslations('library'); const LibraryComponent = () => { const [t] = useLibT(); return <div>{t('libMessage')}</div>; }; // Use in your app <LibProvider map={{en: {library: {libMessage: 'Hello from library!'}}}}> <LibraryComponent /> </LibProvider>Migration from Other Libraries
// react-i18next import {useTranslation} from 'react-i18next'; const {t, i18n} = useTranslation(); t('key'); i18n.changeLanguage('es'); // use-t equivalent import {useT} from 'use-t'; const [t, {setLocale}] = useT(); t('key'); setLocale('es');
// React Intl import {useIntl} from 'react-intl'; const intl = useIntl(); intl.formatMessage({id: 'key'}); // use-t equivalent import {useT} from 'use-t'; const [t] = useT(); t('key');
Translation not showing:
Dynamic loading not working:
TypeScript errors:
import type {TranslatorFn} from 'use-t';
For comprehensive API documentation, see:
<Provider>
- Context provider configurationuseT()
- React hook usage and exampleswithT()
- Higher-order component patterns<Trans>
- Render prop component usage<Consumer>
- Context consumer patternscontext
- Direct context accesscreateTranslations()
- Custom instancesUnlicense — public domain.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4