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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@beforesemicolon/intl

v0.2.0

Published

Web component localization based on Markup

Readme

@beforesemicolon/intl

Scoped internationalization for formatter functions and Web Components.

@beforesemicolon/intl gives you:

  • Runtime scopes with locale, fallback locale, messages, loading state, and formatter caches.
  • Formatter functions for messages, numbers, dates, durations, relative time, lists, display names, and plurals.
  • Web Components that use the nearest <intl-locale> provider.
  • Per-component entrypoints for lazy loading.
  • A browser bundle for script-first apps.

Install

npm install @beforesemicolon/intl

Script-First Usage

Initialize the default runtime and call formatter functions directly.

import {
    formatMessage,
    formatNumber,
    initIntl,
    setLocale,
} from '@beforesemicolon/intl'

initIntl({
    locale: 'en-US',
    fallbackLocale: 'en',
    srcDir: '/locales',
})

formatMessage('home.title')
formatNumber(1200, { style: 'currency', currency: 'USD' })

await setLocale('pt-CV')

Component-First Usage

Register the components you use, then add <intl-locale> around localized UI.

import '@beforesemicolon/intl/components/intl-locale'
import '@beforesemicolon/intl/components/intl-msg'
import '@beforesemicolon/intl/components/intl-number'
import '@beforesemicolon/intl/components/intl-datetime'
<intl-locale locale="en-US" src-dir="/locales" fallback>
    <h1><intl-msg key="home.title"></intl-msg></h1>
    <intl-number value="1200" type="currency" currency="USD"></intl-number>
    <intl-datetime
        value="2026-01-01T10:00:00Z"
        date-style="medium"
        time-zone="UTC"
    ></intl-datetime>
</intl-locale>

Nested Providers

Nested <intl-locale> providers create child runtime scopes. Child scopes inherit parent messages and fallback messages unless they override them.

<intl-locale locale="en-US" src-dir="/locales" fallback>
    <intl-msg key="checkout.title"></intl-msg>

    <intl-locale locale="pt-CV" src-dir="/locales" fallback>
        <intl-msg key="checkout.title"></intl-msg>
    </intl-locale>
</intl-locale>

Lazy CDN Usage

<script src="https://unpkg.com/@beforesemicolon/web-component/dist/client.js"></script>
<script src="https://unpkg.com/@beforesemicolon/intl/dist/client.js"></script>

<script>
    BFS.INTL.onLocaleMessagesLoaded
    BFS.INTL.intlMsg('home.title')
    BFS.INTL.intlNumber({ value: 1200, type: 'currency', currency: 'USD' })
</script>

For ESM CDNs, import component entrypoints independently:

import 'https://esm.sh/@beforesemicolon/intl/components/intl-locale'
import 'https://esm.sh/@beforesemicolon/intl/components/intl-msg'

Runtime API

import {
    createIntl,
    getIntl,
    initIntl,
    loadLocale,
    setLocale,
} from '@beforesemicolon/intl'

const checkoutIntl = createIntl({
    locale: 'en-US',
    fallbackLocale: 'en',
    messages: { total: 'Total: {amount}' },
})

getIntl(checkoutIntl)
await loadLocale('pt-CV', checkoutIntl)
await setLocale('pt-CV', checkoutIntl)

Function API

formatMessage(key, values?, options?)
formatNumber(value, options?)
formatDateTime(value, options?)
formatDuration(value, options?)
formatRelativeTime(value, options?)
formatList(value, options?)
formatName(value, options?)
formatPlural(value, options?)

Each formatter accepts locale and scope options where applicable.

formatMessage('hello', { name: 'Elson' }, { scope: checkoutIntl })
formatNumber(1200, { locale: 'pt-CV' })
formatDateTime('2026-01-01T10:00:00Z', {
    dateStyle: 'medium',
    timeZone: 'UTC',
})
formatDuration(3600000, { fields: 'hours', style: 'short' })
formatRelativeTime(Date.now() + 60000, { unit: 'auto' })
formatList(['A', 'B', 'C'], { type: 'conjunction' })
formatName('PT', { type: 'region' })
formatPlural(2, { one: 'item', other: 'items' })

Component API

| Component | Purpose | Common attributes | | ----------------- | -------------------------------- | ---------------------------------------------------------------------------- | | <intl-locale> | Provider scope and locale loader | locale, fallback-locale, src, src-dir, fallback, update-document | | <intl-msg> | Message lookup and interpolation | key, values | | <intl-number> | Number, currency, percent, unit | value, type, currency, unit, locale | | <intl-datetime> | Date/time formatting | value, date-style, time-style, time-zone | | <intl-duration> | Duration formatting | value, fields, time-style | | <intl-rel-time> | Relative time formatting | value, unit, numeric, live | | <intl-list> | List formatting | value, type, type-style | | <intl-name> | Display names | value, type, name-style, language | | <intl-plural> | Plural selection | value, type, zero, one, two, few, many, other |

Message File Format

Message files are JSON objects. Nested keys are addressed with dot notation.

{
    "home": {
        "title": "Welcome",
        "hello": "Hello {name}"
    },
    "checkout": {
        "total": "Total: {amount}"
    }
}
<intl-msg key="home.hello" values='{"name":"Elson"}'></intl-msg>

Fallback Behavior

  • Components use the nearest <intl-locale> runtime.
  • Explicit locale attributes override the provider locale for that component.
  • Child providers inherit parent messages and fallback messages.
  • fallback-locale is loaded when available.
  • Missing messages render the key unless a custom missing handler is provided.
  • Invalid formatter input renders an empty string and logs a component error.

Examples Per Component

<intl-msg key="home.title"></intl-msg>
<intl-number value="1200" type="currency" currency="USD"></intl-number>
<intl-datetime value="2026-01-01T10:00:00Z" date-style="long"></intl-datetime>
<intl-duration
    value="3600000"
    fields="hours"
    time-style="short"
></intl-duration>
<intl-rel-time value="1780000000000" live></intl-rel-time>
<intl-list value="book pen pencil" type="and"></intl-list>
<intl-name value="PT" type="region"></intl-name>
<intl-plural value="2" one="item" other="items"></intl-plural>

Recommended Usage

  • Use <intl-msg key="..."> for message lookup.
  • Use time-zone and time-zone-name for date-time options.
  • Use package-level formatter functions when JavaScript code needs the same formatting behavior as components.
  • Use @beforesemicolon/intl/components/intl-* entrypoints for lazy component registration.
  • Use <intl-locale> scopes when a page or subtree needs explicit locale state.