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

@timkit/languages

v1.2.0

Published

Language definitions and utilities for internationalization

Readme

@timkit/languages

A comprehensive language and locale definitions package providing structured data for multilingual applications. This package uses a nested architecture where languages contain their translation variants and regional locales for maximum flexibility and data-driven operation.

Installation

npm install @timkit/languages

Core Architecture

This package uses a nested data architecture that provides a clean, hierarchical structure:

Language (e.g., Spanish)
  ├─ Base info: name, originalName, dir
  ├─ Variants: {"es": "European Spanish", "es-419": "Latin American Spanish"}
  ├─ Default regions: {"es": "es-es"}
  └─ Regions:
      ├─ "es-es": {name: "Spain", code: "es", flag: "es.svg", variant: "es"}
      ├─ "es-mx": {name: "Mexico", code: "mx", flag: "mx.svg", variant: "es-419"}
      └─ ...

Why Nested Architecture?

This architecture provides several key benefits:

  • Data-driven: No hardcoded logic - all mappings are in the data
  • Hierarchical: Clear parent-child relationships between languages, variants, and regions
  • Efficient storage: Multiple regions can share one translation variant (e.g., all Latin American countries use es-419)
  • Type-safe: Full TypeScript support with readonly data structures
  • Future-proof: Adding new languages/regions requires only data changes, no code changes

How It Works

const LANGS = {
  "es": {
    name: "Spanish",
    originalName: "Español",
    dir: "ltr",
    variants: {
      "es": "European Spanish",
      "es-419": "Latin American Spanish"
    },
    defaultRegion: {"es": "es-es"},
    regions: {
      "es-es": {name: "Spain", code: "es", flag: "es.svg", variant: "es"},
      "es-mx": {name: "Mexico", code: "mx", flag: "mx.svg", variant: "es-419"},
      // ... more regions
    }
  }
}

Data Structures

Lang Interface

interface Lang {
  name: string;                      // English name (e.g., "Spanish", "Arabic")
  originalName: string;              // Native name (e.g., "Español", "العربية")
  dir: "ltr" | "rtl";               // Text direction
  variants: Record<string, string>;  // Translation variants (BCP 47)
  defaultRegion: Record<string, string>; // Default region for each variant
  regions: Record<string, RegionInfo>;   // Regional locales
}

RegionInfo Interface

interface RegionInfo {
  name: string;    // Region name (e.g., "Mexico", "Spain")
  code: string;    // Country code (e.g., "mx", "es")
  flag: string;    // Flag SVG filename (e.g., "mx.svg")
  variant: string; // Translation variant this region uses (e.g., "es-419")
}

DbLanguageFormat Interface

interface DbLanguageFormat {
  lang: string;    // Language code (e.g., "es")
  variant: string; // Variant for translation lookup (e.g., "es-419")
  region: string;  // Full region code (e.g., "es-mx")
  url: string;     // URL segment / country code (e.g., "mx")
}

Usage Examples

Basic Usage

import { getLang, getRegion, getVariantForRegion, LANGS } from '@timkit/languages';

// Get base language information
const lang = getLang('es');
console.log(lang);
// {
//   name: "Spanish",
//   originalName: "Español",
//   dir: "ltr",
//   variants: { "es": "European Spanish", "es-419": "Latin American Spanish" },
//   defaultRegion: { "es": "es-es" },
//   regions: { ... }
// }

// Get regional locale information
const region = getRegion('es-mx');
console.log(region);
// {
//   name: "Mexico",
//   code: "mx",
//   flag: "mx.svg",
//   variant: "es-419"
// }

// Get the translation variant for a region
const variant = getVariantForRegion('es', 'es-mx'); // "es-419"

Understanding Translation Sharing

import { getVariantForRegion, getRegionsByVariant } from '@timkit/languages';

// All Latin American regions share the same translation variant
console.log(getVariantForRegion('es', 'es-mx')); // "es-419"
console.log(getVariantForRegion('es', 'es-ar')); // "es-419"
console.log(getVariantForRegion('es', 'es-cl')); // "es-419"

// Spain uses a different variant
console.log(getVariantForRegion('es', 'es-es')); // "es"

// Find all regions sharing Latin American Spanish
const latinAmericanRegions = getRegionsByVariant('es-419');
console.log(latinAmericanRegions); // ["es-mx", "es-ar", "es-cl", "es-co"]

// Romanian is shared between Romania and Moldova
console.log(getVariantForRegion('ro', 'ro-ro')); // "ro"
console.log(getVariantForRegion('ro', 'ro-md')); // "ro" - same translation!

Building DB Format for Storage

import { buildDbFormat } from '@timkit/languages';

