Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

🗺 Translations with React hooks

License

NotificationsYou must be signed in to change notification settings

streamich/use-t

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

92 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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 withuseT()
🚀Zero dependencies — Lightweight and fast
📦Dynamic loading — Load translations on-demand
🏷️Namespace support — Organize translations by feature
🔧Template literals — JSX interpolation witht.t
🌍Fallback locales — Graceful degradation
📝TypeScript — Full type safety and IntelliSense
Multiple APIs — Hooks, HOCs, render props, and context

Installation

npm iuse-t

Quick Start

Basic Usage

import{Provider,useT}from'use-t';// 1. Define your translationsconsttranslations={en:{main:{greeting:'Hello',welcome:'Welcome back!'}},es:{main:{greeting:'Hola',welcome:'¡Bienvenido de nuevo!'}}};// 2. Create a component that uses translationsconstApp=()=>{const[t,{setLocale, locale}]=useT();return(<div><h1>{t('greeting')}, World!</h1><p>{t('welcome')}</p><buttononClick={()=>setLocale(locale==='en' ?'es' :'en')}>        Switch Language</button></div>);};// 3. Wrap your app with Providerexportdefault()=>(<Providerlocale="en"map={translations}><App/></Provider>);

Function-based Translations

consttranslations={en:{main:{userGreeting:(name)=>`Hello,${name}!`,itemCount:(count)=>`You have${count}${count===1 ?'item' :'items'}`}}};constUserProfile=({username, itemCount})=>{const[t]=useT();return(<div><h2>{t('userGreeting',username)}</h2><p>{t('itemCount',itemCount)}</p></div>);};

Template Literal Interpolation

consttranslations={en:{main:{welcomeMessage:(interpolate)=>interpolate`Welcome${0}, you have${1} new messages!`}}};constDashboard=({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>);};

API Reference

import{Provider,useT,withT,Trans,Consumer,context,createTranslations}from'use-t';
ExportTypeDescription
<Provider>ComponentContext provider for translations
useT()HookReact hook returning[t, state]
withT()HOCHigher-order component injectingt andT props
<Trans>ComponentRender prop component for translations
<Consumer>ComponentContext consumer for provider state
contextContextReact context object
createTranslations()FunctionCreate custom translation instances

<Provider> Props

<Providerlocale="en"// Current locale (default: 'en')defaultLocale="en"// Fallback locale (default: 'en')ns="main"// Default namespace (default: 'main')map={translations}// Preloaded translationsloader={loadFn}// Dynamic loader function>

useT() Hook

const[t,state]=useT();// Default namespaceconst[t,state]=useT('errors');// Single namespaceconst[t,state]=useT(['main','errors']);// Multiple namespaces

Translation functiont:

  • 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

Advanced Usage

Dynamic Loading

constProvider=()=>{constloadTranslations=async(locale,namespace)=>{constresponse=awaitfetch(`/api/translations/${locale}/${namespace}`);returnresponse.json();};return(<Providerlocale="en"loader={loadTranslations}map={{en:{main:{loading:'Loading...'}}// Initial translations}}><App/></Provider>);};

Namespaces

consttranslations={en:{common:{save:'Save',cancel:'Cancel'},errors:{required:'This field is required',invalid:'Invalid input'},dashboard:{title:'Dashboard',stats:'Statistics'}}};// Use multiple namespacesconstForm=()=>{const[t]=useT(['common','errors']);return(<form><buttontype="submit">{t('save')}</button><buttontype="button">{t('cancel')}</button><spanclassName="error">{t('required')}</span></form>);};// Namespace-specific componentconstDashboard=()=>{const[t]=useT('dashboard');return(<div><h1>{t('title')}</h1><p>{t('stats')}</p></div>);};

Complex Interpolations

consttranslations={en:{main:{loginFooter:(interpolate)=>interpolate`        By signing in, you agree to our${0} and${1}.      `,notification:(interpolate)=>interpolate`${0} sent you${1}${2}      `}}};constLoginForm=()=>{const[t]=useT();return(<div><form>...</form><p>{t.t('loginFooter')`          By signing in, you agree to our${<Linkto="/terms">Terms</Link>} and${<Linkto="/privacy">Privacy Policy</Link>}.        `}</p></div>);};constNotificationItem=({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';constMyComponent=({t, T, ...otherProps})=>(<div><h1>{t('title')}</h1><buttononClick={()=>T.setLocale('es')}>      Español</button></div>);exportdefaultwithT(MyComponent);// Or with specific namespace:exportdefaultwithT(MyComponent,'dashboard');

Render Props

import{Trans}from'use-t';constNavigation=()=>(<nav><Transns="navigation">{(t,T)=>(<><ahref="/">{t('home')}</a><ahref="/about">{t('about')}</a><buttononClick={()=>T.setLocale('fr')}>            Français</button></>)}</Trans></nav>);// String shorthandconstTitle=()=><Trans>pageTitle</Trans>;// Mixed contentconstHeader=()=>(<Trans>{t=>t('welcome')}!</Trans>);

TypeScript Support

use-t is written in TypeScript and provides full type safety:

import{TranslatorFn,ProviderState,TranslationMap}from'use-t';// Type your translationsinterfaceTranslations{greeting:string;userWelcome:(name:string)=>string;itemCount:(count:number)=>string;}consttranslations:TranslationMap={en:{main:{greeting:'Hello',userWelcome:(name:string)=>`Welcome,${name}!`,itemCount:(count:number)=>`${count} items`}asTranslations}};// Typed component propsinterfaceProps{t:TranslatorFn;T:ProviderState;}constMyComponent:React.FC<Props>=({t, T})=>(<div><h1>{t('greeting')}</h1><p>{t('userWelcome','John')}</p></div>);

Best Practices

Translation Organization

// ✅ Good: Organize by feature/pageconsttranslations={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 namespaceconsttranslations={en:{main:{login:'Log In',dashboardWelcome:'Welcome back!',saveButton:'Save',// ... hundreds of keys}}};

Performance Tips

// ✅ Good: Load namespaces on-demandconstLazyDashboard=()=>{const[t]=useT('dashboard');// Only loads dashboard namespacereturn<div>{t('title')}</div>;};// ✅ Good: Preload critical translations<Providermap={{en:{common:commonTranslations// Critical UI elements}}}loader={dynamicLoader}// Non-critical loaded on-demand>// ✅ Good: Use default locale as fallback<Providerlocale="fr"defaultLocale="en"// Falls back to English if French missingmap={translations}>

Error Handling

consttranslations={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 missingconstComponent=()=>{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 namespaceconst{Provider:LibProvider,useT:useLibT}=createTranslations('library');constLibraryComponent=()=>{const[t]=useLibT();return<div>{t('libMessage')}</div>;};// Use in your app<LibProvidermap={{en:{library:{libMessage:'Hello from library!'}}}}><LibraryComponent/></LibProvider>

Migration from Other Libraries

From react-i18next

// react-i18nextimport{useTranslation}from'react-i18next';const{t, i18n}=useTranslation();t('key');i18n.changeLanguage('es');// use-t equivalentimport{useT}from'use-t';const[t,{setLocale}]=useT();t('key');setLocale('es');

From React Intl

// React Intlimport{useIntl}from'react-intl';constintl=useIntl();intl.formatMessage({id:'key'});// use-t equivalentimport{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 format

Detailed API Documentation

For comprehensive API documentation, see:

License

Unlicense — public domain.

About

🗺 Translations with React hooks

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Contributors4

  •  
  •  
  •  
  •  

[8]ページ先頭

©2009-2025 Movatter.jp