CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-language-tags

Work with IANA language tags based on BCP 47 standards for validation, parsing, and manipulation of language tags and subtags

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

search-discovery.mddocs/

Search and Discovery

Advanced search functionality for finding tags and subtags by description, plus utilities for working with macrolanguages and specific subtag types.

Capabilities

Search Function

Search for tags and subtags by description with support for regular expressions and case-insensitive matching.

/**
 * Search for tags and subtags by description
 * @param {string|RegExp} query - Search query string or regular expression
 * @param {boolean} [all=false] - Include grandfathered/redundant tags in results
 * @returns {(Tag|Subtag)[]} Array of matching Tag and Subtag objects
 */
function search(query: string | RegExp, all?: boolean): (Tag | Subtag)[];

Usage Examples:

import { search } from "language-tags";

// Simple string search (case-insensitive)
const frenchResults = search("french");
frenchResults.forEach(result => {
  if (result instanceof Tag) {
    console.log(`Tag: ${result.format()} - ${result.descriptions()[0]}`);
  } else {
    console.log(`Subtag: ${result.format()} (${result.type()}) - ${result.descriptions()[0]}`);
  }
});

// Regular expression search
const englishVariants = search(/^English/);
console.log(`Found ${englishVariants.length} results starting with "English"`);

// Case-sensitive search (when query contains uppercase)
const specificResults = search("United States");
console.log(specificResults[0].subtag); // "us"

// Search with all results including grandfathered tags
const allResults = search("chinese", true);
console.log(`Total results: ${allResults.length}`);

Macrolanguage Functions

Work with macrolanguages and their constituent individual languages.

/**
 * Get all individual languages for a given macrolanguage subtag
 * @param {string} macrolanguage - The macrolanguage subtag code
 * @returns {Subtag[]} Array of individual language Subtag objects
 * @throws {Error} If the provided code is not a macrolanguage
 */
function languages(macrolanguage: string): Subtag[];

Usage Examples:

import { languages } from "language-tags";

// Get all Chinese language variants
try {
  const chineseLanguages = languages("zh");
  console.log(`Chinese has ${chineseLanguages.length} individual languages:`);
  
  chineseLanguages.forEach(lang => {
    console.log(`- ${lang.format()}: ${lang.descriptions()[0]}`);
  });
  // Output includes: cmn (Mandarin Chinese), yue (Yue Chinese), etc.
  
} catch (error) {
  console.log("Not a macrolanguage");
}

// Check Arabic variants
const arabicLanguages = languages("ar");
arabicLanguages.forEach(lang => {
  console.log(`${lang.format()}: ${lang.descriptions().join(", ")}`);
});

Specific Type Lookup Functions

Convenience functions for looking up specific types of subtags.

/**
 * Get a language-type subtag by code
 * @param {string} subtag - The subtag code to look up
 * @returns {Subtag|null} Language Subtag object or null if not found
 */
function language(subtag: string): Subtag | null;

/**
 * Get a region-type subtag by code  
 * @param {string} subtag - The subtag code to look up
 * @returns {Subtag|null} Region Subtag object or null if not found
 */
function region(subtag: string): Subtag | null;

/**
 * Get a subtag by specific type
 * @param {string} subtag - The subtag code to look up
 * @param {string} type - The specific type to retrieve
 * @returns {Subtag|null} Subtag object of specified type or null if not found
 */
function type(subtag: string, type: string): Subtag | null;

/**
 * Get the registry file date
 * @returns {string} Date string when the IANA registry was last updated (YYYY-MM-DD format)
 */
function date(): string;

Usage Examples:

import { language, region, type } from "language-tags";

// Look up specific language
const english = language("en");
if (english) {
  console.log(english.descriptions()); // ["English"]
  console.log(english.scope()); // null (not a macrolanguage)
}

// Look up specific region
const unitedStates = region("US");
if (unitedStates) {
  console.log(`${unitedStates.format()}: ${unitedStates.descriptions().join(", ")}`); // "US: United States"
}

// Look up by specific type
const hanScript = type("Hans", "script");
if (hanScript) {
  console.log(`${hanScript.format()}: ${hanScript.descriptions().join(", ")}`); // "Hans: Han (Simplified variant)"
}

// Handle not found cases
const nonexistent = language("xyz");
if (!nonexistent) {
  console.log("Language code 'xyz' not found");
}

// Get registry information
const registryDate = date();
console.log(`Registry last updated: ${registryDate}`); // "Registry last updated: 2023-12-11"

// Look up different types for the same code
const zhLanguage = type("zh", "language");
const zhMacro = type("zh", "macrolanguage");
console.log(`zh as language: ${zhLanguage?.descriptions()[0]}`);
console.log(`zh as macrolanguage: ${zhMacro?.descriptions()[0]}`);