// Get complete database format for a region
const dbFormat = buildDbFormat('es-mx');
console.log(dbFormat);
// {
//   lang: "es",
//   variant: "es-419",  // Use this for translation lookup
//   region: "es-mx",    // Full region identifier
//   url: "mx"           // URL segment
// }

// Use in your database:
await db.siteLanguages.create({
  data: {
    siteId: 'site-123',
    ...buildDbFormat('es-mx')
  }
});

Building a Language Selector

import {
  getLangsArray,
  getLanguageRegionsArray,
  getVariant
} from '@timkit/languages';

function buildLanguageSelector() {
  const languages = getLangsArray();

  return languages.map(lang => ({
    code: lang.code,
    name: lang.name,
    originalName: lang.originalName,
    dir: lang.dir,
    regions: getLanguageRegionsArray(lang.code).map(region => ({
      code: region.code,
      name: region.name,
      flag: `/flags/${region.flag}`,
      variantName: getVariant(region.variant)
    }))
  }));
}

// Result structure:
// [
//   {
//     code: "es",
//     name: "Spanish",
//     originalName: "Español",
//     dir: "ltr",
//     regions: [
//       {
//         code: "es-es",
//         name: "Spain",
//         flag: "/flags/es.svg",
//         variantName: "European Spanish"
//       },
//       {
//         code: "es-mx",
//         name: "Mexico",
//         flag: "/flags/mx.svg",
//         variantName: "Latin American Spanish"
//       },
//       ...
//     ]
//   },
//   ...
// ]

RTL Language Handling

import { isRTL, getTextDirection, getRTLLangs } from '@timkit/languages';

// Check if a language uses right-to-left text
if (isRTL('ar')) {
  document.dir = 'rtl';
}

// Get text direction
const dir = getTextDirection('he'); // "rtl"

// Get all RTL language codes
const rtlLangs = getRTLLangs();
console.log(rtlLangs); // ["ar", "he", "fa", "ur"]

Database Integration Example

import {
  buildDbFormat,
  getLanguageCode,
  getLang,
  getRegion,
  getRegionsByVariant
} from '@timkit/languages';

async function setupSiteLanguage(regionCode: string) {
  // Get complete DB format
  const dbFormat = buildDbFormat(regionCode);
  if (!dbFormat) {
    throw new Error(`Invalid region: ${regionCode}`);
  }

  // Store in database
  await db.siteLanguages.create({
    data: {
      siteId: 'site-123',
      lang: dbFormat.lang,
      variant: dbFormat.variant,  // Use for translation queries
      region: dbFormat.region,
      url: dbFormat.url
    }
  });

  // Fetch translations using the variant
  const translations = await db.translations.findMany({
    where: {
      siteId: 'site-123',
      variant: dbFormat.variant
    }
  });

  return translations;
}

// Example: Setting up Mexican Spanish
await setupSiteLanguage('es-mx');
// Stores: { lang: "es", variant: "es-419", region: "es-mx", url: "mx" }
// All Latin American sites will share "es-419" translations

API Reference

Core Collections

LANGS

const LANGS: Record<string, Lang>

Nested collection of 48 languages with all their variants and regions.

Access examples:

LANGS.es.name                    // "Spanish"
LANGS.es.variants                // { "es": "European Spanish", "es-419": "..." }
LANGS.es.regions['es-mx']        // { name: "Mexico", code: "mx", ... }
LANGS.ar.dir                     // "rtl"

LANG_CODES

const LANG_CODES: LangCode[]     // All 48 language codes

Language Functions

getLang(code: string): Lang | undefined

Get complete language information including nested variants and regions.

const spanish = getLang('es');
// Returns entire Spanish object with variants and regions

isLangCode(code: string): code is LangCode

Type guard to check if a string is a valid language code.

if (isLangCode('es')) {
  const lang = LANGS[code]; // Type-safe
}

searchLanguage(query: string): LangCode[]

Search for languages by English or native name (case-insensitive).

searchLanguage('Spanish');  // ["es"]
searchLanguage('español');  // ["es"]
searchLanguage('中文');      // ["zh"]

Variant Functions

getVariant(variantCode: string): string | undefined

Get the display name for a translation variant.

getVariant('es-419'); // "Latin American Spanish"
getVariant('ar');     // "Modern Standard Arabic"

getVariantForRegion(langCode: string, regionCode: string): string | undefined

Data-driven - Get which translation variant a region uses. No hardcoded logic - reads directly from the data.

getVariantForRegion('es', 'es-mx'); // "es-419"
getVariantForRegion('es', 'es-es'); // "es"
getVariantForRegion('en', 'en-au'); // "en-gb"

getVariantName(regionCode: string): string

Get the translation variant display name for a region.

getVariantName('es-mx'); // "Latin American Spanish"
getVariantName('en-gb'); // "British English"

