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

@tuplo/yaintl

v1.4.0

Published

Yet another i18n library with ICU message syntax

Downloads

158

Readme

Why

Other i18n solutions supporting ICU syntax were too heavy to bundle with our apps where every kb in size counts. So we wrote this stripped down to the basics solution while still supporting complex ICU syntax and a familiar API.

Install

$ npm install @tuplo/yaintl

# or with yarn
$ yarn add @tuplo/yaintl

Usage

import I18n from '@tuplo/yaintl';

const i18n = new I18n({ 
  locale: "en-GB", 
  messages: { simple: { message: "Hi {name}!" } }
})

const t = i18n.build('simple')

t('message', { name: "Alice" }) // ⇒ "Hi Alice!"

Message syntax

We use the ICU syntax to declare i18n messages. Here's a brief description of how to use this syntax.

Plain string

const messages = {
  hello: "Hi stranger!"
}

t('hello'); // ⇒ "Hi stranger!"

Interpolation

Where placeholders in the message are replaced by given values.

Placeholder

const messages = {
  desc: "{name} lives in {city}."
}

t('desc', { name: "Alice", city: "London" } ); // ⇒ "Alice lives in London."

Plural

const messages = {
  photos: "You have {count, plural, one {# photo} other {# photos}}."
}

t('photos', { count: 1 }) // ⇒ "You have 1 photo."
t('photos', { count: 12 }) // ⇒ "You have 12 photos."

Plural with offset

const messages = {
  adds: "{adds, plural, offset:1 =0 {No-one has added this} =1 {You added this} one {You and one other person added this} other {You and # others added this}}."
}

t('adds', { adds: 0 }); // ⇒ "No-one has added this."
t('adds', { adds: 1 }); // ⇒ "You added this."
t('adds', { adds: 2 }); // ⇒ "You and one other person added this."
t('adds', { adds: 12 }); // ⇒ "You and 11 others added this."

Ordinal

const messages = {
  queue: "You are the {pos, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}.",
}

t('queue', { pos: 1 }); // ⇒ "You are the 1st."
t('queue', { pos: 2 }); // ⇒ "You are the 2nd."
t('queue', { pos: 3 }); // ⇒ "You are the 3rd."
t('queue', { pos: 12 }); // ⇒ "You are the 12th."

Select

const messages = {
  liked: "{gender, select, male {He} female {She} other {They}} liked this."
}

t('liked', { gender: 'male' }); // ⇒ "He liked this."
t('liked', { gender: 'female' }); // ⇒ "She liked this."
t('liked', { gender: undefined }); // ⇒ "They liked this."

Formatting

Values can also be formatted based on their type by using the syntax {variable, type, format}. Example: "The default value is {count, number, decimal}."

  • variable is the variable we pass
  • type is how to interpret the value
  • format is optional, and is a further refinement on how to display that type of data

Number

Possible values from style option on Intl.NumberFormat.

const messages = {
  num: "The default value is {count, number}.",
  perc: "The tank is at {count, number, percent} capacity.",
}

t('num', { count: 1_499 }); // ⇒ "The default value is 1,499."
t('perc', { count: 0.76 }); // ⇒ "The tank is at 76% capacity."

Date

Possible values from dateStyle option on Intl.DateTimeFormat.

const messages = {
  dt1: "Sale begins { startDate, date, short }.",
  dt2: "Sale begins { startDate, date, medium }.",
  dt3: "Sale begins { startDate, date, long }.",
  dt4: "Sale begins { startDate, date, full }.",
}

const startDate = new Date('2022-12-25');
t('dt1', { startDate }); // ⇒ "Sale begins 25/12/2022."
t('dt2', { startDate }); // ⇒ "Sale begins 25 Dec 2022."
t('dt3', { startDate }); // ⇒ "Sale begins 25 December 2022."
t('dt4', { startDate }); // ⇒ "Sale begins Sunday, 25 December 2022."

Time

Possible values from timeStyle option on Intl.DateTimeFormat.

const messages = {
  tm1: "Coupon expires at { startTime, time, short }.",
  tm2: "Coupon expires at { startTime, time, medium }.",
  tm3: "Coupon expires at { startTime, time, long }.",
  tm4: "Coupon expires at { startTime, time, full }.",
}

const startTime = new Date('2022-12-25T12:34:00.000Z');
t('tm1', { startTime }); // ⇒ "Coupon expires at 12:34."
t('tm2', { startTime }); // ⇒ "Coupon expires at 12:34:00."
t('tm3', { startTime }); // ⇒ "Coupon expires at 12:34:00 GMT."
t('tm4', { startTime }); // ⇒ "Coupon expires at 12:34:00 GMT."

List

Possible values from style option on Intl.ListFormat.

const messages = {
  l1: "With { team, list }.",
  l2: "With { team, list, long }.",
  l3: "With { team, list, short }.",
  l4: "With { team, list, narrow }.",
}

const team = ['Alice', 'Bob', 'Charlie'];
t('l1', { team }); // ⇒ "With Alice, Bob and Charlie."
t('l2', { team }); // ⇒ "With Alice, Bob and Charlie."
t('l3', { team }); // ⇒ "With Alice, Bob and Charlie."
t('l4', { team }); // ⇒ "With Alice, Bob, Charlie."

Custom formatters

Besides the default styles from Intl formatters, we can use all those options to create custom formatters.

Number

All possible options listed at Intl.NumberFormat.

const formats = {
  number: {
    nf1: { notation: 'scientific' },
    nf2: { signDisplay: 'exceptZero' }  
  }
}
const messages = {
  'm1': 'The value is {count, number, nf1}.',
  'm2': 'The value is {count, number, nf2}.'
}
const i18n = new I18n({ locale: 'en-GB', messages, formats });

const count = 1_234_567_890;
t('m1', { count }) // ⇒ "The value is 1.235E9."
t('m2', { count }) // ⇒ "The value is +1,234,567,890."

Date

All possible options listed at Intl.DateTimeFormat.

const formats = {
  dateTime: {
    df1: { day: 'numeric', month: 'short' },
    df2: { month: 'long' }  
  }
}
const messages = {
  'm1': 'Sale begins {start, date, df1}.',
  'm2': 'Sale begins {start, date, df2}.'
}
const i18n = new I18n({ locale: 'en-GB', messages, formats });

const start = new Date('2022-12-25');
t('m1', { start }) // ⇒ "Sale begins 25 Dec."
t('m2', { start }) // ⇒ "Sale begins December."

Time

All possible options listed at Intl.DateTimeFormat.

const formats = {
  dateTime: {
    tf1: { timeStyle: 'short' },
    tf2: { timeStyle: 'short', timeZone: 'America/Los_Angeles' }  
  }
}
const messages = {
  'm1': 'Sale begins {start, time, tf1}.',
  'm2': 'Sale begins {start, time, tf2}.'
}
const i18n = new I18n({ locale: 'en-GB', messages, formats });

const start = new Date('2022-12-25T23:30:00.000Z');
t('m1', { start }) // ⇒ "Sale begins 23:30."
t('m2', { start }) // ⇒ "Sale begins 15:30."

List

All possible options listed at Intl.ListFormat.

const formats = {
  dateTime: {
    lf1: { type: 'disjunction' }
  }
}
const messages = {
  'm1': 'With {team, list, lf1}.'
}
const i18n = new I18n({ locale: 'en-GB', messages, formats });

const team = ['Alice', 'Bob', 'Charlie'];
t('m1', { team }) // ⇒ "With Alice, Bob or Charlie."

License

MIT