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

pk-lang-codes

v0.2.0

Published

Unified language & locale code toolkit. ISO 639-1/2, BCP 47, scripts, regions. TypeScript-first, tree-shakeable, zero dependencies.

Readme

pk-lang-codes

Tiny, tree-shakeable language & locale toolkit for JavaScript/TypeScript.

ISO 639-1/2, BCP 47, scripts (with text direction), regions, and territory-language mapping for 257 countries — all in 68 KB on npm. Zero dependencies.

npm bundle

Install

npm install pk-lang-codes

Why?

Your server gets a locale code from a phone — zh-Hant-TW, ar-SA, hi-IN — and you need to:

  • Pick the right translationzh-TW → Traditional Chinese, not Simplified
  • Know the language, script, region, and text direction
  • Build a language selector with native names (العربية, 中文, हिन्दी)
  • Find what languages a country speaks
  • Detect RTL for layout

One import. One function. Done.

import { resolveLocale } from 'pk-lang-codes';

const locale = resolveLocale('ar-SA');
// {
//   language:     { code: 'ar', name: 'Arabic', nativeName: 'العربية' },
//   direction:    'rtl',           ← auto-detected even without script tag
//   region:       { code: 'SA', name: 'Saudi Arabia' },
//   displayName:  'Arabic (Saudi Arabia)',
// }

Smart Translation Matching

The killer feature — match a device locale to the best translation from your supported list:

import { matchTranslation } from 'pk-lang-codes';

const supported = ['en', 'zh-Hans', 'zh-Hant', 'es', 'pt', 'pt-BR', 'ar', 'ja'];

matchTranslation('zh-Hant-TW', supported);  // 'zh-Hant'  → Traditional, not Simplified
matchTranslation('zh-Hans-CN', supported);  // 'zh-Hans'  → Simplified
matchTranslation('zh-TW', supported);       // 'zh-Hant'  → infers script from region!
matchTranslation('zh-CN', supported);       // 'zh-Hans'  → infers script from region!
matchTranslation('pt-BR', supported);       // 'pt-BR'    → exact regional match
matchTranslation('pt-PT', supported);       // 'pt'       → falls back to base Portuguese
matchTranslation('en-AU', supported);       // 'en'       → base English
matchTranslation('ar-EG', supported);       // 'ar'       → Arabic
matchTranslation('sw-KE', supported);       // 'en'       → Kenya's primary lang (English)

No more generic zh when your user needs Traditional Chinese. No more guessing.

Features

Resolve any device locale — one call

import { resolveLocale } from 'pk-lang-codes';

resolveLocale('zh-Hant-TW');
// language: Chinese (中文) | script: Han Traditional | region: Taiwan | direction: ltr

resolveLocale('sr-Latn-RS');
// language: Serbian (српски) | script: Latin | region: Serbia | direction: ltr

What languages does a country need?

257 countries, every spoken language, with population % and official status.

import { getLanguagesForRegion, getOfficialLanguages, getPrimaryLanguage } from 'pk-lang-codes';

// China — 28 languages
getLanguagesForRegion('CN');
// [
//   { languageCode: 'zh', populationPercent: 90, officialStatus: 'official' },
//   { languageCode: 'wuu', populationPercent: 6,   officialStatus: 'none' },       // Wu
//   { languageCode: 'yue', populationPercent: 5.2, officialStatus: 'none' },       // Cantonese
//   { languageCode: 'ug',  populationPercent: 0.55, officialStatus: 'official_regional' },  // Uyghur
//   ...24 more
// ]

// India — 80+ languages, 21 official
getOfficialLanguages('IN');
// hi (official), en (official), bn (official_regional), te, mr, ta, ur, gu, kn, ml...

// Quick lookup
getPrimaryLanguage('JP');  // 'ja'
getPrimaryLanguage('BR');  // 'pt'
getPrimaryLanguage('SA');  // 'ar'

RTL detection — works without script tag

Most real-world locale codes don't include the script (ar-SA not ar-Arab-SA). resolveLocale handles this automatically:

resolveLocale('ar-SA').direction;   // 'rtl' ✓
resolveLocale('he-IL').direction;   // 'rtl' ✓
resolveLocale('fa-IR').direction;   // 'rtl' ✓
resolveLocale('ur-PK').direction;   // 'rtl' ✓
resolveLocale('en-US').direction;   // 'ltr' ✓
resolveLocale('hi-IN').direction;   // 'ltr' ✓
<html dir={resolveLocale(deviceLocale).direction}>

