DoneDeal0 / Talkr

Talkr is the lightest i18n provider for React applications. It supports Typescript, provides autocompletion, has 0 dependencies, and is very easy to use.
https://talkr-documentation.netlify.app/
249 stars 10 forks source link
i18n react react-context reactjs translation translations

Capture d’écran 2024-05-20 à 17 19 54


TALKR

Talkr is the lightest i18n provider for React applications. It supports Typescript, provides autocompletion, has 0 dependencies, and is very easy to use.

CI CD NPM Downloads


FEATURES


SCREENSHOT

talkr autocomplete in action


INSTALLATION

// with npm
npm install talkr
// with yarn
yarn add talkr

ADD TRANSLATION FILES

🤓: Some languages have more complex plural rules, that may require these five options to offer a perfect user experience. For instance, Arabic handle zero, one, two, numbers between 3 and 10 and numbers over 10 as separate entities. If a language doesn't need all these subtleties - like english - you can only write zero, one and many in the JSON file.

{
  "hello": "hello",
  "feedback": {
    "error": "The connection failed",
    "success": "The connection succedeed"
  },
  "user": {
    "describe": {
      "simple": "You are __name__",
      "complex": "You are __name__ and you like __hobby__"
    }
  },
  "idiom": {
    "sovereign": {
      "female": "Long live the Queen!",
      "male": "Long live the King!"
    }
  },
  "message-count": {
    "zero": "you don't have new messages",
    "one": "you have 1 message",
    "many": "you have __count__ messages"
  },
  "days": ["Monday", "Tuesday", "Wednesday"],
}

SET UP

import * as React from "react";
import { createRoot } from "react-dom/client";
import { Talkr } from "talkr";
import App from "./app";
import en from "./i18n/en.json";
import fr from "./i18n/fr.json";

const root = createRoot(document.getElementById("root"));

root.render(
  <Talkr languages={{ en, fr }} defaultLanguage="en">
    <App />
  </Talkr>,
);

SIMPLE USAGE

import React from "react";
import { useT } from "talkr";

export default function MyComponent() {
  const { T } = useT();
  return (
    <>
      <h1>{T("hello")}</h1>
      <div>{T("feedback.success")}</div>
    </>
  );
}

DYNAMIC VALUES

"user": {
    "describe": {
      "simple": "You are __name__",
      "complex": "You are __name__ and you like __hobby__"
    }
  }
import React from "react";
import { useT } from "talkr";

export default function MyComponent() {
  const { T } = useT();
  return (
    <>
      <h1>{T("user.describe.complex", { name: "joe", hobby: "coding" })}</h1>
    </>
  );
}

PLURAL

"message-count": {
    "zero": "you don't have new messages",
    "one": "you have 1 message",
    "many": "you have __count__ messages"
  }
import React, { useState } from "react";
import { useT } from "talkr";

export default function MyComponent() {
  const { T } = useT();
  const [count, setCount] = useState(0);
  return (
    <>
      <h1>{T("message-count", { count })}</h1>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </>
  );
}

GENDER

"idiom": {
    "sovereign": {
      "female": "Long live the Queen!",
      "male": "Long live the King!"
    }
  }
import React from "react";
import { useT } from "talkr";

export default function MyComponent() {
  const { T } = useT();
  return (
    <>
      <h1>{T("idiom.sovereign", { gender: "m" })}</h1>
    </>
  );
}

LIST

  listType?: "conjunction" | "disjunction"; // ""conjunction" by default
  listStyle?: "long" | "narrow"; // "narrow" by default
  "days": ["Monday", "Tuesday", "Wednesday"],
import React from "react";
import { useT } from "talkr";

export default function MyComponent() {
  const { T } = useT();
  return (
    <>
      <h1>{T("days", { listType: "conjunction" })}</h1>
    </>
  );
}

LOCALE

import React, { useState } from "react";
import { useT } from "talkr";

export default function MyComponent() {
  const { T, setLocale, locale } = useT();
  return (
    <>
      <h1>{T("hello")}</h1>
      <p>{locale}</p>
      <button onClick={() => setLocale("fr")}>speak french</button>
    </>
  );
}

AUTOCOMPLETION

Autocompletion for translation keys is available in Typescript projects. Because json must be parsed at compile time, you will need to create your own useAutocompleteT hook with Talkr's Autocomplete type wrapper.

Here's how to do it:

import { useT, Autocomplete, TParams, tr } from "talkr";
import en from "./en.json";

type Key = Autocomplete<typeof en>;

export const useAutocompleteT = () => {
  const { locale, languages, defaultLanguage } = useT();
  return {
    T: (key: Key, params?: TParams) =>
      tr({ locale, languages, defaultLanguage }, key, params),
  };
};

If you prefer to keep the useT naming, just write:

import { useT as useTr, Autocomplete, TParams, tr } from "talkr";
import en from "./en.json";

type Key = Autocomplete<typeof en>;

export const useT = () => {
  const { locale, languages, defaultLanguage } = useTr();
  return {
    T: (key: Key, params?: TParams) =>
      tr({ locale, languages, defaultLanguage }, key, params),
  };
};

Autocomplete usage

You now have the choice between using your own useAutocompleteT hook - which provides real-time autocompletion - or using Talkr's useT - which doesn't provide autocompletion - in your app.

import { useAutocompleteT } from "./translate";

function App() {
  const { T } = useAutocompleteT();
  return (
    <>
      <h1>{T("feedback.success")}</h1>
      <h4>{T("user.describe.complex", { name: "joe", hobby: "coding" })}</h4>
    </>
  );
}

🤓 Pro-tip: since you will need to import useAutocompleteT from translate.tsx, it is highly recommended to add an alias translate to your builder's config and tsconfig.json.

This will allow you to write

import { useAutocompleteT } from "translate" 👍

instead of

import { useAutocompleteT } from "../../translate" 👎

Exemples: webpack

resolve: {
  extensions: [".ts", ".tsx", ".js", "jsx", ".json"],
  alias: {
      translate: path.resolve(__dirname, "src/translate/"),
 }

tsconfig

{ "compilerOptions": {
  "paths": {
  "translate/*": ["src/translate/*"]
  }
}}

for other bundlers, please refer to their respective documentations.


REACT NATIVE

import { StyleSheet, Text, View } from "react-native";
import { Talkr } from "talkr";
import en from "./src/i18n/en.json";
import fr from "./src/i18n/fr.json";
import MyComponent from "./src/MyComponent";

export default function App() {
  return (
    <Talkr languages={{ en, fr }} defaultLanguage="en">
      <View style={styles.container}>
        <MyComponent />
      </View>
    </Talkr>
  );
}
import React, { Text, Button } from "react-native";
import { useState } from "react";
import { useT } from "talkr";

export default function MyComponent() {
  const { T } = useT();
  const [count, setCount] = useState(0);

  return (
    <>
      <Text>{T("hello")}</Text>
      <Text>
        {T("user.describe.complex", { name: "joe", hobby: "coding" })}
      </Text>
      <Text>{T("message-count", { count })}</Text>
      <Button onPress={() => setCount(count + 1)} title="+1" />
    </>
  );
}

AVAILABLE PROPS

You can pass these props to Talkr's provider Type Role
languages object object containing all your json files. Typical format: {en: {...}, fr: {...}}
defaultLanguage string default language of your app (a similar key must be included in the language prop)
detectBrowserLanguage boolean if true, Talkr will automatically use browser language and override the defaultLanguage. If the browser language is not included in your available translations, it will switch back to defaultLanguage. Not available in React Native. Use expo-localization to fetch the default user locale instead.

🤓: The auto-detect language feature will always return a simple key such as 'fr' instead of 'fr_FR'. Keep things simple and always declare your languages with 2 letters.


CREDITS

DoneDeal0


SUPPORT

If you or your company uses Talkr, please show your support by becoming a sponsor! Your name and company logo will be displayed on the README.md. https://github.com/sponsors/DoneDeal0


sponsor




Also see our website