Socket
Socket
Sign inDemoInstall

language-tags

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

language-tags - npm Package Compare versions

Comparing version 1.0.5 to 1.0.6

12

lib/index.js

@@ -11,7 +11,7 @@ /**

var Tag = require('./Tag');
var Subtag = require('./Subtag');
var Tag = require('./Tag.js');
var Subtag = require('./Subtag.js');
var index = require('language-subtag-registry/data/json/index');
var registry = require('language-subtag-registry/data/json/registry');
var index = require('language-subtag-registry/data/json/index.json');
var registry = require('language-subtag-registry/data/json/registry.json');

@@ -109,3 +109,3 @@ var tags = function(tag) {

macrolanguage = macrolanguage.toLowerCase();
if (!require('language-subtag-registry/data/json/macrolanguage')[macrolanguage]) {
if (!require('language-subtag-registry/data/json/macrolanguage.json')[macrolanguage]) {
throw new Error('\'' + macrolanguage + '\' is not a macrolanguage.');

@@ -143,3 +143,3 @@ }

tags.date = function() {
return require('language-subtag-registry/data/json/meta')['File-Date'];
return require('language-subtag-registry/data/json/meta.json')['File-Date'];
};

@@ -11,115 +11,116 @@ /**

var index = require('language-subtag-registry/data/json/index');
var registry = require('language-subtag-registry/data/json/registry');
var index = require('language-subtag-registry/data/json/index.json');
var registry = require('language-subtag-registry/data/json/registry.json');
module.exports = Subtag;
class Subtag {
static ERR_NONEXISTENT = 1;
static ERR_TAG = 2;
Subtag.ERR_NONEXISTENT = 1;
Subtag.ERR_TAG = 2;
/**
* @param {string} subtag
* @param {string} type
*/
constructor (subtag, type) {
var types, i, record;
function Subtag(subtag, type) {
var types, i, record, error;
// Lowercase for consistency (case is only a formatting convention, not a standard requirement).
subtag = subtag.toLowerCase();
type = type.toLowerCase();
// Lowercase for consistency (case is only a formatting convention, not a standard requirement).
subtag = subtag.toLowerCase();
type = type.toLowerCase();
function error (code, message) {
var err;
error = function(code, message) {
var err;
err = new Error(message);
err.code = code;
err.subtag = subtag;
throw err;
};
err = new Error(message);
err.code = code;
err.subtag = subtag;
throw err;
};
types = index[subtag];
if (!types) {
error(Subtag.ERR_NONEXISTENT, 'Non-existent subtag \'' + subtag + '\'.');
}
types = index[subtag];
if (!types) {
error(Subtag.ERR_NONEXISTENT, 'Non-existent subtag \'' + subtag + '\'.');
i = types[type];
if (!i && 0 !== i) {
error(Subtag.ERR_NONEXISTENT, 'Non-existent subtag \'' + subtag + '\' of type \'' + type + '\'.');
}
record = registry[i];
if (!record.Subtag) {
error(Subtag.ERR_TAG, '\'' + subtag + '\' is a \'' + type + '\' tag.');
}
this.data = { subtag, record, type };
}
i = types[type];
if (!i && 0 !== i) {
error(Subtag.ERR_NONEXISTENT, 'Non-existent subtag \'' + subtag + '\' of type \'' + type + '\'.');
type () {
return this.data.type;
}
record = registry[i];
if (!record.Subtag) {
error(Subtag.ERR_TAG, '\'' + subtag + '\' is a \'' + type + '\' tag.');
descriptions () {
// Every record has one or more descriptions (stored as an array).
return this.data.record.Description;
}
this.data = {};
this.data.subtag = subtag;
this.data.record = record;
this.data.type = type;
}
preferred () {
var type, preferred = this.data.record['Preferred-Value'];
Subtag.prototype.type = function() {
return this.data.type;
};
if (preferred) {
type = this.data.type;
if (type === 'extlang') {
type = 'language';
}
Subtag.prototype.descriptions = function() {
return new Subtag(preferred, type);
}
// Every record has one or more descriptions (stored as an array).
return this.data.record.Description;
};
return null;
}
Subtag.prototype.preferred = function() {
var type, preferred = this.data.record['Preferred-Value'];
script () {
var script = this.data.record['Suppress-Script'];
if (preferred) {
type = this.data.type;
if (type === 'extlang') {
type = 'language';
if (script) {
return new Subtag(script, 'script');
}
return new Subtag(preferred, type);
return null;
}
return null;
};
scope () {
return this.data.record.Scope || null;
}
Subtag.prototype.script = function() {
var script = this.data.record['Suppress-Script'];
deprecated () {
return this.data.record.Deprecated || null;
}
if (script) {
return new Subtag(script, 'script');
added () {
return this.data.record.Added;
}
return null;
};
comments () {
// Comments don't always occur for records, so switch to an empty array if missing.
return this.data.record.Comments || [];
}
Subtag.prototype.scope = function() {
return this.data.record.Scope || null;
};
format () {
var subtag = this.data.subtag;
Subtag.prototype.deprecated = function() {
return this.data.record.Deprecated || null;
};
switch (this.data.type) {
case 'region':
return subtag.toUpperCase();
case 'script':
return subtag[0].toUpperCase() + subtag.slice(1);
}
Subtag.prototype.added = function() {
return this.data.record.Added;
};
return subtag;
}
Subtag.prototype.comments = function() {
// Comments don't always occur for records, so switch to an empty array if missing.
return this.data.record.Comments || [];
};
Subtag.prototype.format = function() {
var subtag = this.data.subtag;
switch (this.data.type) {
case 'region':
return subtag.toUpperCase();
case 'script':
return subtag[0].toUpperCase() + subtag.substr(1);
toString () {
return this.format();
}
}
return subtag;
};
Subtag.prototype.toString = function() {
return this.format();
};
module.exports = Subtag;

@@ -11,396 +11,400 @@ /**

var index = require('language-subtag-registry/data/json/index');
var registry = require('language-subtag-registry/data/json/registry');
var index = require('language-subtag-registry/data/json/index.json');
var registry = require('language-subtag-registry/data/json/registry.json');
var Subtag = require('./Subtag');
var Subtag = require('./Subtag.js');
module.exports = Tag;
class Tag {
static ERR_DEPRECATED = 1;
static ERR_NO_LANGUAGE = 2;
static ERR_UNKNOWN = 3;
static ERR_TOO_LONG = 4;
static ERR_EXTRA_REGION = 5;
static ERR_EXTRA_EXTLANG = 6;
static ERR_EXTRA_SCRIPT = 7;
static ERR_DUPLICATE_VARIANT = 8;
static ERR_WRONG_ORDER = 9;
static ERR_SUPPRESS_SCRIPT = 10;
static ERR_SUBTAG_DEPRECATED = 11;
static ERR_EXTRA_LANGUAGE = 12;
Tag.ERR_DEPRECATED = 1;
Tag.ERR_NO_LANGUAGE = 2;
Tag.ERR_UNKNOWN = 3;
Tag.ERR_TOO_LONG = 4;
Tag.ERR_EXTRA_REGION = 5;
Tag.ERR_EXTRA_EXTLANG = 6;
Tag.ERR_EXTRA_SCRIPT = 7;
Tag.ERR_DUPLICATE_VARIANT = 8;
Tag.ERR_WRONG_ORDER = 9;
Tag.ERR_SUPPRESS_SCRIPT = 10;
Tag.ERR_SUBTAG_DEPRECATED = 11;
Tag.ERR_EXTRA_LANGUAGE = 12;
/** @param {string} tag */
constructor (tag) {
var types;
function Tag(tag) {
var types;
// Lowercase for consistency (case is only a formatting convention, not a standard requirement).
tag = tag.trim().toLowerCase();
// Lowercase for consistency (case is only a formatting convention, not a standard requirement).
tag = tag.trim().toLowerCase();
this.data = { tag };
this.data = {};
this.data.tag = tag;
// Check if the input tag is grandfathered or redundant.
types = index[tag];
if (types && (types.grandfathered || types.redundant)) {
this.data.record = registry[types.grandfathered || types.redundant];
// Check if the input tag is grandfathered or redundant.
types = index[tag];
if (types && (types.grandfathered || types.redundant)) {
this.data.record = registry[types.grandfathered || types.redundant];
}
}
}
Tag.prototype.preferred = function() {
var preferred = this.data.record['Preferred-Value'];
preferred () {
var preferred = this.data.record['Preferred-Value'];
if (preferred) {
return new Tag(preferred);
}
if (preferred) {
return new Tag(preferred);
}
return null;
};
Tag.prototype.subtags = function() {
var codes, data = this.data, subtags = [];
// No subtags if the tag is grandfathered.
if (data.record && this.type() === 'grandfathered') {
return subtags;
return null;
}
codes = data.tag.split('-');
if (!codes.length) {
return subtags;
}
/** @return {Subtag[]} */
subtags () {
var codes, data = this.data, subtags = [];
// Try and find the language tag.
codes.some(function(code, i) {
var types;
// Singletons and anything after are unhandled.
if (code.length < 2) {
return true; // Stop the loop (stop processing after a singleton).
// No subtags if the tag is grandfathered.
if (data.record && this.type() === 'grandfathered') {
return subtags;
}
types = index[code];
// Check for non-existent tag.
if (!types) {
return; // Skip to the next item.
codes = data.tag.split('-');
if (!codes.length) {
return subtags;
}
// Check against undefined because value could be 0.
// Language subtags may only appear at the beginning of the tag, otherwise the subtag type is indeterminate.
if (0 === i && undefined !== types.language) {
subtags.push(new Subtag(code, 'language'));
return;
}
// Try and find the language tag.
codes.some(function (code, i) {
var types;
switch (code.length) {
case 2:
// Singletons and anything after are unhandled.
if (code.length < 2) {
return true; // Stop the loop (stop processing after a singleton).
}
// Should be a region.
if (types.region) {
subtags.push(new Subtag(code, 'region'));
types = index[code];
// Error case: language subtag in the wrong place.
} else if (types.language) {
subtags.push(new Subtag(code, 'language'));
// Check for non-existent tag.
if (!types) {
return; // Skip to the next item.
}
break;
case 3:
// Could be a numeric region code e.g. '001' for 'World'.
if (types.region) {
subtags.push(new Subtag(code, 'region'));
} else if (types.extlang) {
subtags.push(new Subtag(code, 'extlang'));
// Error case: language subtag in the wrong place.
} else if (types.language) {
// Check against undefined because value could be 0.
// Language subtags may only appear at the beginning of the tag, otherwise the subtag type is indeterminate.
if (0 === i && undefined !== types.language) {
subtags.push(new Subtag(code, 'language'));
return;
}
break;
case 4:
switch (code.length) {
case 2:
// Could be a numeric variant.
if (types.variant) {
subtags.push(new Subtag(code, 'variant'));
} else if (types.script) {
subtags.push(new Subtag(code, 'script'));
}
// Should be a region.
if (types.region) {
subtags.push(new Subtag(code, 'region'));
break;
default:
// Error case: language subtag in the wrong place.
} else if (types.language) {
subtags.push(new Subtag(code, 'language'));
}
// Should be a variant.
if (types.variant) {
subtags.push(new Subtag(code, 'variant'));
}
break;
case 3:
break;
}
});
// Could be a numeric region code e.g. '001' for 'World'.
if (types.region) {
subtags.push(new Subtag(code, 'region'));
} else if (types.extlang) {
subtags.push(new Subtag(code, 'extlang'));
return subtags;
};
// Error case: language subtag in the wrong place.
} else if (types.language) {
subtags.push(new Subtag(code, 'language'));
}
Tag.prototype.language = function() {
return this.find('language');
};
break;
case 4:
Tag.prototype.region = function() {
return this.find('region');
};
// Could be a numeric variant.
if (types.variant) {
subtags.push(new Subtag(code, 'variant'));
} else if (types.script) {
subtags.push(new Subtag(code, 'script'));
}
Tag.prototype.script = function() {
return this.find('script');
};
break;
default:
Tag.prototype.find = function(type) {
var i, l, subtag, subtags = this.subtags();
// Should be a variant.
if (types.variant) {
subtags.push(new Subtag(code, 'variant'));
}
for (i = 0, l = subtags.length; i < l; i++) {
subtag = subtags[i];
break;
}
});
if (subtag.type() === type) {
return subtag;
}
return subtags;
}
};
Tag.prototype.valid = function() {
return this.errors().length < 1;
};
language () {
return this.find('language');
}
Tag.prototype.errors = function() {
var error, subtags, data = this.data, errors = [];
region () {
return this.find('region');
}
error = function(code, subtag) {
var err, message;
script () {
return this.find('script');
}
switch (code) {
case Tag.ERR_DEPRECATED:
message = 'The tag \'' + data.tag + '\' is deprecated.';
/** @param {string} type */
find (type) {
var i, l, subtag, subtags = this.subtags();
// Note that a record that contains a 'Deprecated' field and no corresponding 'Preferred-Value' field has no replacement mapping (RFC 5646 section 3.1.6).
if (data.record['Preferred-Value']) {
message += ' Use \'' + data.record['Preferred-Value'] + '\' instead.';
}
for (i = 0, l = subtags.length; i < l; i++) {
subtag = subtags[i];
break;
case Tag.ERR_SUBTAG_DEPRECATED:
message = 'The subtag \'' + subtag + '\' is deprecated.';
break;
case Tag.ERR_NO_LANGUAGE:
if (!data.tag) {
message = 'Empty tag.';
} else {
message = 'Missing language tag in \'' + data.tag + '\'.';
if (subtag.type() === type) {
return subtag;
}
break;
case Tag.ERR_UNKNOWN:
message = 'Unknown code \'' + subtag + '\'';
break;
case Tag.ERR_TOO_LONG:
message = 'The private-use subtag \'' + subtag + '\' is too long.';
break;
case Tag.ERR_EXTRA_LANGUAGE:
case Tag.ERR_EXTRA_EXTLANG:
case Tag.ERR_EXTRA_REGION:
case Tag.ERR_EXTRA_SCRIPT:
message = 'Extra ' + subtag.type() + ' subtag \'' + subtag + '\' found.';
break;
case Tag.ERR_DUPLICATE_VARIANT:
message = 'Duplicate variant subtag \'' + subtag + '\' found.';
break;
case Tag.ERR_WRONG_ORDER:
message = 'The subtag \'' + subtag[0] + '\' should not appear before \'' + subtag[1] + '\'.';
break;
case Tag.ERR_SUPPRESS_SCRIPT:
message = 'The script subtag \'' + subtag + '\' is the same as the language suppress-script.';
break;
}
}
err = new Error(message);
err.code = code;
err.tag = data.tag;
err.subtag = subtag;
errors.push(err);
};
valid () {
return this.errors().length < 1;
}
// Check if the tag is grandfathered and if the grandfathered tag is deprecated (e.g. no-nyn).
if (data.record) {
if (data.record.Deprecated) {
error(Tag.ERR_DEPRECATED);
}
errors () {
var error, subtags, data = this.data, errors = [];
// Only check every subtag if the tag is not explicitly listed as grandfathered or redundant.
return errors;
}
error = function (code, subtag) {
var err, message;
// Check that all subtag codes are meaningful.
data.tag.split('-').some(function(code, i, codes) {
var types;
switch (code) {
case Tag.ERR_DEPRECATED:
message = 'The tag \'' + data.tag + '\' is deprecated.';
// Ignore anything after a singleton.
if (code.length < 2) {
// Note that a record that contains a 'Deprecated' field and no corresponding 'Preferred-Value' field has no replacement mapping (RFC 5646 section 3.1.6).
if (data.record['Preferred-Value']) {
message += ' Use \'' + data.record['Preferred-Value'] + '\' instead.';
}
// Check that each private-use subtag is within the maximum allowed length.
codes.slice(i).forEach(function(code) {
if (code.length > 8) {
error(Tag.ERR_TOO_LONG, code);
}
});
break;
case Tag.ERR_SUBTAG_DEPRECATED:
message = 'The subtag \'' + subtag + '\' is deprecated.';
break;
case Tag.ERR_NO_LANGUAGE:
if (!data.tag) {
message = 'Empty tag.';
} else {
message = 'Missing language tag in \'' + data.tag + '\'.';
}
return true;
}
break;
case Tag.ERR_UNKNOWN:
message = 'Unknown code \'' + subtag + '\'';
break;
case Tag.ERR_TOO_LONG:
message = 'The private-use subtag \'' + subtag + '\' is too long.';
break;
case Tag.ERR_EXTRA_LANGUAGE:
case Tag.ERR_EXTRA_EXTLANG:
case Tag.ERR_EXTRA_REGION:
case Tag.ERR_EXTRA_SCRIPT:
message = 'Extra ' + subtag.type() + ' subtag \'' + subtag + '\' found.';
break;
case Tag.ERR_DUPLICATE_VARIANT:
message = 'Duplicate variant subtag \'' + subtag + '\' found.';
break;
case Tag.ERR_WRONG_ORDER:
message = 'The subtag \'' + subtag[0] + '\' should not appear before \'' + subtag[1] + '\'.';
break;
case Tag.ERR_SUPPRESS_SCRIPT:
message = 'The script subtag \'' + subtag + '\' is the same as the language suppress-script.';
break;
}
types = index[code];
if (!types) {
error(Tag.ERR_UNKNOWN, code);
err = new Error(message);
err.code = code;
err.tag = data.tag;
err.subtag = subtag;
errors.push(err);
};
// Check if the tag is grandfathered and if the grandfathered tag is deprecated (e.g. no-nyn).
if (data.record) {
if (data.record.Deprecated) {
error(Tag.ERR_DEPRECATED);
}
// Only check every subtag if the tag is not explicitly listed as grandfathered or redundant.
return errors;
}
return false; // Continue to the next item.
});
// Check that all subtag codes are meaningful.
data.tag.split('-').some(function (code, i, codes) {
var types;
// Check that first tag is a language tag.
subtags = this.subtags();
if (!subtags.length || 'language' !== subtags[0].type()) {
error(Tag.ERR_NO_LANGUAGE);
return errors;
}
// Ignore anything after a singleton.
if (code.length < 2) {
// Check for more than one of some types and for deprecation.
subtags.forEach(function(subtag, i) {
var type = subtag.type(), language, script, found = this;
// Check that each private-use subtag is within the maximum allowed length.
codes.slice(i).forEach(function (code) {
if (code.length > 8) {
error(Tag.ERR_TOO_LONG, code);
}
});
if (subtag.deprecated()) {
error(Tag.ERR_SUBTAG_DEPRECATED, subtag);
}
return true;
}
if (found[type]) {
found[type].push(subtag);
types = index[code];
if (!types) {
error(Tag.ERR_UNKNOWN, code);
}
return false; // Continue to the next item.
});
// Check that first tag is a language tag.
subtags = this.subtags();
if (!subtags.length || 'language' !== subtags[0].type()) {
error(Tag.ERR_NO_LANGUAGE);
return errors;
}
switch (type) {
case 'language':
if (found.language.length > 1) {
error(Tag.ERR_EXTRA_LANGUAGE, subtag);
}
// Check for more than one of some types and for deprecation.
subtags.forEach(function (subtag, i) {
var type = subtag.type(), language, script, found = this;
break;
case 'region':
if (found.region.length > 1) {
error(Tag.ERR_EXTRA_REGION, subtag);
if (subtag.deprecated()) {
error(Tag.ERR_SUBTAG_DEPRECATED, subtag);
}
break;
case 'extlang':
if (found.extlang.length > 1) {
error(Tag.ERR_EXTRA_EXTLANG, subtag);
if (found[type]) {
found[type].push(subtag);
}
break;
case 'script':
if (found.script.length > 1) {
error(Tag.ERR_EXTRA_SCRIPT, subtag);
switch (type) {
case 'language':
if (found.language.length > 1) {
error(Tag.ERR_EXTRA_LANGUAGE, subtag);
}
// Check if script is same as language suppress-script.
} else {
language = subtags[0];
if ('language' === language.type()) {
script = language.script();
if (script && script.format() === subtag.format()) {
error(Tag.ERR_SUPPRESS_SCRIPT, subtag);
break;
case 'region':
if (found.region.length > 1) {
error(Tag.ERR_EXTRA_REGION, subtag);
}
}
break;
case 'extlang':
if (found.extlang.length > 1) {
error(Tag.ERR_EXTRA_EXTLANG, subtag);
}
break;
case 'script':
if (found.script.length > 1) {
error(Tag.ERR_EXTRA_SCRIPT, subtag);
// Check if script is same as language suppress-script.
} else {
language = subtags[0];
if ('language' === language.type()) {
script = language.script();
if (script && script.format() === subtag.format()) {
error(Tag.ERR_SUPPRESS_SCRIPT, subtag);
}
}
}
break;
case 'variant':
if (found.variant.length > 1 && found.variant.some(function (variant) {
return variant.format() === subtag.format();
})) {
error(Tag.ERR_DUPLICATE_VARIANT, subtag);
}
}
}, {
language: [],
extlang: [],
variant: [],
script: [],
region: []
});
break;
case 'variant':
if (found.variant.length > 1 && found.variant.some(function(variant) {
return variant.format() === subtag.format();
})) {
error(Tag.ERR_DUPLICATE_VARIANT, subtag);
// Check for correct order.
subtags.forEach(function (subtag, i, subtags) {
var priority = this, next = subtags[i + 1];
if (next && priority[subtag.type()] > priority[next.type()]) {
error(Tag.ERR_WRONG_ORDER, [subtag, next]);
}
}
}, {
language: [],
extlang: [],
variant: [],
script: [],
region: []
});
}, {
language: 4,
extlang: 5,
script: 6,
region: 7,
variant: 8
});
// Check for correct order.
subtags.forEach(function(subtag, i, subtags) {
var priority = this, next = subtags[i + 1];
return errors;
}
if (next && priority[subtag.type()] > priority[next.type()]) {
error(Tag.ERR_WRONG_ORDER, [subtag, next]);
type () {
var record = this.data.record;
if (record) {
return record.Type;
}
}, {
language: 4,
extlang: 5,
script: 6,
region: 7,
variant: 8
});
return errors;
};
return 'tag';
}
Tag.prototype.type = function() {
var record = this.data.record;
added () {
var record = this.data.record;
if (record) {
return record.Type;
return record && record.Added;
}
return 'tag';
};
deprecated () {
var record = this.data.record;
Tag.prototype.added = function() {
var record = this.data.record;
return record && record.Deprecated;
}
return record && record.Added;
};
descriptions () {
var record = this.data.record;
Tag.prototype.deprecated = function() {
var record = this.data.record;
if (record && record.Description) {
return record.Description;
}
return record && record.Deprecated;
};
return [];
}
Tag.prototype.descriptions = function() {
var record = this.data.record;
format () {
var tag = this.data.tag;
if (record && record.Description) {
return record.Description;
}
// Format according to algorithm defined in RFC 5646 section 2.1.1.
return tag.split('-').reduce(function (p, c, i, a) {
if (i === 0) {
return c;
}
return [];
};
if (a[i - 1].length === 1) {
return p + '-' + c;
}
Tag.prototype.format = function() {
var tag = this.data.tag;
switch (c.length) {
case 2:
return p + '-' + c.toUpperCase();
case 4:
return p + '-' + c[0].toUpperCase() + c.substr(1);
}
// Format according to algorithm defined in RFC 5646 section 2.1.1.
return tag.split('-').reduce(function(p, c, i, a) {
if (i === 0) {
return c;
}
if (a[i - 1].length === 1) {
return p + '-' + c;
}
});
}
}
switch (c.length) {
case 2:
return p + '-' + c.toUpperCase();
case 4:
return p + '-' + c[0].toUpperCase() + c.substr(1);
}
return p + '-' + c;
});
};
module.exports = Tag;
{
"name": "language-tags",
"version": "1.0.5",
"implements": ["CommonJS/Modules/1.0"],
"version": "1.0.6",
"implements": [
"CommonJS/Modules/1.0"
],
"description": "Work with IANA language tags.",
"main": "lib/index.js",
"homepage": "https://github.com/mattcg/language-tags",
"author": "Matthew Caruana Galizia <m@m.cg>",
"author": "Matthew Caruana Galizia <mattcg@gmail.com>",
"repository": {

@@ -29,9 +31,12 @@ "type": "git",

"dependencies": {
"language-subtag-registry": "~0.3.2"
"language-subtag-registry": "^0.3.20"
},
"devDependencies": {
"mocha": "~2.3.4",
"mocha": "~6.2.0",
"istanbul": "~0.4.2",
"coveralls": "~2.11.6"
}
"coveralls": "~3.0.5"
},
"files": [
"/lib"
]
}

@@ -6,3 +6,3 @@ # IANA Language Tags for JavaScript #

Based on [BCP 47](http://tools.ietf.org/html/bcp47) ([RFC 5646](http://tools.ietf.org/html/rfc5646)) and the latest [IANA language subtag registry](http://www.iana.org/assignments/language-subtag-registry).
Based on [BCP 47](https://www.rfc-editor.org/info/bcp47) ([RFC 5646](https://www.rfc-editor.org/rfc/rfc5646.html)) and the latest [IANA language subtag registry](http://www.iana.org/assignments/language-subtag-registry).

@@ -9,0 +9,0 @@ This project will be updated as the standards change.

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc