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

intl-schematic

v1.0.0-rc.9

Published

<h1 align="center"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Raiondesu/intl-schematic/main/logo/Dark%20Logo.svg"> <source media="(prefers-color-scheme: light)" srcset="https://raw.github

Downloads

511

Readme

Stupidly simple, incredibly tiny, blazingly fast.

This is a tiny framework-agnostic i18n library (1kb gzip, zero-dependency) that allows to localize and format strings with infinitely expandable functionality.

  • 🦺 Full type-safety: full autocomplete on translation keys, typed translation parameters and more;
  • 🎄 Tree-shakable: only take what you need;
  • 🌌 Truly universal: one-size-fits-all solution - able to suit any project setup;
  • 🎈 Incredibly lightweight: less than 1kb for the core package, less than 5kb for every feature imaginable.
  • 🧩 Easily integrates with UI-frameworks: we don't play favorites here - every framework can use this;
  • 🔌 Pluginable: extend any processing step without limits - see the plugins API for more;
  • 📃 JSON-validation using a JSON-schema: intellisense and popup hints right in the translation document;
  • 🚫 No string-interpolation: translation strings will never be processed or mangled by-default, so all unicode symbols are safe to use;

Table of contents

Basic Usage

See a simplified example below and don't be afraid to take a look into the sources to find out more.

Define a translation document factory

// In the real world, this function would probably contain
// a dynamic import of the required translation document
const getDocument = () => ({
  "hello": "Hello, World!"
});

Create a translator function (t())

import { createTranslator } from 'intl-schematic';

const t = createTranslator(getDocument);

// OR

const t = createTranslator(getDocument, [
  // Add optional plugins here
  // they will be applied to translations in corresponding order
]);

Use the translator function

console.log(t('hello')); // `Hello, World!`

Using with reactive frameworks

Many other i18n libraries require deep integration into a specific UI-framework.
This, however, is not the case with intl-schematic, due to its framework-agnostic and isomorphic architecture.

The only requirement to make it behave "natively" for a certain framework, is to simply add a reactive dependency to a closure of getLocaleDocument function (the first argument of createTranslator).

Here's an example in a "reactive pseudocode":

// Define a reactive variable;
// Solid
const userLocale = createSignal(new Intl.Locale('en'));
// Vue
const userLocale = ref(new Intl.Locale('en'));

const fetchDocument = () => {
  // Somehow get a value from the reactive variable
  const language = get(userLocale).language;
  // Suppose you have a translation document in the `locales` folder
  return import(`/locales/${language}.json`);
};

// Create a reactive variable for a translation document
const currentDocument = createSignal();

// Then, in a reactive context (like a UI component)
const t = createTranslator(
  // If this function is invoked in a reactive context,
  // the framework will most likely track this as a reactive dependency
  () => get(currentDocument)
);

// useEffect/watch/computed
createEffect(() => {
  // Since calling `fetchDocument`
  // involves getting a value from a reactive variable,
  // this is tracked as a reactive dependency and will re-run accordingly
  fetchDocument()
    .then(newDocument => set(currentDocument, newDocument));
});

<p>{t('some key')}</p> // Some text

// Then change the locale
set(userLocale, new Intl.Locale('es'));

// The text re-renders automatically once the new translation document is fetched
<p>{t('some key')}</p> // Algún texto

Even though something like this is fairly trivial to implement, given a basic knowledge of any specific UI-framework, intl-schematic still offers some "in-house"-made integrations:

Current framework integrations

  • @intl-schematic/solid - reactive adapter for solid-js
    • Allows to use wrapper components like <Intl> or <Multiline> to simplify working with multipart string translations in need of complex styling
    • Creates a reactive resource with the locale document and user's locale that is then passed in a closure to intl-schematic and user-defined plugins
  • @intl-schematic/vue - reactive adapter for vue
    • Utilizes a watcher to reactively fetch the needed document based on user locale
  • @intl-schematic/react - reactive adapter for react
    • Utilizes a useEffect hook to reactively fetch the needed document based on user locale

If you want an integration for your favorite framework, feel free to contibute or create an issue!

Plugins

This is by far the main strength of the library.

Translating keys relies on simple key-value lookup, and most i18n libraries add many unnecessary features on top of this primitive functionality.

intl-schematic instead provides a way to extend both its functionality and type definitions in a comprehensive enough way, so that anyone can pick and choose what exact features are needed for their project without any bloat whatsoever.

In other words, plugins allow to almost infinitely expand the functionality of intl-schematic.

To find out more, see the main plugins readme.

List

Current list of all official plugins is as follows:

Add default plugins and processors

You might want to install the default plugin collection:

npm i @intl-schematic/plugin-defaults

These allow to use standard Intl features, like DateTimeFormat, PluralRules and DisplayNames, as well as cross-reference keys and many other features.

import { createTranslator } from 'intl-schematic';
import { defaultPlugins, defaultProcessors } from '@intl-schematic/plugin-defaults';

const getDocument = () => ({
  price: {
    // Processor name - number - means process with Intl.NumberFormat
    number: {
      // Intl.NumberFormat options
      style: "currency",
      currency: "USD",
      currencyDisplay: "symbol",
      trailingZeroDisplay: "stripIfInteger"
    },
    input: 0 // fallback
 }
});

const getLocale = () => new Intl.Locale('en');

const t = createTranslator(getDocument, defaultPlugins(
  getLocale,
  defaultProcessors
));

console.log(t('price', 123)); // "$123"

Using with JSON-schema

intl-schematic, as well as its plugins, defines a JSON-schema API designed specifically to allow type-checking JSON translation documents.

Using the CLI

Broken right now, see manual definition.

To quickly define the translation.schema.json for your translation documents, you can run the official CLI in your project's root:

npx intl-schematic init
# or provide an optional custom file name
npx intl-schematic init ./locales/my-translation.schema.json

And then use it in your translation document:

// en.json
{
  // Path to the schema from the example above
  "$schema": "./translation.schema.json",
  "key": "Translation of my key"
}
import translation from './en.json';

const t = createTranslator(() => translation);

// Etc., see example at the start of this file

Note: the $schema key will be automatically excluded
from type hints for t() for your convenience!

Manual definition

To define a JSON-schema for your translation documents, simply create a .schema.json file with this template:

// translation.schema.json
{
  "$ref": "https://unpkg.com/intl-schematic/translation.schema.json",
  "additionalProperties": {
    "anyOf": [
      // Definition for the default string key-value pair
      {
        "$ref": "https://unpkg.com/intl-schematic/property.schema.json",
      }
      // Add references to more allowed types for your schema
      /* for example, @intl-schematic/plugin-processors definition:
      {
        "$ref": "https://unpkg.com/@intl-schematic/plugin-processors/property.schema.json"
      }
      */
    ]
  }
}

Plugins that define a property.schema.json

Not all plugins have a property.schema.json file, not all of them need to.
Here's a list of the ones that do:

No-goals

Even though custom plugins can do literally anything with keys, values, and translation documents,
the core library will not support:

  • Translation key nesting using dot-notation: needlessly complicates key lookup and maintenance;
    • Instead use namespaced keys or the nested plugin (which supports dot-notation!);
  • String interpolation: the library by-itself does not and will not do any processing on the strings.