@timkit/languages
v1.2.0
Published
Language definitions and utilities for internationalization
Maintainers
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/languagesCore 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" translationsAPI 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 codesLanguage 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 regionsisLangCode(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'); // falseRegion 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'); // undefinedgetAllRegionCodes(): 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'); // falseDatabase 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'); // falsegetRTLLangs(): 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 regiongetVariantForRegion()- Reads variant directly from region datagetRegion()- 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 coverageDevelopment
npm install # Install dependencies
npm run build # Build for production (CJS, ESM, TypeScript definitions)
npm run dev # Development mode with watch
npm test # Run testsLicense
MIT