getAllVariantCodes(): string[]

Get all translation variant codes across all languages.

const variants = getAllVariantCodes();
// ["af", "ar", "es", "es-419", "en-gb", "en-us", ...]

getRegionsByVariant(variantCode: string): string[]

Get all regions that use a specific translation variant.

getRegionsByVariant('es-419');
// ["es-mx", "es-ar", "es-cl", "es-co"]

getRegionsByVariant('en-gb');
// ["en-gb", "en-au", "en-ie"]

isValidVariant(variantCode: string): boolean

Check if a variant code exists.

isValidVariant('es-419'); // true
isValidVariant('xx-xx');  // false

Region Functions

getRegion(regionCode: string): RegionInfo | undefined

Data-driven - Get region information. Searches through LANGS to find the region.

const mexico = getRegion('es-mx');
// {
//   name: "Mexico",
//   code: "mx",
//   flag: "mx.svg",
//   variant: "es-419"
// }

getLanguageCode(regionCode: string): string | undefined

Data-driven - Extract language code from a region. Searches through LANGS to find which language owns the region.

getLanguageCode('es-mx'); // "es"
getLanguageCode('en-us'); // "en"
getLanguageCode('invalid'); // undefined

getAllRegionCodes(): string[]

Get all region codes across all languages.

const regions = getAllRegionCodes();
// ["af-za", "af-na", "ar-sa", "ar-eg", ...]

isValidRegion(regionCode: string): boolean

Check if a region code exists.

isValidRegion('es-mx'); // true
isValidRegion('xx-xx'); // false

Database Functions

buildDbFormat(regionCode: string): DbLanguageFormat | undefined

Build complete database storage format from a region code.

const dbFormat = buildDbFormat('es-mx');
// {
//   lang: "es",
//   variant: "es-419",
//   region: "es-mx",
//   url: "mx"
// }

getLanguageWithDefaults(langCode: string)

Get complete language info with default selections pre-populated.

const spanish = getLanguageWithDefaults('es');
// {
//   lang: { ... full Spanish object },
//   defaultVariant: "es",
//   defaultRegion: "es-es",
//   defaultDbFormat: { lang: "es", variant: "es", region: "es-es", url: "es" }
// }

Language-Specific Functions

getLanguageVariants(langCode: string): Record<string, string> | undefined

Get all translation variants for a specific language.

getLanguageVariants('es');
// { "es": "European Spanish", "es-419": "Latin American Spanish" }

getLanguageRegions(langCode: string): Record<string, RegionInfo> | undefined

Get all regions for a specific language.

const spanishRegions = getLanguageRegions('es');
// {
//   "es-es": { name: "Spain", code: "es", flag: "es.svg", variant: "es" },
//   "es-mx": { name: "Mexico", code: "mx", flag: "mx.svg", variant: "es-419" },
//   ...
// }

getLanguageRegionsArray(langCode: string)

Get language regions as an array.

const regions = getLanguageRegionsArray('es');
// [
//   { code: "es-es", name: "Spain", flag: "es.svg", variant: "es" },
//   { code: "es-mx", name: "Mexico", flag: "mx.svg", variant: "es-419" },
//   ...
// ]

getDefaultRegion(langCode: string): string | undefined

Get the default region for a language.

getDefaultRegion('es'); // "es-es"
getDefaultRegion('en'); // "en-gb"

getDefaultRegionForVariant(langCode: string, variantCode: string)

Get the default region for a specific variant.

getDefaultRegionForVariant('es', 'es'); // "es-es"

Display Functions

getDisplayName(regionCode: string): string

Get full display name combining language and region.

getDisplayName('es-mx'); // "Spanish (Mexico)"
getDisplayName('en-us'); // "English (United States)"

getFlagPath(regionCode: string): string

Get the flag SVG filename for a region.

getFlagPath('es-mx'); // "mx.svg"

Text Direction Functions

getTextDirection(langCode: string): "ltr" | "rtl"

Get text direction for a language.

getTextDirection('ar'); // "rtl"
getTextDirection('en'); // "ltr"

isRTL(langCode: string): boolean

Check if a language uses right-to-left text.

isRTL('ar'); // true
isRTL('he'); // true
isRTL('en'); // false

getRTLLangs(): LangCode[]

Get all RTL language codes.

getRTLLangs(); // ["ar", "he", "fa", "ur"]

getLTRLangs(): LangCode[]

Get all LTR language codes (44 languages).

Array Conversion Functions

getLangsArray(): Array<Lang & { code: LangCode }>

Convert LANGS to array format with language codes.

const langs = getLangsArray();
// [
//   {
//     code: "es",
//     name: "Spanish",
//     originalName: "Español",
//     dir: "ltr",
//     variants: { ... },
//     regions: { ... }
//   },
//   ...
// ]

