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

@engoo/mnoga

v1.0.0

Published

Simple internationalization library for Javascript.

Downloads

6

Readme

Mnoga Build Status

Simple and easy-to-use internationalization library for javascript or typescript.

Mnoga (/ˈmnɔɡa/) is the Polish word for "plural."

Features

  • Uses a nested JSON format and interpolation style similar to Rails I18n YAML.
  • Strings are written in a format that is easy to use by content editors.
  • Normalizes BCP 47 language tags.
  • Includes CLDR pluralization rules for a lot common languages.
    • Rules are extensible.
  • Fallback solutions for when a highly specific locale is not found.
  • Customizable fallback locale for when content is not found.
  • Typed definitions for those using typescript.
  • No dependencies.

Installation

If you are using npm:

npm install @engoo/mnoga

If you are using yarn:

yarn add @engoo/mnoga

Basic Usage

Let's say our site supports Japanese and English. We'll store our translations in two separate files that are in a nested JSON format.

The keys must consist of alphanumeric characters (with hyphen and underscore also being allowed). If the string has multiple plural versions, the keys zero, one, two, many, few, and other can be used, depending on the language. Please look at the CLDR pluralization rules to see keys apply to which language.

Strings can contain variables by using the wrapper %{variableName}, where variableName is a variable name of your choosing. There is a magic variable called count, which is used primarily for pluralization.

en.json

{
  "admin": {
    "header": {
      "logged-in-as": "You are logged in as %{username}.",
    }
  },
  "animals": {
    "dog": "dog",
    "cat": {
      "one": "%{count} cat",
      "other": "%{count} cats"
    }
  }
}

ja.json

{
  "animals": {
    "dog": "犬",
    "cat": "%{count}匹の猫"
  }
}

Let's use the library to print a few strings.

index.js

import Mnoga from '@engoo/mnoga';
import ja from './ja';
import en from './en';

// Instantiate an instance of Mnoga.
const mnoga = new Mnoga();

// Set translations for japanese and english.
mnoga.setPhrases('ja', ja);
mnoga.setPhrases('en', en);

// Set the fallback locale. `en` is already the default.
mnoga.setFallback('en');

// Use 'ja' as the primary locale.
mnoga.setLocale('ja');

// When looking up a string, we use the keys delimited by a period.
mnoga.t('animals.cat', { count: 1 }); // 1匹の猫
mnoga.t('animals.cat', { count: 5 }); // 5匹の猫
mnoga.t('animals.dog');               // 犬

// This falls back to english, since that is our fallback and there is no Japanese translation.
mnoga.t('admin.header.logged-in-as', { username: 'Mnoga' }); // You are logged in as Mnoga.

// Keys that are not found in the fallback simply print the key.
mnoga.t('this.key.does.not.exist'); // this.key.does.not.exist

// Switching to english and running the same strings.
mnoga.setLocale('en');

mnoga.t('animals.cat', { count: 1 });                         // 1 cat
mnoga.t('animals.cat', { count: 5 });                         // 5 cats
mnoga.t('animals.dog');                                       // dog
mnoga.t('admin.header.logout');                               // Click here to sign out
mnoga.t('this.key.does.not.exist');                           // this.key.does.not.exist
mnoga.t('admin.header.logged-in-as', { username: 'Mnoga' });  // You are logged in as Mnoga.

Supporting Language Scripts and Regions

Languages like Chinese can be difficult to support, since the language tags an environment provides may contain script, region or both. setLocale will try removing the region tag, then the script tag to see if there are any reasonable matches to fallback on.

const mnoga = new Mnoga();

mnoga.setPhrases('zh', {});

// If the locale contains script and region, it will fallback and choose zh.
mnoga.setLocale('zh-Hant-HK');
mnoga.getLocale();              // zh

// If the locale contains only region, it will fallback and choose zh.
mnoga.setLocale('zh-HK');
mnoga.getLocale();              // zh

// If the locale contains only script, it will fallback and choose zh.
mnoga.setLocale('zh-Hant');
mnoga.getLocale();              // zh

Let's say you support simplified and traditional Chinese. It's advised that instead of setting translations for all possible regions, it's better to use setAlias so that regions will get set as the officially supported locale.

const mnoga = new Mnoga();

mnoga.setPhrases('zh-Hans', {});
mnoga.setPhrases('zh-Hant', {});

