{"id":13450887,"url":"https://github.com/streamich/use-t","last_synced_at":"2025-08-12T08:06:23.837Z","repository":{"id":33282640,"uuid":"156400579","full_name":"streamich/use-t","owner":"streamich","description":"🗺 Translations with React hooks","archived":false,"fork":false,"pushed_at":"2025-08-09T04:09:08.000Z","size":745,"stargazers_count":46,"open_issues_count":34,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-09T06:09:11.240Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/streamich.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"streamich"}},"created_at":"2018-11-06T14:59:28.000Z","updated_at":"2025-08-03T20:10:47.000Z","dependencies_parsed_at":"2024-10-11T23:32:46.381Z","dependency_job_id":"e09523fd-e376-4f39-8669-3d5a6264e3ef","html_url":"https://github.com/streamich/use-t","commit_stats":{"total_commits":67,"total_committers":4,"mean_commits":16.75,"dds":"0.26865671641791045","last_synced_commit":"5e32613e4a44a1c9d92e7da481d2f9a469d7a0dd"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/streamich/use-t","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamich%2Fuse-t","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamich%2Fuse-t/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamich%2Fuse-t/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamich%2Fuse-t/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/streamich","download_url":"https://codeload.github.com/streamich/use-t/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamich%2Fuse-t/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269734044,"owners_count":24466545,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-10T02:00:08.965Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T07:00:39.833Z","updated_at":"2025-08-12T08:06:23.829Z","avatar_url":"https://github.com/streamich.png","language":"TypeScript","readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003e\n    \u003cbr/\u003e\n    \u003cbr/\u003e\n    🗺\n    \u003cbr /\u003e\n    use-t\n  \u003c/h1\u003e\n  \u003csup\u003eModern React translations made simple.\u003c/sup\u003e\n  \u003cbr /\u003e\n  \u003cbr /\u003e\n  \u003cbr /\u003e\n  \u003cbr /\u003e\n\u003c/div\u003e\n\n**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.\n\n\u003ch2 align=\"center\"\u003e✨ Features\u003c/h2\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n🪝 **Hook-based API** \u0026mdash; Modern React hooks with `useT()`  \n🚀 **Zero dependencies** \u0026mdash; Lightweight and fast  \n📦 **Dynamic loading** \u0026mdash; Load translations on-demand  \n🏷️ **Namespace support** \u0026mdash; Organize translations by feature  \n🔧 **Template literals** \u0026mdash; JSX interpolation with `t.t`  \n🌍 **Fallback locales** \u0026mdash; Graceful degradation  \n📝 **TypeScript** \u0026mdash; Full type safety and IntelliSense  \n⚡ **Multiple APIs** \u0026mdash; Hooks, HOCs, render props, and context\n\n\u003c/div\u003e\n\n\u003ch2 align=\"center\"\u003eInstallation\u003c/h2\u003e\n\u003cdiv align=\"center\"\u003e\n\u003cpre\u003enpm i \u003ca href=\"https://www.npmjs.com/package/use-t\"\u003euse-t\u003c/a\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003ch2 align=\"center\"\u003eQuick Start\u003c/h2\u003e\n\n### Basic Usage\n\n```jsx\nimport {Provider, useT} from 'use-t';\n\n// 1. Define your translations\nconst translations = {\n  en: {\n    main: {\n      greeting: 'Hello',\n      welcome: 'Welcome back!'\n    }\n  },\n  es: {\n    main: {\n      greeting: 'Hola',\n      welcome: '¡Bienvenido de nuevo!'\n    }\n  }\n};\n\n// 2. Create a component that uses translations\nconst App = () =\u003e {\n  const [t, {setLocale, locale}] = useT();\n  \n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003e{t('greeting')}, World!\u003c/h1\u003e\n      \u003cp\u003e{t('welcome')}\u003c/p\u003e\n      \n      \u003cbutton onClick={() =\u003e setLocale(locale === 'en' ? 'es' : 'en')}\u003e\n        Switch Language\n      \u003c/button\u003e\n    \u003c/div\u003e\n  );\n};\n\n// 3. Wrap your app with Provider\nexport default () =\u003e (\n  \u003cProvider locale=\"en\" map={translations}\u003e\n    \u003cApp /\u003e\n  \u003c/Provider\u003e\n);\n```\n\n### Function-based Translations\n\n```jsx\nconst translations = {\n  en: {\n    main: {\n      userGreeting: (name) =\u003e `Hello, ${name}!`,\n      itemCount: (count) =\u003e `You have ${count} ${count === 1 ? 'item' : 'items'}`\n    }\n  }\n};\n\nconst UserProfile = ({username, itemCount}) =\u003e {\n  const [t] = useT();\n  \n  return (\n    \u003cdiv\u003e\n      \u003ch2\u003e{t('userGreeting', username)}\u003c/h2\u003e\n      \u003cp\u003e{t('itemCount', itemCount)}\u003c/p\u003e\n    \u003c/div\u003e\n  );\n};\n```\n\n### Template Literal Interpolation\n\n```jsx\nconst translations = {\n  en: {\n    main: {\n      welcomeMessage: (interpolate) =\u003e interpolate`Welcome ${0}, you have ${1} new messages!`\n    }\n  }\n};\n\nconst Dashboard = ({user, messageCount}) =\u003e {\n  const [t] = useT();\n  \n  return (\n    \u003cdiv\u003e\n      {/* With translation */}\n      {t.t('welcomeMessage')`Welcome ${user.name}, you have ${messageCount} new messages!`}\n      \n      {/* Fallback if translation missing */}\n      {t.t('missingKey')`Default message with ${user.name}`}\n    \u003c/div\u003e\n  );\n};\n```\n\n\u003ch2 align=\"center\"\u003eAPI Reference\u003c/h2\u003e\n\n```js\nimport {Provider, useT, withT, Trans, Consumer, context, createTranslations} from 'use-t';\n```\n\n| Export | Type | Description |\n|--------|------|-------------|\n| **`\u003cProvider\u003e`** | Component | Context provider for translations |\n| **`useT()`** | Hook | React hook returning `[t, state]` |\n| **`withT()`** | HOC | Higher-order component injecting `t` and `T` props |\n| **`\u003cTrans\u003e`** | Component | Render prop component for translations |\n| **`\u003cConsumer\u003e`** | Component | Context consumer for provider state |\n| **`context`** | Context | React context object |\n| **`createTranslations()`** | Function | Create custom translation instances |\n\n### `\u003cProvider\u003e` Props\n\n```jsx\n\u003cProvider\n  locale=\"en\"           // Current locale (default: 'en')\n  defaultLocale=\"en\"    // Fallback locale (default: 'en')  \n  ns=\"main\"            // Default namespace (default: 'main')\n  map={translations}    // Preloaded translations\n  loader={loadFn}      // Dynamic loader function\n\u003e\n```\n\n### `useT()` Hook\n\n```jsx\nconst [t, state] = useT();                    // Default namespace\nconst [t, state] = useT('errors');           // Single namespace\nconst [t, state] = useT(['main', 'errors']); // Multiple namespaces\n```\n\n**Translation function `t`:**\n- `t(key)` - Simple translation\n- `t(key, ...args)` - Function translation with arguments\n- `t.t(key)` - Template literal translation\n\n**State object:**\n- `state.locale` - Current locale\n- `state.setLocale(locale)` - Change locale\n- `state.load(locale, namespace)` - Preload translations\n\n\u003ch2 align=\"center\"\u003eAdvanced Usage\u003c/h2\u003e\n\n### Dynamic Loading\n\n```jsx\nconst Provider = () =\u003e {\n  const loadTranslations = async (locale, namespace) =\u003e {\n    const response = await fetch(`/api/translations/${locale}/${namespace}`);\n    return response.json();\n  };\n\n  return (\n    \u003cProvider \n      locale=\"en\"\n      loader={loadTranslations}\n      map={{\n        en: { main: { loading: 'Loading...' } } // Initial translations\n      }}\n    \u003e\n      \u003cApp /\u003e\n    \u003c/Provider\u003e\n  );\n};\n```\n\n### Namespaces\n\n```jsx\nconst translations = {\n  en: {\n    common: {\n      save: 'Save',\n      cancel: 'Cancel'\n    },\n    errors: {\n      required: 'This field is required',\n      invalid: 'Invalid input'\n    },\n    dashboard: {\n      title: 'Dashboard',\n      stats: 'Statistics'\n    }\n  }\n};\n\n// Use multiple namespaces\nconst Form = () =\u003e {\n  const [t] = useT(['common', 'errors']);\n  \n  return (\n    \u003cform\u003e\n      \u003cbutton type=\"submit\"\u003e{t('save')}\u003c/button\u003e\n      \u003cbutton type=\"button\"\u003e{t('cancel')}\u003c/button\u003e\n      \u003cspan className=\"error\"\u003e{t('required')}\u003c/span\u003e\n    \u003c/form\u003e\n  );\n};\n\n// Namespace-specific component\nconst Dashboard = () =\u003e {\n  const [t] = useT('dashboard');\n  \n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003e{t('title')}\u003c/h1\u003e\n      \u003cp\u003e{t('stats')}\u003c/p\u003e\n    \u003c/div\u003e\n  );\n};\n```\n\n### Complex Interpolations\n\n```jsx\nconst translations = {\n  en: {\n    main: {\n      loginFooter: (interpolate) =\u003e interpolate`\n        By signing in, you agree to our ${0} and ${1}.\n      `,\n      notification: (interpolate) =\u003e interpolate`\n        ${0} sent you ${1} ${2}\n      `\n    }\n  }\n};\n\nconst LoginForm = () =\u003e {\n  const [t] = useT();\n  \n  return (\n    \u003cdiv\u003e\n      \u003cform\u003e...\u003c/form\u003e\n      \u003cp\u003e\n        {t.t('loginFooter')`\n          By signing in, you agree to our ${\u003cLink to=\"/terms\"\u003eTerms\u003c/Link\u003e} and ${\u003cLink to=\"/privacy\"\u003ePrivacy Policy\u003c/Link\u003e}.\n        `}\n      \u003c/p\u003e\n    \u003c/div\u003e\n  );\n};\n\nconst NotificationItem = ({sender, count, type}) =\u003e {\n  const [t] = useT();\n  \n  return (\n    \u003cdiv\u003e\n      {t.t('notification')`\n        ${\u003cstrong\u003e{sender}\u003c/strong\u003e} sent you ${count} ${type}\n      `}\n    \u003c/div\u003e\n  );\n};\n```\n\n### Higher-Order Component\n\n```jsx\nimport {withT} from 'use-t';\n\nconst MyComponent = ({t, T, ...otherProps}) =\u003e (\n  \u003cdiv\u003e\n    \u003ch1\u003e{t('title')}\u003c/h1\u003e\n    \u003cbutton onClick={() =\u003e T.setLocale('es')}\u003e\n      Español\n    \u003c/button\u003e\n  \u003c/div\u003e\n);\n\nexport default withT(MyComponent);\n// Or with specific namespace:\nexport default withT(MyComponent, 'dashboard');\n```\n\n### Render Props\n\n```jsx\nimport {Trans} from 'use-t';\n\nconst Navigation = () =\u003e (\n  \u003cnav\u003e\n    \u003cTrans ns=\"navigation\"\u003e\n      {(t, T) =\u003e (\n        \u003c\u003e\n          \u003ca href=\"/\"\u003e{t('home')}\u003c/a\u003e\n          \u003ca href=\"/about\"\u003e{t('about')}\u003c/a\u003e\n          \u003cbutton onClick={() =\u003e T.setLocale('fr')}\u003e\n            Français\n          \u003c/button\u003e\n        \u003c/\u003e\n      )}\n    \u003c/Trans\u003e\n  \u003c/nav\u003e\n);\n\n// String shorthand\nconst Title = () =\u003e \u003cTrans\u003epageTitle\u003c/Trans\u003e;\n\n// Mixed content\nconst Header = () =\u003e (\n  \u003cTrans\u003e\n    {t =\u003e t('welcome')}!\n  \u003c/Trans\u003e\n);\n```\n\n\u003ch2 align=\"center\"\u003eTypeScript Support\u003c/h2\u003e\n\n**use-t** is written in TypeScript and provides full type safety:\n\n```tsx\nimport {TranslatorFn, ProviderState, TranslationMap} from 'use-t';\n\n// Type your translations\ninterface Translations {\n  greeting: string;\n  userWelcome: (name: string) =\u003e string;\n  itemCount: (count: number) =\u003e string;\n}\n\nconst translations: TranslationMap = {\n  en: {\n    main: {\n      greeting: 'Hello',\n      userWelcome: (name: string) =\u003e `Welcome, ${name}!`,\n      itemCount: (count: number) =\u003e `${count} items`\n    } as Translations\n  }\n};\n\n// Typed component props\ninterface Props {\n  t: TranslatorFn;\n  T: ProviderState;\n}\n\nconst MyComponent: React.FC\u003cProps\u003e = ({t, T}) =\u003e (\n  \u003cdiv\u003e\n    \u003ch1\u003e{t('greeting')}\u003c/h1\u003e\n    \u003cp\u003e{t('userWelcome', 'John')}\u003c/p\u003e\n  \u003c/div\u003e\n);\n```\n\n\u003ch2 align=\"center\"\u003eBest Practices\u003c/h2\u003e\n\n### Translation Organization\n\n```js\n// ✅ Good: Organize by feature/page\nconst translations = {\n  en: {\n    auth: {\n      login: 'Log In',\n      signup: 'Sign Up',\n      forgotPassword: 'Forgot Password?'\n    },\n    dashboard: {\n      welcome: 'Welcome back!',\n      stats: 'Your Statistics'\n    },\n    common: {\n      save: 'Save',\n      cancel: 'Cancel',\n      loading: 'Loading...'\n    }\n  }\n};\n\n// ❌ Avoid: All translations in one namespace\nconst translations = {\n  en: {\n    main: {\n      login: 'Log In',\n      dashboardWelcome: 'Welcome back!',\n      saveButton: 'Save',\n      // ... hundreds of keys\n    }\n  }\n};\n```\n\n### Performance Tips\n\n```jsx\n// ✅ Good: Load namespaces on-demand\nconst LazyDashboard = () =\u003e {\n  const [t] = useT('dashboard'); // Only loads dashboard namespace\n  return \u003cdiv\u003e{t('title')}\u003c/div\u003e;\n};\n\n// ✅ Good: Preload critical translations\n\u003cProvider \n  map={{\n    en: { \n      common: commonTranslations // Critical UI elements\n    }\n  }}\n  loader={dynamicLoader} // Non-critical loaded on-demand\n\u003e\n\n// ✅ Good: Use default locale as fallback\n\u003cProvider \n  locale=\"fr\" \n  defaultLocale=\"en\" // Falls back to English if French missing\n  map={translations}\n\u003e\n```\n\n### Error Handling\n\n```jsx\nconst translations = {\n  en: {\n    main: {\n      // Use descriptive keys that work as fallbacks\n      'user.welcome': 'Welcome!',\n      'error.network': 'Network error occurred',\n      'button.save': 'Save'\n    }\n  }\n};\n\n// Keys become fallback text if translation missing\nconst Component = () =\u003e {\n  const [t] = useT();\n  \n  return (\n    \u003cdiv\u003e\n      {/* Shows \"Welcome!\" or \"user.welcome\" if missing */}\n      \u003ch1\u003e{t('user.welcome')}\u003c/h1\u003e\n      \n      {/* Shows \"Save\" or \"button.save\" if missing */}\n      \u003cbutton\u003e{t('button.save')}\u003c/button\u003e\n    \u003c/div\u003e\n  );\n};\n```\n\n\u003ch2 align=\"center\"\u003eCustom Translation Instances\u003c/h2\u003e\n\nCreate isolated translation contexts for libraries or complex apps:\n\n```jsx\nimport {createTranslations} from 'use-t';\n\n// Create custom instance with different default namespace\nconst {Provider: LibProvider, useT: useLibT} = createTranslations('library');\n\nconst LibraryComponent = () =\u003e {\n  const [t] = useLibT();\n  return \u003cdiv\u003e{t('libMessage')}\u003c/div\u003e;\n};\n\n// Use in your app\n\u003cLibProvider map={{en: {library: {libMessage: 'Hello from library!'}}}}\u003e\n  \u003cLibraryComponent /\u003e\n\u003c/LibProvider\u003e\n```\n\n\u003ch2 align=\"center\"\u003eMigration from Other Libraries\u003c/h2\u003e\n\n### From react-i18next\n\n```jsx\n// react-i18next\nimport {useTranslation} from 'react-i18next';\nconst {t, i18n} = useTranslation();\nt('key');\ni18n.changeLanguage('es');\n\n// use-t equivalent\nimport {useT} from 'use-t';\nconst [t, {setLocale}] = useT();\nt('key');\nsetLocale('es');\n```\n\n### From React Intl\n\n```jsx\n// React Intl\nimport {useIntl} from 'react-intl';\nconst intl = useIntl();\nintl.formatMessage({id: 'key'});\n\n// use-t equivalent\nimport {useT} from 'use-t';\nconst [t] = useT();\nt('key');\n```\n\n\u003ch2 align=\"center\"\u003eTroubleshooting\u003c/h2\u003e\n\n**Translation not showing:**\n- Check if the key exists in your translation map\n- Verify the correct namespace is being used\n- Ensure Provider is wrapping your component\n- Check browser console for loading errors\n\n**Dynamic loading not working:**\n- Verify your loader function returns a Promise\n- Check network requests in browser dev tools\n- Ensure proper error handling in loader\n\n**TypeScript errors:**\n- Import types: `import type {TranslatorFn} from 'use-t';`\n- Check translation map structure matches expected format\n\n\u003ch2 align=\"center\"\u003eDetailed API Documentation\u003c/h2\u003e\n\nFor comprehensive API documentation, see:\n\n- [`\u003cProvider\u003e`](./docs/Provider.md) - Context provider configuration\n- [`useT()`](./docs/useT.md) - React hook usage and examples  \n- [`withT()`](./docs/withT.md) - Higher-order component patterns\n- [`\u003cTrans\u003e`](./docs/Trans.md) - Render prop component usage\n- [`\u003cConsumer\u003e`](./docs/Consumer.md) - Context consumer patterns\n- [`context`](./docs/context.md) - Direct context access\n- [`createTranslations()`](./docs/createTranslations.md) - Custom instances\n\n\u003ch2 align=\"center\"\u003eLicense\u003c/h2\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"./LICENSE\"\u003eUnlicense\u003c/a\u003e \u0026mdash; public domain.\n\u003c/p\u003e\n","funding_links":["https://github.com/sponsors/streamich"],"categories":["Packages"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstreamich%2Fuse-t","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstreamich%2Fuse-t","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstreamich%2Fuse-t/lists"}