getVariantsArray(): Array<{ code: string; name: string; lang: string }>

Get all variants as an array with their parent language.

const variants = getVariantsArray();
// [
//   { code: "es", name: "European Spanish", lang: "es" },
//   { code: "es-419", name: "Latin American Spanish", lang: "es" },
//   ...
// ]

getRegionsArray(): Array<RegionInfo & { locale: string; lang: string }>

Get all regions as an array with full locale codes and parent language.

const regions = getRegionsArray();
// [
//   {
//     locale: "es-mx",
//     lang: "es",
//     name: "Mexico",
//     code: "mx",
//     flag: "mx.svg",
//     variant: "es-419"
//   },
//   ...
// ]

Supported Languages & Translation Variants

The package includes 48 languages with multiple translation variants for languages with regional differences.

Languages with Multiple Translation Variants

Spanish (2 variants)

  • European Spanish (es): Spain
  • Latin American Spanish (es-419): Mexico, Argentina, Chile, Colombia

English (2 variants)

  • British English (en-gb): United Kingdom, Ireland, Australia
  • American English (en-us): United States, Canada

Portuguese (2 variants)

  • European Portuguese (pt): Portugal
  • Brazilian Portuguese (pt-br): Brazil

French (2 variants)

  • French (fr): France
  • Canadian French (fr-ca): Canada

Chinese (2 variants)

  • Simplified Chinese (zh-hans): China
  • Traditional Chinese (zh-hant): Taiwan

Shared Translation Variants (Efficiency)

Multiple regions share the same translation to reduce duplication:

  • Romanian (ro): Romania, Moldova
  • Modern Standard Arabic (ar): Saudi Arabia, Egypt, UAE
  • German (de): Germany, Austria, Switzerland
  • Dutch (nl): Netherlands, Belgium
  • Bengali (bn): Bangladesh, India
  • Swahili (sw): Kenya, Tanzania
  • Afrikaans (af): South Africa, Namibia

Complete Language List (48 languages)

African Languages:

  • Afrikaans (af), Akan (ak), Swahili (sw)

Arabic (RTL):

  • Arabic (ar) - Modern Standard Arabic shared across all regions

Asian Languages:

  • Bengali (bn), Chinese (zh), Filipino (fil), Hindi (hi), Indonesian (id), Japanese (ja), Korean (ko), Malay (ms), Thai (th), Vietnamese (vi)

European Languages:

  • Albanian (sq), Bulgarian (bg), Catalan (ca), Croatian (hr), Czech (cs), Danish (da), Dutch (nl), English (en), Estonian (et), Finnish (fi), French (fr), German (de), Greek (el), Hungarian (hu), Icelandic (is), Italian (it), Latvian (lv), Lithuanian (lt), Maltese (mt), Norwegian (no), Polish (pl), Portuguese (pt), Romanian (ro), Serbian (sr), Slovak (sk), Slovenian (sl), Spanish (es), Swedish (sv)

Middle Eastern Languages (RTL):

  • Hebrew (he), Persian (fa), Urdu (ur)

Other:

  • Russian (ru), Turkish (tr), Ukrainian (uk)

TypeScript Support

Full TypeScript support with comprehensive type definitions:

import type {
  Lang,
  RegionInfo,
  DbLanguageFormat,
  LangCode
} from '@timkit/languages';

// Type-safe access
function setupLanguage(langCode: LangCode) {
  const lang = LANGS[langCode]; // Fully typed
  // ...
}

// Type guard for runtime validation
function handleUserInput(input: string) {
  if (isLangCode(input)) {
    // input is now typed as LangCode
    setupLanguage(input);
  }
}

Data-Driven Architecture

All functions are data-driven with no hardcoded logic:

  • getLanguageCode() - Searches LANGS to find which language owns a region
  • getVariantForRegion() - Reads variant directly from region data
  • getRegion() - Searches LANGS to find region information

Benefits:

  • Adding new languages requires only data changes
  • No code modifications needed for new regions/variants
  • Consistent behavior across all functions
  • Easy to maintain and extend

Module Formats

Supports both CommonJS and ES Modules:

// ESM
import { LANGS, getLang, buildDbFormat } from '@timkit/languages';

// CommonJS
const { LANGS, getLang, buildDbFormat } = require('@timkit/languages');

Testing

Comprehensive test suite with 89 tests:

npm test              # Run all tests
npm run test:watch    # Watch mode
npm run test:coverage # With coverage

Development

npm install       # Install dependencies
npm run build     # Build for production (CJS, ESM, TypeScript definitions)
npm run dev       # Development mode with watch
npm test          # Run tests

License

MIT