Language selector with native names

import { getLanguage, getAllLanguages, searchLanguages } from 'pk-lang-codes';

getLanguage('fr');  // { name: 'French', nativeName: 'français', ... }
getLanguage('ja');  // { name: 'Japanese', nativeName: '日本語', ... }
getLanguage('ar');  // { name: 'Arabic', nativeName: 'العربية', ... }

// Search in any language
searchLanguages('Deutsch');  // → German
searchLanguages('中文');      // → Chinese
searchLanguages('french');   // → French

BCP 47 parsing & validation

import { parseBcp47, formatBcp47, isValidBcp47 } from 'pk-lang-codes/bcp47';

parseBcp47('zh-Hant-TW');
// { language: 'zh', script: 'Hant', region: 'TW', variants: [], privateUse: null }

formatBcp47({ language: 'sr', script: 'Latn', region: 'RS' });  // 'sr-Latn-RS'

isValidBcp47('en-US');      // true
isValidBcp47('not valid!'); // false

Script direction lookup

import { getScript } from 'pk-lang-codes/scripts';

getScript('Arab');  // { name: 'Arabic', direction: 'rtl' }
getScript('Hebr');  // { name: 'Hebrew', direction: 'rtl' }
getScript('Latn');  // { name: 'Latin',  direction: 'ltr' }
getScript('Deva');  // { name: 'Devanagari', direction: 'ltr' }

Type-safe — full autocomplete

import type { Iso639_1Code, ScriptCode, RegionCode } from 'pk-lang-codes';

const lang: Iso639_1Code = 'en';    // autocomplete for 184 codes
const script: ScriptCode = 'Latn';  // autocomplete for 226 codes
const region: RegionCode = 'US';    // autocomplete for 249 codes

// Type guards narrow string → literal union
import { isIso639_1Code, getLanguage } from 'pk-lang-codes';

const input: string = req.query.lang;
if (isIso639_1Code(input)) {
  const lang = getLanguage(input);  // fully typed, no cast
}

Tree-Shaking

Import only the module you need — unused data stays out of your bundle:

import { resolveLocale } from 'pk-lang-codes/locale';       // Locale resolution
import { getLanguage } from 'pk-lang-codes/iso639-1';       // 184 languages
import { getLanguageByAlpha3 } from 'pk-lang-codes/iso639-2'; // 485 languages
import { parseBcp47 } from 'pk-lang-codes/bcp47';           // BCP 47 only
import { getScript } from 'pk-lang-codes/scripts';           // 226 scripts
import { getRegion } from 'pk-lang-codes/regions';           // 255 regions

| Entry point | What you get | Size (min) | |---|---|---| | pk-lang-codes/bcp47 | Parse, format, validate BCP 47 tags | ~1 KB | | pk-lang-codes/iso639-1 | 184 languages with native names | ~8 KB | | pk-lang-codes/iso639-2 | 485 three-letter language codes | ~10 KB | | pk-lang-codes/scripts | 226 scripts with LTR/RTL direction | ~8 KB | | pk-lang-codes/regions | 255 countries with alpha-2/3/numeric | ~7 KB | | pk-lang-codes/locale | Full resolver + territory mapping | ~25 KB | | pk-lang-codes | Everything | ~60 KB |

Data Coverage

| Standard | Entries | Key Data | |---|---|---| | ISO 639-1 | 184 languages | English + native names (العربية, 中文, हिन्दी...) | | ISO 639-2 | 485 languages | Bibliographic + terminological codes | | ISO 15924 | 226 scripts | Text direction (LTR/RTL) | | ISO 3166-1 | 255 regions | Alpha-2, alpha-3, numeric | | CLDR | 257 territories | Spoken languages, population %, official status | | BCP 47 | — | Parse, format, validate |

Data Sources

All data is fetched from authoritative upstream sources:

Data is regenerated weekly via CI. Regenerate manually with npm generate.

Package Size

| Metric | Size | |---|---| | npm tarball | 68 KB | | Unpacked (ESM) | 112 KB | | Dependencies | 0 |

Development

npm install      # Install
npm generate     # Fetch + regenerate data
npm build        # Build ESM + CJS + DTS
npm test         # Run 73 tests
npm typecheck    # Type check

License

MIT