// Mainland china should use simplified Chinese.
mnoga.setAlias(['zh', 'zh-CN'], 'zh-Hans');

// Other regions like Hong Kong, Macau and Taiwan should support traditional Chinese.
mnoga.setAlias(['zh-TW', 'zh-HK', 'zh-MO'], 'zh-Hant');

// Using an aliased locale will result in the primary locale being zh-Hant.
mnoga.setLocale('zh-TW');
mnoga.getLocale();  // zh-Hant

// Languages containing region and script will fallback to the language script.
mnoga.setLocale('zh-Hant-HK');
mnoga.getLocale();  // zh-Hant

Aliasing also works for regions. For example, let's say we officially support US English and British English, but also want users from Australia to use British English.

const mnoga = new Mnoga();

mnoga.setPhrases('en-US', {});
mnoga.setPhrases('en-GB', {});

mnoga.setAlias('en-AU', 'en-GB');

mnoga.setLocale('en-AU');
mnoga.getLocale();  // en-GB

Need to re-render content

The library has a subscribe method. A handler can be passed to that will be triggered when any significant changes occur. For example, changing the primary locale or setting new translations will cause the method to be executed.

const mnoga = new Mnoga();

// Will update the title whenever locale or phrases change.
const render = () => {
  document.head.title = mnoga.t('title');
};

// Set some translations.
mnoga.setPhrases('en', { title: 'English Homepage' });
mnoga.setPhrases('ja', { title: '日本語ホ-ムページ' });

// Returns an unsubscribe method that can be called if we want to stop listening for changes.
const unsubscribe = mnoga.subscribe(update);

// Changing the locale will call subscribe.
mnoga.setLocale('ja');
console.log(document.head.title); // '日本語ホ-ムページ'

// Changing the translations will call subscribe.
mnoga.setPhrases('ja', { title: '新しい日本語ホ-ムページ' });
console.log(document.head.title); // '新しい日本語ホ-ムページ'

Supported Languages and Extending Support

The following locales are supported out of the box: af, ar, be, cs, de, el, en, es, fi, fr, hi, id, it, iu, ja, ko, ms, my, ne, nl, pl, pt, sk, sw, th, tr, ru, uk, vi, zh.

Support for additional locales can be added by using the setRule method.

const mnoga = new Mnoga();

// A rule method is a method that takes a number and returns one of the following
// string values: zero, one, two, few, many, and other.
const rulesForEnglish = (count) => {
  if (count === 1) {
    return 'one';
  } else {
    return 'other';
  }
}

// Sets this rule for English.
mnoga.setRule('en', rulesForEnglish);

Utilities

Utility methods are also provided if you want to maintain your own state.

import { getCanonicalLocales, getFallbackPattern, lookupLocale, lookupPhrase } from '@engoo/mnoga/utils/i18n';

// Returns a canonical format of a locale or multiple locales.
getCanonicalLocales('EN-US');                       // ['en-US']
getCanonicalLocales(['EN-US', 'ZH-HANT-TW', 'Fr']); // ['en-US', 'zh-Hant-TW', 'fr']

// Canonicalized fallback pattern based on a locale.
getFallbackPattern('zh-Hant-TW');  // ['zh-Hant-TW', 'zh-Hant', 'zh']
getFallbackPattern('en-US');       // ['en-US', 'en']

// Gets a preferred locale.
const supportedLocales = ['zh-Hant', 'zh-Hans', 'pt', 'en'];
lookupLocale('zh-Hant-TW', supportedLocales);            // zh-Hant
lookupLocale('zh-Hans-CN', supportedLocales);            // zh-Hans
lookupLocale(['pt-BR', 'en'], supportedLocales);         // pt
lookupLocale('zh', supportedLocales, { zh: 'zh-Hans' }); // zh-Hans

// Lookup a phrase. Be sure to canonicalize the locales.
const phrases = {
  en: {
    context_1: {
      context_2: 'English',
    },
  },
  ja: {
    context_1: {
      context_2: '日本語',
    },
  },
};

lookupPhrase({ key: 'context_1.context_2', locales: ['ja'], phrases });       // 日本語
lookupPhrase({ key: 'context_1.context_2', locales: ['fr', 'en'], phrases }); // English
lookupPhrase({ key: 'context_1.context_2', locales: ['pt'], phrases });       // context_1.context_2

Further Reading

To find out more about the functionality available, please check out the API documentation.