npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

use-t

v1.6.4

Published

React translations

Downloads

1,775

Readme

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

Basic Usage

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> Props

<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
>

useT() Hook

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 translations

Dynamic Loading

const 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>
  );
};

Namespaces

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>
  );
};

Complex Interpolations

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>
  );
};

Higher-Order Component

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');

Render Props

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>
);

Translation Organization

// ✅ 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

// ✅ 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}
>

Error Handling

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>
  );
};

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>

From react-i18next

// 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

// 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:

  • 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 format

For comprehensive API documentation, see: