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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@leile/lobo-t

v1.0.5

Published

A simple library for type-safe translations

Downloads

969

Readme

Lobo-T

A small library for type-safe translations in React applications

Installation

$ npm i @leile/lobo-t
# or
$ yarn add @leile/lobo-t

lobo-t at a glance

You tell lobo-t which languages you support and which language is currently active. lobo-t gives you a React hook that you can use to get a function for translating text resources. A text resource in lobo-t terms is an object that has keys for each language you support. If you try to translate a text resource that is missing one or more languages or a text resource that doesn't exist, lobo-t (or rather, TypeScript) will tell you so.

That's all.

If you want to know more about why we decided to make this, see below.

Usage

// i18n.ts
import { initLobot } from '@leile/lobo-t';

// Specify which languages you support
export enum Language {
  Norwegian = 'nb',
  English = 'en',
}

const lobot = initLobot<typeof Language>(Language.English);

export const LanguageProvider = lobot.LanguageProvider;
export const useTranslation = lobot.useTranslation;
// index.tsx
import { LanguageProvider, Language } from './i18n';
import App from './App';

// You decide how to detect/store the active language.
// In this example, we get it as a prop.
// When it changes, components using the useTranslation hook will re-render with the correct language
export default (props: { activeLanguage: Language }) => (
  <LanguageProvider value={props.activeLanguage}>
    <App />
  </LanguageProvider>
);
// App.tsx
import { useTranslation } from './i18n';

// Text resources must have a key for each language you support
const texts = {
  header: {
    nb: 'Dette er en header',
    en: 'This is a header',
  },
  activeUsers: count => ({
    nb: `Det er nå ${count} aktive brukere`,
    en: `There are now ${count} active users`,
  }),
  // or
  //   header: {
  //     [Language.Norwegian]: 'Dette er en header',
  //     [Language.English]: 'This is a header',
  //   },
  //   activeUsers: count => ({
  //     [Language.Norwegian]: `Det er nå ${count} aktive brukere`,
  //     [Language.English]: `There are now ${count} active users`,
  //   }),
};

export default () => {
  const { t } = useTranslation();

  return (
    <div>
      <h1>{t(texts.header)}</h1>
      <p>{t(texts.activeUsers(5))}</p>
    </div>
  );
};

Why?

After using other translation libraries for quite some time we realized that we didn't really like them. They worked, but there were some things that irked us. For example:

  • Some tools store translations in JSON files in separate folders per language. This makes the physical distance between translations too large. In our experience this often lead to texts in different languages communicating different things to users, because they were not written at the same time.
  • Accessing text resources by calling a function with a string that coincidentally should correspond to a path in a JSON object is brittle and makes refactoring hard
  • String interpolation is brittle when not type-checked. Having {{somevariablename}} in strings and passing objects with properties that should match whatever you wrote in the translation file is an error waiting to happen.
  • Having styling or more complex contents in text resources is often very complex and requires parsing and/or third-party tools

So we sat down and came up with a list of what we wanted. For context, most of our applications are written using next.js, all of them in TypeScript, and at the moment we support two languages. Since we use next.js we get code splitting out of the box, so we don't really need our internationalization tool to have complex lazy-loading features. Additionally, we, the developers, are the ones writing the translations.

Our list of requirements:

Type-checked

  • Trying to translate a resource that doesn't exist should be a compile-time error
  • The compiler should tell you when you're missing translations for one or more of the languages you support

Text resources should be able to live close to where they are used

We like the way CSS modules allow us to scope our CSS so that changes in one part of the application don't break other stuff. It would be nice to be able to apply the same principle to internationalization.

It should be easy to see where a text resource is used

  • There is a difference between two things being similar and being the same. It happens often while refactoring one thing that some other thing stops making sense
  • Dead code should be deleted, and so should unused text resources (and your editor/IDE should tell you if it wasn't dead after all)

Translations for different languages should be located close together

The save button should communicate to the user that it will save, no matter what language the user is using. It should not say "Save" in English and "Fullfør" (which means "Complete") in Norwegian. Keeping the English and Norwegian texts close together, rather than in separate files in separate folders, helps us keep semantics in check.

String interpolation should be easy and type-checked

When using a text resource that expects some external input you should be notified of this before leaving your editor/IDE.

Using some styling in translations should be possible

Sometimes it makes sense to have some styling in the text resource. This could be done either with inline HTML/JSX or using markdown in some way.

For example, in our opinion:

const myText = <span>String with a <strong>bold</strong> word.</span>
/// ...
<div>{myTextResource}</div>

is easier and less error-prone than

const myTextOne = 'String with a';
const myTextTwo = 'bold';
const myTextThree = ' word';
// ...
<div>
  {myTextOne}
  <strong>{myTextTwo}</strong>
  {myTextThree}
</div>;

In the second example, can you tell at a glance whether this wil render with the correct whitespace or not?

This library is probably not for you if

  • You get your text resources from a CMS or store them someplace other than in your code-base
  • The developers are not the ones writing the translations
  • You don't use TypeScript
  • You don't like the API (but if you have any suggestions on how to improve it, discuss it with us!)
  • You need support for many languages - the structure of your translation objects might become messy
  • You don't like superheroes that can regenerate from a single cell and claims to know 17,897 different languages from across the galaxy (Lobo)