Work with IANA language tags based on BCP 47 standards for validation, parsing, and manipulation of language tags and subtags
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Utilities for working with individual language subtags including lookup, filtering, and type checking. These functions help analyze individual components of language tags and work with the IANA language subtag registry.
Look up one or more subtags and return detailed Subtag objects for each possible type.
/**
* Look up one or more subtags. Returns an array of Subtag objects for all possible types.
* @param {string|string[]} subtags - Single subtag string or array of subtag strings
* @returns {Subtag[]} Array of Subtag objects (one for each valid type)
*/
function subtags(subtags: string | string[]): Subtag[];Usage Examples:
import { subtags } from "language-tags";
// Single subtag lookup
const enSubtags = subtags("en");
console.log(enSubtags.length); // 1
console.log(enSubtags[0].type()); // "language"
console.log(enSubtags[0].descriptions()); // ["English"]
// Multiple subtags
const results = subtags(["en", "US", "Hans"]);
results.forEach(subtag => {
console.log(`${subtag.format()}: ${subtag.type()} - ${subtag.descriptions()[0]}`);
});
// Output:
// en: language - English
// US: region - United States
// Hans: script - Han (Simplified variant)
// Subtag with multiple possible types
const zhSubtags = subtags("zh");
zhSubtags.forEach(subtag => {
console.log(`Type: ${subtag.type()}, Scope: ${subtag.scope()}`);
});Returns an array of codes that are not registered subtags in the IANA registry.
/**
* Filter out valid subtags, returning only unregistered codes
* @param {string[]} subtags - Array of subtag strings to check
* @returns {string[]} Array of subtag strings that are not registered
*/
function filter(subtags: string[]): string[];Usage Examples:
import { filter } from "language-tags";
// Mix of valid and invalid subtags
const mixed = ["en", "invalid", "US", "xyz", "Hans"];
const invalid = filter(mixed);
console.log(invalid); // ["invalid", "xyz"]
// All valid subtags
const valid = ["en", "US", "CA"];
const none = filter(valid);
console.log(none); // []
// Check if any subtags are invalid
const userInput = ["fr", "CH", "Latin"];
const invalidSubtags = filter(userInput);
if (invalidSubtags.length > 0) {
console.log(`Invalid subtags: ${invalidSubtags.join(", ")}`);
}Get all possible types for a subtag, excluding grandfathered and redundant types.
/**
* Get all possible types for a subtag
* @param {string} subtag - The subtag to check
* @returns {string[]} Array of type strings ("language", "region", "script", etc.)
*/
function types(subtag: string): string[];Usage Examples:
import { types } from "language-tags";
// Language subtag
console.log(types("en")); // ["language"]
// Region subtag
console.log(types("US")); // ["region"]
// Script subtag
console.log(types("Hans")); // ["script"]
// Invalid subtag
console.log(types("invalid")); // []
// Check if subtag can be used as a specific type
const subtag = "zh";
const availableTypes = types(subtag);
if (availableTypes.includes("language")) {
console.log(`${subtag} can be used as a language subtag`);
}Methods for retrieving metadata about individual subtags.
/**
* Get the type of this subtag
* @returns {string} The subtag type ("language", "region", "script", "variant", "extlang")
*/
type(): string;
/**
* Get description strings for this subtag
* @returns {string[]} Array of description strings
*/
descriptions(): string[];
/**
* Get the preferred subtag if this one is deprecated
* @returns {Subtag|null} Preferred Subtag object or null if not deprecated
*/
preferred(): Subtag | null;
/**
* Get the deprecation date if this subtag is deprecated
* @returns {string|null} Date string or null if not deprecated
*/
deprecated(): string | null;
/**
* Get the date when this subtag was added to the registry
* @returns {string|undefined} Date string in YYYY-MM-DD format or undefined if not available
*/
added(): string | undefined;
/**
* Get comments associated with this subtag
* @returns {string[]} Array of comment strings
*/
comments(): string[];
/**
* Get the scope of this subtag (for language types)
* @returns {string|null} Scope string or null if not applicable
*/
scope(): string | null;
/**
* For language/extlang subtags, get the default script subtag
* @returns {Subtag|null} Default Script subtag or null if none
*/
script(): Subtag | null;Methods for proper formatting and string conversion.
/**
* Format the subtag according to RFC 5646 case conventions
* @returns {string} Properly formatted subtag string
*/
format(): string;
/**
* Convert subtag to string (same as format())
* @returns {string} Formatted subtag string
*/
toString(): string;Usage Examples:
import { subtags } from "language-tags";
// Get detailed information about a language subtag
const [english] = subtags("en");
console.log(english.type()); // "language"
console.log(english.descriptions()); // ["English"]
console.log(english.added()); // Date when added to registry
console.log(english.scope()); // null (not a macrolanguage)
// Work with a region subtag
const [unitedStates] = subtags("US");
console.log(unitedStates.type()); // "region"
console.log(unitedStates.descriptions()); // ["United States"]
console.log(unitedStates.format()); // "US"
// Check for deprecated subtags
const [subtag] = subtags("some-code");
if (subtag.deprecated()) {
const preferred = subtag.preferred();
console.log(`${subtag.format()} is deprecated, use ${preferred.format()} instead`);
}
// Language with default script
const [chinese] = subtags("zh").filter(s => s.type() === "language");
const defaultScript = chinese.script();
if (defaultScript) {
console.log(`Default script for Chinese: ${defaultScript.format()}`);
}The Subtag class provides constants for validation error types:
static ERR_NONEXISTENT = 1; // Subtag does not exist in registry
static ERR_TAG = 2; // Input is a tag, not a subtagUsage Examples:
import { Subtag } from "language-tags";
// Handle subtag construction errors
try {
const subtag = new Subtag("nonexistent", "language");
} catch (error) {
if (error.code === Subtag.ERR_NONEXISTENT) {
console.log("Subtag not found in registry");
}
}import { types, filter } from "language-tags";
function validateTagComponents(components) {
// Check if all components are valid
const invalid = filter(components);
if (invalid.length > 0) {
throw new Error(`Invalid components: ${invalid.join(", ")}`);
}
// Check expected types
const [lang, script, region] = components;
if (!types(lang).includes("language")) {
throw new Error(`${lang} is not a valid language code`);
}
if (script && !types(script).includes("script")) {
throw new Error(`${script} is not a valid script code`);
}
if (region && !types(region).includes("region")) {
throw new Error(`${region} is not a valid region code`);
}
}
validateTagComponents(["en", "Latn", "US"]); // OK
validateTagComponents(["en", "Invalid", "US"]); // Throws errorimport { subtags, types } from "language-tags";
function buildTag(language, script, region) {
const components = [language, script, region].filter(Boolean);
// Validate each component exists and has correct type
components.forEach((component, index) => {
const expectedTypes = ["language", "script", "region"];
const componentTypes = types(component);
if (!componentTypes.includes(expectedTypes[index])) {
throw new Error(`${component} is not a valid ${expectedTypes[index]}`);
}
});
return components.join("-");
}
const tag = buildTag("zh", "Hans", "CN");
console.log(tag); // "zh-Hans-CN"