https://github.com/streamich/use-t
🗺 Translations with React hooks
https://github.com/streamich/use-t
Last synced: 2 months ago
JSON representation
🗺 Translations with React hooks
- Host: GitHub
- URL: https://github.com/streamich/use-t
- Owner: streamich
- License: unlicense
- Created: 2018-11-06T14:59:28.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2025-08-09T04:09:08.000Z (2 months ago)
- Last Synced: 2025-08-09T06:09:11.240Z (2 months ago)
- Language: TypeScript
- Homepage:
- Size: 728 KB
- Stars: 46
- Watchers: 1
- Forks: 2
- Open Issues: 34
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
- fucking-awesome-react-hooks - `use-t` - language using hooks. (Packages)
- awesome-react-hooks-cn - `use-t` - language using hooks. (Packages)
- awesome-react-hooks - `use-t` - language using hooks. (Packages)
- awesome-react-hooks - `use-t` - language using hooks. (Packages)
README
🗺
use-t
Modern React translations made simple.
**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.
✨ Features
🪝 **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 contextInstallation
Quick Start
### Basic Usage
```jsx
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 (
{t('greeting')}, World!
{t('welcome')}
setLocale(locale === 'en' ? 'es' : 'en')}>
Switch Language
);
};// 3. Wrap your app with Provider
export default () => (
);
```### Function-based Translations
```jsx
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 (
{t('userGreeting', username)}
{t('itemCount', itemCount)}
);
};
```### Template Literal Interpolation
```jsx
const translations = {
en: {
main: {
welcomeMessage: (interpolate) => interpolate`Welcome ${0}, you have ${1} new messages!`
}
}
};const Dashboard = ({user, messageCount}) => {
const [t] = useT();
return (
{/* 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}`}
);
};
```API Reference
```js
import {Provider, useT, withT, Trans, Consumer, context, createTranslations} from 'use-t';
```| Export | Type | Description |
|--------|------|-------------|
| **``** | Component | Context provider for translations |
| **`useT()`** | Hook | React hook returning `[t, state]` |
| **`withT()`** | HOC | Higher-order component injecting `t` and `T` props |
| **``** | Component | Render prop component for translations |
| **``** | Component | Context consumer for provider state |
| **`context`** | Context | React context object |
| **`createTranslations()`** | Function | Create custom translation instances |### `` Props
```jsx
```
### `useT()` Hook
```jsx
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 translation
- `t(key, ...args)` - Function translation with arguments
- `t.t(key)` - Template literal translation**State object:**
- `state.locale` - Current locale
- `state.setLocale(locale)` - Change locale
- `state.load(locale, namespace)` - Preload translationsAdvanced Usage
### Dynamic Loading
```jsx
const Provider = () => {
const loadTranslations = async (locale, namespace) => {
const response = await fetch(`/api/translations/${locale}/${namespace}`);
return response.json();
};return (
);
};
```### Namespaces
```jsx
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 (
{t('save')}
{t('cancel')}
{t('required')}
);
};// Namespace-specific component
const Dashboard = () => {
const [t] = useT('dashboard');
return (
{t('title')}
{t('stats')}
);
};
```### Complex Interpolations
```jsx
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 (
...
{t.t('loginFooter')`
By signing in, you agree to our ${Terms} and ${Privacy Policy}.
`}
);
};const NotificationItem = ({sender, count, type}) => {
const [t] = useT();
return (
{t.t('notification')`
${{sender}} sent you ${count} ${type}
`}
);
};
```### Higher-Order Component
```jsx
import {withT} from 'use-t';const MyComponent = ({t, T, ...otherProps}) => (
{t('title')}
T.setLocale('es')}>
Español
);export default withT(MyComponent);
// Or with specific namespace:
export default withT(MyComponent, 'dashboard');
```### Render Props
```jsx
import {Trans} from 'use-t';const Navigation = () => (
{(t, T) => (
<>
{t('home')}
{t('about')}
T.setLocale('fr')}>
Français
>
)}
);// String shorthand
const Title = () => pageTitle;// Mixed content
const Header = () => (
{t => t('welcome')}!
);
```TypeScript Support
**use-t** is written in TypeScript and provides full type safety:
```tsx
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 = ({t, T}) => (
{t('greeting')}
{t('userWelcome', 'John')}
);
```Best Practices
### Translation Organization
```js
// ✅ 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
}
}
};
```### Performance Tips
```jsx
// ✅ Good: Load namespaces on-demand
const LazyDashboard = () => {
const [t] = useT('dashboard'); // Only loads dashboard namespace
return{t('title')};
};// ✅ Good: Preload critical translations
// ✅ Good: Use default locale as fallback
```
### Error Handling
```jsx
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 (
{/* Shows "Welcome!" or "user.welcome" if missing */}
{t('user.welcome')}
{/* Shows "Save" or "button.save" if missing */}
{t('button.save')}
);
};
```Custom Translation Instances
Create isolated translation contexts for libraries or complex apps:
```jsx
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{t('libMessage')};
};// Use in your app
```
Migration from Other Libraries
### From react-i18next
```jsx
// 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');
```### From React Intl
```jsx
// 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');
```Troubleshooting
**Translation not showing:**
- Check if the key exists in your translation map
- Verify the correct namespace is being used
- Ensure Provider is wrapping your component
- Check browser console for loading errors**Dynamic loading not working:**
- Verify your loader function returns a Promise
- Check network requests in browser dev tools
- Ensure proper error handling in loader**TypeScript errors:**
- Import types: `import type {TranslatorFn} from 'use-t';`
- Check translation map structure matches expected formatDetailed API Documentation
For comprehensive API documentation, see:
- [``](./docs/Provider.md) - Context provider configuration
- [`useT()`](./docs/useT.md) - React hook usage and examples
- [`withT()`](./docs/withT.md) - Higher-order component patterns
- [``](./docs/Trans.md) - Render prop component usage
- [``](./docs/Consumer.md) - Context consumer patterns
- [`context`](./docs/context.md) - Direct context access
- [`createTranslations()`](./docs/createTranslations.md) - Custom instancesLicense
Unlicense — public domain.