Advanced Search Patterns

Find Similar Languages

import { search, languages } from "language-tags";

function findSimilarLanguages(query) {
  // Search by description
  const results = search(query);
  
  // Filter for language subtags only
  const languageResults = results.filter(result => 
    result.type && result.type() === "language"
  );
  
  // Also check if query is a macrolanguage
  try {
    const variants = languages(query.toLowerCase());
    return {
      similar: languageResults,
      variants: variants
    };
  } catch {
    return {
      similar: languageResults,
      variants: []
    };
  }
}

const chineseInfo = findSimilarLanguages("Chinese");
console.log(`Similar languages: ${chineseInfo.similar.length}`);
console.log(`Chinese variants: ${chineseInfo.variants.length}`);

Find Regions for Language

import { search } from "language-tags";

function findRegionsForLanguage(languageName) {
  // Search for the language name
  const results = search(languageName);
  
  // Find regions mentioned in descriptions
  const regions = [];
  results.forEach(result => {
    if (result.type && result.type() === "region") {
      const descriptions = result.descriptions();
      if (descriptions.some(desc => 
        desc.toLowerCase().includes(languageName.toLowerCase())
      )) {
        regions.push(result);
      }
    }
  });
  
  return regions;
}

const spanishRegions = findRegionsForLanguage("spanish");
spanishRegions.forEach(region => {
  console.log(`${region.subtag}: ${region.descriptions()[0]}`);
});

Validate Tag Components by Search

import { search, language, region, type } from "language-tags";

function validateAndDescribe(lang, script, reg) {
  const results = {};
  
  // Validate language
  const langSubtag = language(lang);
  if (langSubtag) {
    results.language = {
      code: lang,
      name: langSubtag.descriptions()[0],
      valid: true
    };
  } else {
    // Try searching for similar
    const similar = search(lang).filter(r => r.type && r.type() === "language");
    results.language = {
      code: lang,
      valid: false,
      suggestions: similar.slice(0, 3).map(s => ({
        code: s.subtag,
        name: s.descriptions()[0]
      }))
    };
  }
  
  // Validate script if provided
  if (script) {
    const scriptSubtag = type(script, "script");
    if (scriptSubtag) {
      results.script = {
        code: script,
        name: scriptSubtag.descriptions()[0],
        valid: true
      };
    } else {
      const similar = search(script).filter(r => r.type && r.type() === "script");
      results.script = {
        code: script,
        valid: false,
        suggestions: similar.slice(0, 3).map(s => ({
          code: s.subtag,
          name: s.descriptions()[0]
        }))
      };
    }
  }
  
  // Validate region if provided
  if (reg) {
    const regionSubtag = region(reg);
    if (regionSubtag) {
      results.region = {
        code: reg,
        name: regionSubtag.descriptions()[0],
        valid: true
      };
    } else {
      const similar = search(reg).filter(r => r.type && r.type() === "region");
      results.region = {
        code: reg,
        valid: false,
        suggestions: similar.slice(0, 3).map(s => ({
          code: s.subtag,
          name: s.descriptions()[0]
        }))
      };
    }
  }
  
  return results;
}

// Example usage
const validation = validateAndDescribe("en", "Latn", "US");
console.log(JSON.stringify(validation, null, 2));

Search Result Types

Search results can be either Tag or Subtag objects. You can distinguish between them:

import { search } from "language-tags";
import Tag from "language-tags/lib/Tag.js";
import Subtag from "language-tags/lib/Subtag.js";

const results = search("english");
results.forEach(result => {
  if (result instanceof Tag) {
    console.log(`Complete tag: ${result.format()}`);
    console.log(`Type: ${result.type()}`);
    console.log(`Valid: ${result.valid()}`);
  } else if (result instanceof Subtag) {
    console.log(`Subtag: ${result.subtag}`);
    console.log(`Type: ${result.type()}`);
    console.log(`Descriptions: ${result.descriptions().join(", ")}`);
  }
  
  // Alternative approach using duck typing
  if (result.type && typeof result.type === 'function') {
    // It's a Subtag (has type() method)
    console.log(`Subtag result: ${result.format()}`);
  } else {
    // It's a Tag (has format() but no type() method in same way)
    console.log(`Tag result: ${result.format()}`);
  }
});

Performance Notes

  • Search function returns results sorted by description length for better precision matching
  • Case-insensitive searches are more expensive than exact matches
  • Regular expression searches provide the most flexibility but may be slower on large result sets
  • Use specific type lookup functions (language, region, type) when you know the expected subtag type for better performance

docs

index.md

search-discovery.md

subtag-operations.md

tag-operations.md

tile.json