🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@esgettext/runtime

Package Overview
Dependencies
Maintainers
0
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@esgettext/runtime - npm Package Compare versions

Comparing version
1.1.0
to
1.2.0
+1415
dist/esgettext.js
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.esgettext = {}));
})(this, (function (exports) { 'use strict';
let isBrowser = false;
/*
* Force an execution environment. By default, the environment (NodeJS or
* browser) is auto-detected. You can force the library to assume a certain
* environment with this function.
*
* @param browser - whether to assume a browser or not
* @returns the new setting.
*/
function browserEnvironment(browser) {
if (typeof browser !== 'undefined') {
isBrowser = browser;
}
return isBrowser;
}
let userLocalesSelected = ['C'];
/*
* Force an execution environment. By default, the environment (NodeJS or
* browser) is auto-detected. You can force the library to assume a certain
* environment with this function.
*
* @param browser - whether to assume a browser or not
* @returns the new setting.
*/
function userLocales(locales) {
if (typeof locales !== 'undefined') {
userLocalesSelected = locales;
}
return userLocalesSelected;
}
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol */
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
/* eslint-disable @typescript-eslint/explicit-function-return-type */
class TransportHttp {
loadFile(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.open('GET', url, true);
xhr.onload = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
resolve(xhr.response);
}
else {
reject(new Error('get failed with status ' + xhr.status));
}
};
xhr.onerror = err => reject(err);
xhr.send();
});
}
}
/*
* Function for germanic plural. Returns singular (0) for 1 item, and
* 1 for everything else.
*
* @param numItems - number of items
* @returns the index into the plural translations
*/
function germanicPlural(numItems) {
return numItems === 1 ? 0 : 1;
}
/*
* A minimalistic buffer implementation that can only read 32 bit unsigned
* integers and strings.
*/
class DataViewlet {
/*
* Create a DataViewlet instance. All encodings that are supported by
* the runtime environments `TextDecoder` interface.
*
* @param array - a `Unit8Array` view on the binary buffer
* @param encoding - encoding of strings, defaults to utf-8
*/
constructor(array, encoding = 'utf-8') {
this.array = array;
this.decoder = new TextDecoder(encoding);
this._encoding = encoding;
}
/**
* Get the encoding for strings.
*
* @returns the encoding in use
*/
get encoding() {
return this._encoding;
}
/**
* Switch to a new encoding.
*
* @param encoding - new encoding to use
*/
set encoding(encoding) {
this.decoder = new TextDecoder(encoding);
this._encoding = encoding;
}
/*
* Reads an unsigned 32-bit integer from the buffer at
* the specified offset as big-endian.
*
* @param offset - Number of bytes to skip before starting to read.
* Must satisfy `0 <= offset <= buf.length - 4`.
* Default: 0.
* @returns the 32-bit unsigned integer at position `offset`.s
*/
readUInt32BE(offset = 0) {
if (offset + 4 > this.array.byteLength + this.array.byteOffset) {
throw new Error('read past array end');
}
return ((((this.array[offset] << 24) >>> 0) |
(this.array[offset + 1] << 16) |
(this.array[offset + 2] << 8) |
this.array[offset + 3]) >>>
0);
}
/*
* Reads an unsigned 32-bit integer from the buffer at
* the specified offset as little-endian.
*
* @param offset - Number of bytes to skip before starting to read.
* Must satisfy `0 <= offset <= buf.length - 4`.
* Default: 0.
* @returns the 32-bit unsigned integer at position `offset`.s
*/
readUInt32LE(offset = 0) {
if (offset + 4 > this.array.byteLength + this.array.byteOffset) {
throw new Error('read past array end');
}
return ((((this.array[offset + 3] << 24) >>> 0) |
(this.array[offset + 2] << 16) |
(this.array[offset + 1] << 8) |
this.array[offset]) >>>
0);
}
/*
* Read a string at a specified offset.
*
* @param offset - to beginning of buffer in bytes
* @param length - of the string to read in bytes or to the end of the
* buffer if not specified.
*/
readString(offset = 0, length) {
if (offset + length >
this.array.byteLength + this.array.byteOffset) {
throw new Error('read past array end');
}
if (typeof length === 'undefined') {
length = this.array.byteLength - offset;
}
return this.decoder.decode(this.array.slice(offset, offset + length));
}
}
/*
* Parse an MO file.
*
* An exception is thrown for invalid data.
*
* @param raw - The input as either a binary `String`, any `Array`-like byte
* storage (`Array`, `Uint8Array`, `Arguments`, `jQuery(Array)`, ...)
* @returns a Catalog
*/
function parseMoCatalog(raw) {
const catalog = {
major: 0,
minor: 0,
entries: {},
pluralFunction: germanicPlural,
};
let offset = 0;
const blob = new DataViewlet(new Uint8Array(raw), 'ascii');
const magic = blob.readUInt32LE(offset);
let reader;
if (magic === 0x950412de) {
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
reader = (buf, off) => buf.readUInt32LE(off);
}
else if (magic === 0xde120495) {
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
reader = (buf, off) => buf.readUInt32BE(off);
}
else {
throw new Error(`invalid MO magic 0x${magic.toString(16)}`);
}
offset += 4;
// The revision is encoded in two shorts, major and minor. We don't care
// about the minor revision.
const major = reader(blob, offset) >> 16;
offset += 4;
if (major > 0) {
throw new Error(`unsupported major revision ${major}`);
}
const numStrings = reader(blob, offset);
offset += 4;
const msgidOffset = reader(blob, offset);
offset += 4;
const msgstrOffset = reader(blob, offset);
offset = msgidOffset;
const origTab = [];
for (let i = 0; i < numStrings; ++i) {
const l = reader(blob, offset);
offset += 4;
const stringOffset = reader(blob, offset);
offset += 4;
origTab.push([l, stringOffset]);
}
offset = msgstrOffset;
const transTab = [];
for (let i = 0; i < numStrings; ++i) {
const l = reader(blob, offset);
offset += 4;
const stringOffset = reader(blob, offset);
offset += 4;
transTab.push([l, stringOffset]);
}
const poHeader = {};
for (let i = 0; i < numStrings; ++i) {
const orig = origTab[i];
let l = orig[0];
offset = orig[1];
const msgid = blob.readString(offset, l).split('\u0000')[0];
const trans = transTab[i];
l = trans[0];
offset = trans[1];
const msgstr = blob.readString(offset, l).split('\u0000');
let pairs, kv;
if (i === 0 && msgid === '') {
pairs = msgstr[0].split('\n');
for (let j = 0; j < pairs.length; ++j) {
if (pairs[j] !== '') {
kv = pairs[j].split(/[ \t]*:[ \t]*/);
poHeader[kv[0].toLowerCase()] = kv[1];
}
}
if (poHeader['content-type'] !== undefined) {
const enc = poHeader['content-type'].replace(/.*=/, '');
if (enc !== poHeader['content-type']) {
blob.encoding = enc;
}
}
}
catalog.entries[msgid] = msgstr;
}
return catalog;
}
function validateMoJsonCatalog(udata) {
// We could use ajv but it results in almost 300 k minimized code
// for the browser bundle. This validator instead is absolutely
// minimalistic, and only avoids exceptions that can occur, when
// accessing entries.
if (udata === null || typeof udata === 'undefined') {
throw new Error('catalog is either null or undefined');
}
const data = udata;
if (data.constructor !== Object) {
throw new Error('catalog must be a dictionary');
}
// We don't care about major and minor because they are actually not
// used.
if (!Object.prototype.hasOwnProperty.call(data, 'entries')) {
throw new Error('catalog.entries does not exist');
}
const entries = data.entries;
if (entries === null || typeof entries === 'undefined') {
throw new Error('catalog.entries are not defined or null');
}
if (entries.constructor !== Object) {
throw new Error('catalog.entries must be a dictionary');
}
for (const [key, value] of Object.entries(entries)) {
if (!Array.isArray(value)) {
throw new Error(`catalog entry for key '${key}' is not an array`);
}
}
return data;
}
function parseMoJsonCatalog(json) {
const text = new TextDecoder().decode(json);
const data = JSON.parse(text);
return validateMoJsonCatalog(data);
}
function validateJsonCatalog(udata) {
// We could use ajv but it results in almost 300 k minimized code
// for the browser bundle. This validator instead is absolutely
// minimalistic, and only avoids exceptions that can occur, when
// accessing entries.
if (udata === null || typeof udata === 'undefined') {
throw new Error('catalog is either null or undefined');
}
const entries = udata;
if (entries.constructor !== Object) ;
// Convert to a regular catalog.
const catalog = {
major: 0,
minor: 1,
pluralFunction: () => 0,
entries: {},
};
for (const [msgid, msgstr] of Object.entries(entries)) {
// Just stringify all values but do not complain.
catalog.entries[msgid] = [msgstr.toString()];
}
return catalog;
}
function parseJsonCatalog(json) {
const text = new TextDecoder().decode(json);
const data = JSON.parse(text);
return validateJsonCatalog(data);
}
const tagHyphenRegex = new RegExp('^[a-z0-9]+(?:-[a-z0-9]+)*$', 'i');
const tagUnderscoreRegex = new RegExp('^[a-z0-9]+(?:_[a-z0-9]+)*$', 'i');
function splitLocale(locale) {
let charset = '', modifier = '';
const underscoreSeparator = locale.includes('_');
locale = locale.replace(/@([a-z]+)$/i, (_, match) => {
modifier = match;
return '';
});
locale = locale.replace(/\.([-0-9a-z]+)$/i, (_, match) => {
charset = match;
return '';
});
if (underscoreSeparator) {
if (!tagUnderscoreRegex.exec(locale)) {
return null;
}
}
else {
if (!tagHyphenRegex.exec(locale)) {
return null;
}
}
const separator = underscoreSeparator ? '_' : '-';
const tags = locale.split(separator);
const split = { tags: tags, underscoreSeparator };
if (charset.length) {
split.charset = charset;
}
if (modifier.length) {
split.modifier = modifier;
}
return split;
}
/*
* Caches catalog lookups by path, locale, and textdomain.
*
* Failed lookups are stored as null values.
*
* It is also possible to store a Promise. In that case, if a request is
* made to bind the textdomain, the promise is settled. Note that this
* mechanism is never used for message lookup but only for loading the
* catalog via resolve.
*/
class CatalogCache {
constructor() {
/* Singleton. */
}
static getInstance() {
if (!CatalogCache.instance) {
CatalogCache.instance = new CatalogCache();
}
return CatalogCache.instance;
}
static clear() {
CatalogCache.cache = {};
}
/**
* Lookup a Catalog for a given base path, locale, and textdomain.
*
* The locale key is usually the locale identifier (e.g. de-DE or sr\@latin).
* But it can also be a colon separated list of such locale identifiers.
*
*
* @param localeKey - the locale key
* @param textdomain - the textdomain
* @returns the cached Catalog, a Promise or null for failure
*/
static lookup(localeKey, textdomain) {
if (CatalogCache.cache[localeKey]) {
const ptr = CatalogCache.cache[localeKey];
if (Object.prototype.hasOwnProperty.call(ptr, textdomain)) {
return ptr[textdomain];
}
}
return null;
}
static store(localeKey, textdomain, entry) {
if (Promise.resolve(entry) !== entry) {
// Object.
entry = validateMoJsonCatalog(entry);
}
if (!CatalogCache.cache[localeKey]) {
CatalogCache.cache[localeKey] = {};
}
CatalogCache.cache[localeKey][textdomain] = entry;
}
}
CatalogCache.cache = {};
function explodeLocale(locale, vary) {
const retval = [];
const lsep = locale.underscoreSeparator ? '_' : '-';
let i = 0 ;
const hasCharset = typeof locale.charset !== 'undefined';
const hasModifier = typeof locale.modifier !== 'undefined';
const charsets = hasCharset ? [locale.charset] : [''];
if (hasCharset) {
const charset = locale.charset;
const ucCharset = charset.toUpperCase();
if (ucCharset !== charset) {
charsets.push(ucCharset);
}
charsets.push('');
}
for (; i < locale.tags.length; ++i) {
const lingua = locale.tags.slice(0, i + 1).join(lsep);
const ids = new Array();
charsets.forEach(charset => {
let id = charset.length ? lingua + '.' + charset : lingua;
if (hasModifier) {
id += '@' + locale.modifier;
}
ids.push(id);
});
retval.push(ids);
}
return retval;
}
function loadCatalog(url, format) {
return __awaiter(this, void 0, void 0, function* () {
let transportInstance;
{
transportInstance = new TransportHttp();
}
let validator;
if ('mo.json' === format) {
validator = parseMoJsonCatalog;
}
else if ('.json' === format) {
validator = parseJsonCatalog;
}
else {
validator = parseMoCatalog;
}
try {
const data = yield transportInstance.loadFile(url);
return validator(data);
}
catch (_a) {
return null;
}
});
}
function assemblePath(base, id, domainname, extender) {
return `${base}/${id}/LC_MESSAGES/${domainname}.${extender}`;
}
function loadLanguageFromObject(ids, base, domainname) {
return __awaiter(this, void 0, void 0, function* () {
for (let i = 0; i < ids.length; ++i) {
const id = ids[i];
// Language exists?
if (!Object.prototype.hasOwnProperty.call(base, id)) {
continue;
}
// LC_MESSAGES?
if (!Object.prototype.hasOwnProperty.call(base[id], 'LC_MESSAGES')) {
continue;
}
// Textdomain?
if (!Object.prototype.hasOwnProperty.call(base[id].LC_MESSAGES, domainname)) {
continue;
}
return base[id].LC_MESSAGES[domainname];
}
return null;
});
}
/*
* First tries to load a catalog with the specified charset, then with the
* charset converted to uppercase (if it differs from the original charset),
* and finally without a charset.
*/
function loadLanguage(ids, base, domainname, format) {
return __awaiter(this, void 0, void 0, function* () {
// Check if `base` is an object (LocaleContainer).
if (typeof base === 'object' && base !== null) {
return loadLanguageFromObject(ids, base, domainname);
}
for (const id of ids) {
const catalog = yield loadCatalog(assemblePath(base, id, domainname, format), format);
if (catalog) {
return catalog;
}
}
return null;
});
}
function loadDomain(exploded, localeKey, base, domainname, format) {
return __awaiter(this, void 0, void 0, function* () {
const entries = {};
const catalog = {
major: 0,
minor: 0,
pluralFunction: germanicPlural,
entries,
};
const cacheHit = yield CatalogCache.lookup(localeKey, domainname);
if (cacheHit !== null) {
return cacheHit;
}
for (const tries of exploded) {
const result = yield loadLanguage(tries, base, domainname, format);
if (result) {
catalog.major = result.major;
catalog.minor = result.minor;
catalog.entries = Object.assign(Object.assign({}, catalog.entries), result.entries);
}
}
return catalog;
});
}
function pluralExpression(str) {
const tokens = str
.replace(/[ \t\r\013\014]/g, '')
.replace(/;$/, '')
// Do NOT allow square brackets here. JSFuck!
.split(/[<>!=]=|&&|\|\||[-!*/%+<>=?:;]/);
for (let i = 0; i < tokens.length; ++i) {
const token = tokens[i].replace(/^\(+/, '').replace(/\)+$/, '');
if (token !== 'nplurals' &&
token !== 'plural' &&
token !== 'n' &&
// Does not catch invalid octal numbers but the compiler
// takes care of that.
null === /^[0-9]+$/.exec(token)) {
throw new Error('invalid plural function');
}
}
const code = 'var nplurals = 1, plural = 0;' + str + '; return 0 + plural';
// This may throw an exception!
// eslint-disable-next-line @typescript-eslint/no-implied-eval
return new Function('n', code);
}
function setPluralFunction(catalog) {
if (!Object.prototype.hasOwnProperty.call(catalog.entries, '')) {
return catalog;
}
const headers = catalog.entries[''][0].split('\n');
headers.forEach(header => {
const tokens = header.split(':');
if ('plural-forms' === tokens.shift().toLowerCase()) {
const code = tokens.join(':');
try {
catalog.pluralFunction = pluralExpression(code);
}
catch (_a) {
catalog.pluralFunction = germanicPlural;
}
}
});
return catalog;
}
function resolveImpl(domainname, path, format, localeKey) {
return __awaiter(this, void 0, void 0, function* () {
const defaultCatalog = {
major: 0,
minor: 0,
pluralFunction: germanicPlural,
entries: {},
};
if (localeKey === 'C' || localeKey === 'POSIX') {
return defaultCatalog;
}
const exploded = explodeLocale(splitLocale(localeKey));
const catalog = yield loadDomain(exploded, localeKey, path, domainname, format);
setPluralFunction(catalog);
CatalogCache.store(localeKey, domainname, catalog);
return catalog;
});
}
function gettextImpl(args) {
var _a;
const key = typeof args.msgctxt === 'undefined'
? args.msgid
: args.msgctxt + '\u0004' + args.msgid;
const translations = args.catalog.entries[key];
const numItems = (_a = args.numItems) !== null && _a !== void 0 ? _a : 1;
if (translations && translations.length) {
if (typeof args.msgidPlural === 'undefined') {
return translations[0];
}
else {
let pluralForm = args.catalog.pluralFunction(numItems);
if (pluralForm >= translations.length) {
if (translations.length === 1) {
return translations[0];
}
else {
pluralForm = germanicPlural(numItems);
}
}
return translations[pluralForm];
}
}
else if (typeof args.msgidPlural !== 'undefined') {
const pluralform = args.catalog.pluralFunction(numItems);
if (pluralform === 1) {
return args.msgidPlural;
}
}
return args.msgid;
}
const isNode = typeof process !== 'undefined' &&
process.versions !== null &&
process.versions.node !== null;
const pathSeparator = isNode && process.platform === 'win32' ? '\\' : '/';
function tagsEqual(left, right) {
if (left.length !== right.length) {
return false;
}
for (let i = 0; i < left.length; ++i) {
if (left[i].toLowerCase() !== right[i].toLowerCase()) {
return false;
}
}
return true;
}
function selectLocale(supported, requested) {
let languageMatch = '';
for (let i = 0; i < requested.length; ++i) {
const wanted = splitLocale(requested[i]);
if (!wanted) {
continue;
}
for (let j = 0; j < supported.length; ++j) {
const got = splitLocale(supported[j]);
if (!got) {
continue;
}
if (tagsEqual(wanted.tags, got.tags)) {
return supported[j];
}
if (!languageMatch.length &&
wanted.tags[0].toLowerCase() === got.tags[0].toLowerCase()) {
languageMatch = supported[j];
}
}
}
if (languageMatch.length) {
return languageMatch;
}
return 'C';
}
/**
* A Textdomain is a container for an esgettext configuration and all loaded
* LocaleContainer for the textual domain selected.
*
* The actual translation methods have quite funny names like `_()` or
* `_x()`. The purpose of this naming convention is to make the
* internationalization of your programs as little obtrusive as possible.
* Most of the times you just have to exchange
*
* ```
* doSomething('Hello, world!');
* ```
*
* with
*
* ```
* doSomething(gtx._('Hello, world!'));
* ```
*
* Besides, depending on the string extractor you are using, it may be useful
* that the method names do not collide with method names from other packages.
*/
class Textdomain {
/**
* Retrieve a translation for a string.
*
* @param msgid - the string to translate
*
* @returns the translated string
*/
_(msgid) {
return gettextImpl({ msgid: msgid, catalog: this.catalog });
}
/**
* Retrieve a translation for a string containing a possible plural.
* You will almost always want to call {@link _nx} instead so that
* you can interpolate the number of items into the strings.
*
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
*
* @returns the translated string
*/
_n(msgid, msgidPlural, numItems) {
return gettextImpl({
msgid: msgid,
msgidPlural: msgidPlural,
numItems: numItems,
catalog: this.catalog,
});
}
/**
* Translate a string with a context.
*
* @param msgctxt - the message context
* @param msgid - the string to translate
*
* @returns the translated string
*/
_p(msgctxt, msgid) {
return gettextImpl({
msgctxt: msgctxt,
msgid: msgid,
catalog: this.catalog,
});
}
/**
* The method `_np()` combines `_n()` with `_p()`.
* You will almost always want to call {@link _npx} instead so that
* you can interpolate the number of items into the strings.
*
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - a dictionary with placehoders
* @returns the translated string
*/
_np(msgctxt, msgid, msgidPlural, numItems) {
return gettextImpl({
msgctxt: msgctxt,
msgid: msgid,
msgidPlural: msgidPlural,
numItems: numItems,
catalog: this.catalog,
});
}
/**
* Translate a string with placeholders. The placeholders should be
* wrapped into curly braces and must match the regular expression
* "[_a-zA-Z][_a-zA-Z0-9]*".
*
* @param msgid - the msgid to translate
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string with placeholders expanded
*/
_x(msgid, placeholders) {
return Textdomain.expand(gettextImpl({ msgid: msgid, catalog: this.catalog }), placeholders || {});
}
/**
* Translate a string with a plural expression with placeholders.
*
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string
*/
_nx(msgid, msgidPlural, numItems, placeholders) {
return Textdomain.expand(gettextImpl({
msgid: msgid,
msgidPlural: msgidPlural,
numItems: numItems,
catalog: this.catalog,
}), placeholders || {});
}
/**
* The method `_px()` combines `_p()` with `_x()`.
*
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_px(msgctxt, msgid, placeholders) {
return Textdomain.expand(gettextImpl({ msgctxt: msgctxt, msgid: msgid, catalog: this.catalog }), placeholders || {});
}
/**
* The method `_npx()` brings it all together. It combines `_n()` and
* `_p()` and `_x()`.
*
* @param msgctxt - the message context
* @param msgid - the message id
* @param msgidPlural - the plural string
* @param numItems - the number of items
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_npx(msgctxt, msgid, msgidPlural, numItems, placeholders) {
return Textdomain.expand(gettextImpl({
msgctxt: msgctxt,
msgid: msgid,
msgidPlural: msgidPlural,
numItems: numItems,
catalog: this.catalog,
}), placeholders || {});
}
static getCatalog(locale, textdomain) {
const catalog = CatalogCache.lookup(locale, textdomain);
if (!catalog || Promise.resolve(catalog) === catalog) {
return {
major: 0,
minor: 0,
pluralFunction: germanicPlural,
entries: {},
};
}
return catalog;
}
/**
* Retrieve a translation for a string with a fixed locale.
*
* @param locale - the locale identifier
* @param msgid - the string to translate
*
* @returns the translated string
*/
_l(locale, msgid) {
const catalog = Textdomain.getCatalog(locale, this.textdomain());
return gettextImpl({ msgid: msgid, catalog: catalog });
}
/**
* Retrieve a translation for a string containing a possible plural with
* a fixed locale.
* You will almost always want to call {@link _nx} instead so that
* you can interpolate the number of items into the strings.
*
* @param locale - the locale identifier
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
*
* @returns the translated string
*/
_ln(locale, msgid, msgidPlural, numItems) {
const catalog = Textdomain.getCatalog(locale, this.textdomain());
return gettextImpl({
msgid: msgid,
msgidPlural: msgidPlural,
numItems: numItems,
catalog: catalog,
});
}
/**
* Translate a string with a context with a fixed locale.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the string to translate
*
* @returns the translated string
*/
_lp(locale, msgctxt, msgid) {
const catalog = Textdomain.getCatalog(locale, this.textdomain());
return gettextImpl({ msgctxt: msgctxt, msgid: msgid, catalog: catalog });
}
/**
* The method `_lnp()` combines `_ln()` with `_lp()`.
* You will almost always want to call {@link _npx} instead so that
* you can interpolate the number of items into the strings.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - a dictionary with placehoders
* @returns the translated string
*/
_lnp(locale, msgctxt, msgid, msgidPlural, numItems) {
const catalog = Textdomain.getCatalog(locale, this.textdomain());
return gettextImpl({
msgctxt: msgctxt,
msgid: msgid,
msgidPlural: msgidPlural,
numItems: numItems,
catalog: catalog,
});
}
/**
* Translate a string with placeholders for a fixed locale.
* The placeholders should be
* wrapped into curly braces and must match the regular expression
* "[_a-zA-Z][_a-zA-Z0-9]*".
*
* @param locale - the locale identifier
* @param msgid - the msgid to translate
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string with placeholders expanded
*/
_lx(locale, msgid, placeholders) {
const catalog = Textdomain.getCatalog(locale, this.textdomain());
return Textdomain.expand(gettextImpl({ msgid: msgid, catalog: catalog }), placeholders || {});
}
/**
* Translate a string with a plural expression with placeholders into a
* fixed locale.
*
* @param locale - the locale identifier
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string
*/
_lnx(locale, msgid, msgidPlural, numItems, placeholders) {
const catalog = Textdomain.getCatalog(locale, this.textdomain());
return Textdomain.expand(gettextImpl({
msgid: msgid,
msgidPlural: msgidPlural,
numItems: numItems,
catalog: catalog,
}), placeholders || {});
}
/**
* The method `_lpx()` combines `_lp()` with `_lx()`.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_lpx(locale, msgctxt, msgid, placeholders) {
const catalog = Textdomain.getCatalog(locale, this.textdomain());
return Textdomain.expand(gettextImpl({ msgctxt: msgctxt, msgid: msgid, catalog: catalog }), placeholders || {});
}
/**
* The method `_lnpx()` brings it all together. It combines `_ln()` and
* `_lp()` and `_lx()`.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the message id
* @param msgidPlural - the plural string
* @param numItems - the number of items
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_lnpx(locale, msgctxt, msgid, msgidPlural, numItems, placeholders) {
const catalog = Textdomain.getCatalog(locale, this.textdomain());
return Textdomain.expand(gettextImpl({
msgctxt: msgctxt,
msgid: msgid,
msgidPlural: msgidPlural,
numItems: numItems,
catalog: catalog,
}), placeholders || {});
}
static expand(msg, placeholders) {
return msg.replace(/\{([a-zA-Z][0-9a-zA-Z]*)\}/g, (_, match) => {
if (Object.prototype.hasOwnProperty.call(placeholders, match)) {
return placeholders[match];
}
else {
return `{${match}}`;
}
});
}
/**
* Instantiate a Textdomain object. Textdomain objects are singletons
* for each textdomain identifier.
*
* @param textdomain - the textdomain of your application or library.
*
* @returns a [[`Textdomain`]]
*/
static getInstance(textdomain) {
if (typeof textdomain === 'undefined' ||
textdomain === null ||
textdomain === '') {
throw new Error('Cannot instantiate TextDomain without a textdomain');
}
if (Object.prototype.hasOwnProperty.call(Textdomain.domains, textdomain)) {
return Textdomain.domains[textdomain];
}
else {
const domain = new Textdomain(textdomain);
Textdomain.domains[textdomain] = domain;
domain.catalog = {
major: 0,
minor: 0,
pluralFunction: germanicPlural,
entries: {},
};
return domain;
}
}
/**
* Delete all existing singletons. This method should usually be called
* only, when you want to free memory.
*/
static clearInstances() {
Textdomain.boundDomains = {};
}
/**
* This method is used for testing. Do not use it yourself!
*/
static forgetInstances() {
Textdomain.clearInstances();
Textdomain.domains = {};
}
/**
* Query the locale in use.
*/
static get locale() {
return Textdomain._locale;
}
/**
* Change the locale.
*
* For the web you can use all valid language identifier tags that
* [BCP47](https://tools.ietf.org/html/bcp47) allows
* (and actually a lot more). The tag is always used unmodified.
*
* For server environments, the locale identifier has to match the following
* scheme:
*
* `ll_CC.charset\@modifier`
*
* * `ll` is the two- or three-letter language code.
* * `CC` is the optional two-letter country code.
* * `charset` is an optional character set (letters, digits, and the hyphen).
* * `modifier` is an optional variant (letters and digits).
*
* The language code is always converted to lowercase, the country code is
* converted to uppercase, variant and charset are used as is.
*
* @param locale - the locale identifier
* @returns the locale in use
*/
static set locale(locale) {
const ucLocale = locale.toUpperCase();
if (ucLocale === 'POSIX' || ucLocale === 'C') {
this._locale = 'POSIX';
return;
}
const split = splitLocale(locale);
if (!split) {
throw new Error('invalid locale identifier');
}
// The check from splitLocale() is sufficient.
if (browserEnvironment()) {
this._locale = locale;
return;
}
// Node.
split.tags[0] = split.tags[0].toLowerCase();
if (split.tags.length > 1) {
split.tags[1] = split.tags[1].toUpperCase();
}
const separator = split.underscoreSeparator ? '_' : '-';
this._locale = split.tags.join(separator);
if (typeof split.charset !== 'undefined') {
this._locale += '.' + split.charset;
}
if (typeof split.modifier !== 'undefined') {
this._locale += '@' + split.modifier;
}
}
constructor(domain) {
this._catalogFormat = 'mo.json';
this.catalog = undefined;
this.domain = domain;
const msg = "The property 'locale' is not an instance property but static. Use 'Textdomain.locale' instead!";
Object.defineProperty(this, 'locale', {
get: () => {
throw new Error(msg);
},
set: () => {
throw new Error(msg);
},
enumerable: true,
configurable: true,
});
}
/**
* A textdomain is an identifier for your application or library. It is
* the basename of your translation files which are either
* TEXTDOMAIN.mo.json or TEXTDOMAIN.mo, depending on the format you have
* chosen.
*
* FIXME! This should be a getter!
*
* @returns the textdomain
*/
textdomain() {
return this.domain;
}
/**
* Bind a textdomain to a certain path or queries the path that a
* textdomain is bound to. The catalog file will be searched
* in `${path}/LC_MESSAGES/${domainname}.EXT` where `EXT` is the
* selected catalog format (one of `mo.json`, `mo`, or `json`).
*
* Alternatively, you can pass a [[`LocaleContainer`]] that holds the
* catalogs in memory.
*
* The returned string or `LocaleContainer` is valid until the next
* `bindtextdomain` call with an argument.
*
* @param path - the base path or [[`LocaleContainer`]] for this textdomain
*
* @returns the current base directory or [[`LocaleContainer`]] for this domain, after possibly changing it.
*/
bindtextdomain(path) {
if (typeof path !== 'undefined') {
Textdomain.boundDomains[this.domain] = path;
}
return Textdomain.boundDomains[this.domain];
}
/**
* Resolve a textdomain, i.e. load the LocaleContainer for this domain and all
* of its dependencies for the currently selected locale or the locale
* specified.
*
* The promise will always resolve. If no catalog was found, an empty
* catalog will be returned that is still usable.
*
* @param locale - an optional locale identifier, defaults to Textdomain.locale
*
* @returns a promise for a Catalog that will always resolve.
*/
resolve(locale) {
return __awaiter(this, void 0, void 0, function* () {
const promises = [this.resolve1(locale)];
for (const td in Textdomain.domains) {
if (Object.prototype.hasOwnProperty.call(Textdomain.domains, td) &&
Textdomain.domains[td] !== this) {
promises.push(Textdomain.domains[td].resolve1(locale));
}
}
return Promise.all(promises).then(values => {
return new Promise(resolve => resolve(values[0]));
});
});
}
resolve1(locale) {
return __awaiter(this, void 0, void 0, function* () {
let path = this.bindtextdomain();
if (typeof path === 'undefined' || path === null) {
const parts = browserEnvironment()
? ['', 'assets', 'locale']
: ['.', 'locale'];
path = parts.join(pathSeparator);
}
const resolvedLocale = locale ? locale : Textdomain.locale;
return resolveImpl(this.domain, path, this.catalogFormat, resolvedLocale).then(catalog => {
if (!locale) {
this.catalog = catalog;
}
return new Promise(resolve => resolve(catalog));
});
});
}
/**
* Get the catalog format in use.
*
* @returns one of 'mo.json' or 'mo' (default is 'mo.json')
*/
get catalogFormat() {
return this._catalogFormat;
}
/**
* Set the catalog format to use.
*
* @param format - one of 'mo.json' or 'mo'
*/
set catalogFormat(format) {
format = format.toLowerCase();
if (format === 'mo.json') {
this._catalogFormat = 'mo.json';
}
else if (format === 'mo') {
this._catalogFormat = 'mo';
}
else {
throw new Error(`unsupported format ${format}`);
}
}
/**
* Queries the user's preferred locales. On the server it queries the
* environment variables `LANGUAGE`, `LC_ALL`, `LANG`, and `LC_MESSAGES`
* (in that order). In the browser, it parses it checks the user preferences
* in the variables `navigator.languages`, `navigator.language`,
* `navigator.userLanguage`, `navigator.browserLanguage`, and
* `navigator.systemLanguage`.
*
* @returns the set of locales in order of preference
*
* Added in \@runtime 0.1.0.
*/
static userLocales() {
return userLocales();
}
/**
* Select one of the supported locales from a list of locales accepted by
* the user.
*
* @param supported - the list of locales supported by the application
* @param requested - the list of locales accepted by the user
*
* If called with just one argument, then the list of requested locales
* is determined by calling [[Textdomain.userLocales]].
*
* @returns the negotiated locale or 'C' if not possible.
*/
static selectLocale(supported, requested) {
return selectLocale(supported, requested !== null && requested !== void 0 ? requested : Textdomain.userLocales());
}
/**
* A no-op method for string marking.
*
* Sometimes you want to mark strings for translation but do not actually
* want to translate them, at least not at the time of their definition.
* This is often the case, when you have to preserve the original string.
*
* Take this example:
*
* ```
* orangeColors = [gtx.N_('coral'), gtx.N_('tomato'), gtx.N_('orangered'),
* gtx.N_('gold'), gtx.N_('orange'), gtx.N_('darkorange')]
* ```
*
* These are standard CSS colors, and you cannot translate them inside
* CSS styles. But for presentation you may want to translate them later:
*
* ```
* console.log(gtx._x("The css color '{color}' is {translated}.",
* {
* color: orangeColors[2],
* translated: gtx._(orangeColors[2]),
* }
* )
* );
* ```
*
* In other words: The method just marks strings for translation, so that
* the extractor `esgettext-xgettext` finds them but it does not actually
* translate anything.
*
* Similar methods are available for other cases (with placeholder
* expansion, context, or both). They are *not* available for plural
* methods because that would not make sense.
*
* Note that all of these methods are also available as instance methods.
*
* @param msgid - the message id
* @returns the original string
*/
static N_(msgid) {
return msgid;
}
/**
* Does the same as the static method `N_()`.
*
* @param msgid - the message id
* @returns the original string
*/
N_(msgid) {
return msgid;
}
/**
* Same as `N_()` but with placeholder expansion.
*
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
N_x(msgid, placeholders) {
return Textdomain.expand(msgid, placeholders !== null && placeholders !== void 0 ? placeholders : {});
}
/**
* Does the same as the static method `N_x()`.
*
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
static N_x(msgid, placeholders) {
return Textdomain.expand(msgid, placeholders !== null && placeholders !== void 0 ? placeholders : {});
}
/**
* Same as `N_()` but with context.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @returns the original string
*/
N_p(_msgctxt, msgid) {
return msgid;
}
/**
* Does the same as the static method `N_p()`.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @returns the original string with placeholders expanded
*/
static N_p(_msgctxt, msgid) {
return msgid;
}
/**
* Same as `N_()` but with context and placeholder expansion.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
N_px(_msgctxt, msgid, placeholders) {
return Textdomain.expand(msgid, placeholders !== null && placeholders !== void 0 ? placeholders : {});
}
/**
* Does the same as the static method `N_px()`.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
static N_px(_msgctxt, msgid, placeholders) {
return Textdomain.expand(msgid, placeholders !== null && placeholders !== void 0 ? placeholders : {});
}
}
Textdomain.domains = {};
Textdomain.boundDomains = {};
Textdomain._locale = 'C';
browserEnvironment(true);
const locales = new Array();
if (window.navigator.languages) {
locales.push(...window.navigator.languages);
}
if (typeof window.navigator.language !== 'undefined') {
locales.push(window.navigator.language);
}
const nav = window.navigator;
if (Object.prototype.hasOwnProperty.call(nav, 'userLanguage') &&
nav.userLanguage) {
locales.push(nav.userLanguage);
}
if (Object.prototype.hasOwnProperty.call(nav, 'browserLanguage') &&
nav['browserLanguage']) {
locales.push(nav.browserLanguage);
}
if (Object.prototype.hasOwnProperty.call(nav, 'systemLanguage') &&
nav['systemLanguage']) {
locales.push(nav.systemLanguage);
}
userLocales(locales);
exports.CatalogCache = CatalogCache;
exports.Textdomain = Textdomain;
exports.parseJsonCatalog = parseJsonCatalog;
exports.parseMoCatalog = parseMoCatalog;
exports.parseMoJsonCatalog = parseMoJsonCatalog;
}));
//# sourceMappingURL=esgettext.js.map

Sorry, the diff of this file is too big to display

+11
-0

@@ -8,2 +8,13 @@ import { Catalog } from './catalog';

static clear(): void;
/**
* Lookup a Catalog for a given base path, locale, and textdomain.
*
* The locale key is usually the locale identifier (e.g. de-DE or sr\@latin).
* But it can also be a colon separated list of such locale identifiers.
*
*
* @param localeKey - the locale key
* @param textdomain - the textdomain
* @returns the cached Catalog, a Promise or null for failure
*/
static lookup(localeKey: string, textdomain: string): Catalog | Promise<Catalog> | null;

@@ -10,0 +21,0 @@ static store(localeKey: string, textdomain: string, entry: Catalog | Promise<Catalog>): void;

+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"catalog-cache.d.ts","sourceRoot":"","sources":["../../src/core/catalog-cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoBpC,qBAAa,YAAY;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAe;IACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAA6B;IAEjD,OAAO;IAIP,MAAM,CAAC,WAAW,IAAI,YAAY;IAQlC,MAAM,CAAC,KAAK,IAAI,IAAI;WAeN,MAAM,CACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAChB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI;WAWtB,KAAK,CAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAC/B,IAAI;CAWP"}
{"version":3,"file":"catalog-cache.d.ts","sourceRoot":"","sources":["../../src/core/catalog-cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoBpC,qBAAa,YAAY;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAe;IACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAA6B;IAEjD,OAAO;IAIP,MAAM,CAAC,WAAW,IAAI,YAAY;IAQlC,MAAM,CAAC,KAAK,IAAI,IAAI;IAIpB;;;;;;;;;;OAUG;WACW,MAAM,CACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAChB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI;WAWtB,KAAK,CAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAC/B,IAAI;CAWP"}

@@ -1,10 +0,48 @@

export interface CatalogEntries {
/**
* The set of translations found in a [[`Catalog`]].
*
* This interface is used internally. You will only need it if you want to
* write your own message retrieval method or want to inspect a loaded
* [[`Catalog`]].
*
* The translations are looked up by their singular form in the original
* language. The value is an array of strings. The first item is the singular
* translation, the optional following items are the plural forms.
*
* If a translation has a message context, the key is the context joined
* with the translation by a `'\u0004'` character. For example, the key for
* the msgid "Open" with the msgctxt "Menu|File" would be `Menu|File\u0004Open`.
*/
export type CatalogEntries = {
[key: string]: Array<string>;
}
export interface Catalog {
};
/**
* A [[`Catalog`]] is a container for a set of translations loaded from a
* `mo.json` or a binary `.mo` file.
*
* This interface is used internally. You will only need it if you want to
* write your own message retrieval method or want to inspect a loaded
* [[`Catalog`]].
*/
export type Catalog = {
/** The major revision number of the catalog, currently always 0. */
major: number;
/** The minor revision number of the catalog, currently always 0 or 1. */
minor: number;
/**
* Compute the index of a plural form from a number of items. If a language
* has one singular and two plural forms, the singular form would have
* index 0 and the plural forms have index 1 and 2.
*
* The plural function would then compute one of 0, 1, or 2 from an
* arbitrary non-negative integer.
*
* @param numItems - the number of items.
*
* @returns the index of the plural form.
*/
pluralFunction(numItems: number): number;
/** The actual translations. */
entries: CatalogEntries;
}
};
//# sourceMappingURL=catalog.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/core/catalog.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,cAAc;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;CAC7B;AAUD,MAAM,WAAW,OAAO;IAEvB,KAAK,EAAE,MAAM,CAAC;IAGd,KAAK,EAAE,MAAM,CAAC;IAcd,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAGzC,OAAO,EAAE,cAAc,CAAC;CACxB"}
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/core/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,cAAc,GAAG;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;CAC7B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,OAAO,GAAG;IACrB,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IAEd,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IAEd;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAEzC,+BAA+B;IAC/B,OAAO,EAAE,cAAc,CAAC;CACxB,CAAC"}

@@ -6,3 +6,13 @@ export declare class DataViewlet {

constructor(array: Uint8Array, encoding?: string);
/**
* Get the encoding for strings.
*
* @returns the encoding in use
*/
get encoding(): string;
/**
* Switch to a new encoding.
*
* @param encoding - new encoding to use
*/
set encoding(encoding: string);

@@ -9,0 +19,0 @@ readUInt32BE(offset?: number): number;

@@ -1,1 +0,1 @@

{"version":3,"file":"data-viewlet.d.ts","sourceRoot":"","sources":["../../src/core/data-viewlet.ts"],"names":[],"mappings":"AAIA,qBAAa,WAAW;IAYtB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAXvB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,SAAS,CAAS;gBAUR,KAAK,EAAE,UAAU,EAClC,QAAQ,SAAU;IAWnB,IAAI,QAAQ,IAAI,MAAM,CAErB;IAOD,IAAI,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAG5B;IAUD,YAAY,CAAC,MAAM,SAAI,GAAG,MAAM;IAuBhC,YAAY,CAAC,MAAM,SAAI,GAAG,MAAM;IAqBhC,UAAU,CAAC,MAAM,SAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM;CAc/C"}
{"version":3,"file":"data-viewlet.d.ts","sourceRoot":"","sources":["../../src/core/data-viewlet.ts"],"names":[],"mappings":"AAIA,qBAAa,WAAW;IAYtB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAXvB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,SAAS,CAAS;gBAUR,KAAK,EAAE,UAAU,EAClC,QAAQ,SAAU;IAMnB;;;;OAIG;IACH,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED;;;;OAIG;IACH,IAAI,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAG5B;IAUD,YAAY,CAAC,MAAM,SAAI,GAAG,MAAM;IAuBhC,YAAY,CAAC,MAAM,SAAI,GAAG,MAAM;IAqBhC,UAAU,CAAC,MAAM,SAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM;CAc/C"}

@@ -1,9 +0,32 @@

import { Catalog } from './catalog';
export interface LocaleContainer {
import type { Catalog } from './catalog';
/**
* An object storing locale information. It resembles the directory structure
* that [[`Catalog`]] objects are found in.
*
* Example, if your textdomain is 'myapp':
*
* <pre class="language-javascript"><code class="language-javascript">\{
* fr: \{
* LC_MESSAGES: \{
* myapp: catalogs['fr']
* \}
* \},
* 'de-DE': \{
* LC_MESSAGES: \{
* myapp: catalogs['de-DE']
* \}
* \}
* \}
* </code></pre>
*/
export type LocaleContainer = {
/** A language code like 'fr' or 'de-DE'. */
[key: string]: {
/** The Locale category, always 'LC_MESSAGES'. */
[key: string]: {
/** The textdomain. */
[key: string]: Catalog;
};
};
}
};
//# sourceMappingURL=locale-container.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"locale-container.d.ts","sourceRoot":"","sources":["../../src/core/locale-container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsBpC,MAAM,WAAW,eAAe;IAE/B,CAAC,GAAG,EAAE,MAAM,GAAG;QAEd,CAAC,GAAG,EAAE,MAAM,GAAG;YAEd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;SACvB,CAAC;KACF,CAAC;CACF"}
{"version":3,"file":"locale-container.d.ts","sourceRoot":"","sources":["../../src/core/locale-container.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,eAAe,GAAG;IAC7B,4CAA4C;IAC5C,CAAC,GAAG,EAAE,MAAM,GAAG;QACd,iDAAiD;QACjD,CAAC,GAAG,EAAE,MAAM,GAAG;YACd,sBAAsB;YACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;SACvB,CAAC;KACF,CAAC;CACF,CAAC"}

@@ -1,1 +0,1 @@

{"version":3,"file":"resolve-impl.d.ts","sourceRoot":"","sources":["../../src/core/resolve-impl.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,OAAO,EAAkB,MAAM,WAAW,CAAC;AAKpD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAiPrD,wBAAgB,WAAW,CAC1B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GAAG,eAAe,EAC9B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAyBlB"}
{"version":3,"file":"resolve-impl.d.ts","sourceRoot":"","sources":["../../src/core/resolve-impl.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,OAAO,EAAkB,MAAM,WAAW,CAAC;AAKpD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AA4MrD,wBAAsB,WAAW,CAChC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GAAG,eAAe,EAC9B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAiBlB"}

@@ -1,9 +0,52 @@

import { Catalog } from './catalog';
import { LocaleContainer } from './locale-container';
import type { Catalog } from './catalog';
import type { LocaleContainer } from './locale-container';
/**
* Represents a mapping of placeholder strings to the values that they should be replaced with.
* Placeholders must match the regular expression `/^[_a-zA-Z][_a-zA-Z0-9]*$/`.
* @remarks
* Placeholders provide a way to dynamically replace certain strings in a translatable message.
*
* @example
* ```typescript
* const placeholders: Placeholders = {
* 'name': 'John Doe',
* 'age': 30,
* // Add more placeholders as needed
* };
* ```
*
* A typical call would look like this:
*
* ```typescript
* console.log(gtx._x('User {name} is {age} years old.'));
* ```
* @public
*/
export interface Placeholders {
[placeholder: string]: any;
}
/**
* A Textdomain is a container for an esgettext configuration and all loaded
* LocaleContainer for the textual domain selected.
*
* The actual translation methods have quite funny names like `_()` or
* `_x()`. The purpose of this naming convention is to make the
* internationalization of your programs as little obtrusive as possible.
* Most of the times you just have to exchange
*
* ```
* doSomething('Hello, world!');
* ```
*
* with
*
* ```
* doSomething(gtx._('Hello, world!'));
* ```
*
* Besides, depending on the string extractor you are using, it may be useful
* that the method names do not collide with method names from other packages.
*/
export declare class Textdomain {
private static domains;
private static readonly cache;
private static boundDomains;

@@ -14,44 +57,409 @@ private static _locale;

private catalog;
getInstance: (textdomain: string) => Textdomain;
/**
* Retrieve a translation for a string.
*
* @param msgid - the string to translate
*
* @returns the translated string
*/
_(msgid: string): string;
/**
* Retrieve a translation for a string containing a possible plural.
* You will almost always want to call {@link _nx} instead so that
* you can interpolate the number of items into the strings.
*
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
*
* @returns the translated string
*/
_n(msgid: string, msgidPlural: string, numItems: number): string;
/**
* Translate a string with a context.
*
* @param msgctxt - the message context
* @param msgid - the string to translate
*
* @returns the translated string
*/
_p(msgctxt: string, msgid: string): string;
/**
* The method `_np()` combines `_n()` with `_p()`.
* You will almost always want to call {@link _npx} instead so that
* you can interpolate the number of items into the strings.
*
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - a dictionary with placehoders
* @returns the translated string
*/
_np(msgctxt: string, msgid: string, msgidPlural: string, numItems: number): string;
/**
* Translate a string with placeholders. The placeholders should be
* wrapped into curly braces and must match the regular expression
* "[_a-zA-Z][_a-zA-Z0-9]*".
*
* @param msgid - the msgid to translate
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string with placeholders expanded
*/
_x(msgid: string, placeholders?: Placeholders): string;
/**
* Translate a string with a plural expression with placeholders.
*
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string
*/
_nx(msgid: string, msgidPlural: string, numItems: number, placeholders?: Placeholders): string;
/**
* The method `_px()` combines `_p()` with `_x()`.
*
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_px(msgctxt: string, msgid: string, placeholders?: Placeholders): string;
/**
* The method `_npx()` brings it all together. It combines `_n()` and
* `_p()` and `_x()`.
*
* @param msgctxt - the message context
* @param msgid - the message id
* @param msgidPlural - the plural string
* @param numItems - the number of items
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_npx(msgctxt: string, msgid: string, msgidPlural: string, numItems: number, placeholders?: Placeholders): string;
private static getCatalog;
/**
* Retrieve a translation for a string with a fixed locale.
*
* @param locale - the locale identifier
* @param msgid - the string to translate
*
* @returns the translated string
*/
_l(locale: string, msgid: string): string;
/**
* Retrieve a translation for a string containing a possible plural with
* a fixed locale.
* You will almost always want to call {@link _nx} instead so that
* you can interpolate the number of items into the strings.
*
* @param locale - the locale identifier
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
*
* @returns the translated string
*/
_ln(locale: string, msgid: string, msgidPlural: string, numItems: number): string;
/**
* Translate a string with a context with a fixed locale.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the string to translate
*
* @returns the translated string
*/
_lp(locale: string, msgctxt: string, msgid: string): string;
/**
* The method `_lnp()` combines `_ln()` with `_lp()`.
* You will almost always want to call {@link _npx} instead so that
* you can interpolate the number of items into the strings.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - a dictionary with placehoders
* @returns the translated string
*/
_lnp(locale: string, msgctxt: string, msgid: string, msgidPlural: string, numItems: number): string;
/**
* Translate a string with placeholders for a fixed locale.
* The placeholders should be
* wrapped into curly braces and must match the regular expression
* "[_a-zA-Z][_a-zA-Z0-9]*".
*
* @param locale - the locale identifier
* @param msgid - the msgid to translate
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string with placeholders expanded
*/
_lx(locale: string, msgid: string, placeholders?: Placeholders): string;
/**
* Translate a string with a plural expression with placeholders into a
* fixed locale.
*
* @param locale - the locale identifier
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string
*/
_lnx(locale: string, msgid: string, msgidPlural: string, numItems: number, placeholders?: Placeholders): string;
/**
* The method `_lpx()` combines `_lp()` with `_lx()`.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_lpx(locale: string, msgctxt: string, msgid: string, placeholders?: Placeholders): string;
/**
* The method `_lnpx()` brings it all together. It combines `_ln()` and
* `_lp()` and `_lx()`.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the message id
* @param msgidPlural - the plural string
* @param numItems - the number of items
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_lnpx(locale: string, msgctxt: string, msgid: string, msgidPlural: string, numItems: number, placeholders?: Placeholders): string;
private static expand;
/**
* Instantiate a Textdomain object. Textdomain objects are singletons
* for each textdomain identifier.
*
* @param textdomain - the textdomain of your application or library.
*
* @returns a [[`Textdomain`]]
*/
static getInstance(textdomain: string): Textdomain;
/**
* Delete all existing singletons. This method should usually be called
* only, when you want to free memory.
*/
static clearInstances(): void;
/**
* This method is used for testing. Do not use it yourself!
*/
static forgetInstances(): void;
/**
* Query the locale in use.
*/
static get locale(): string;
/**
* Change the locale.
*
* For the web you can use all valid language identifier tags that
* [BCP47](https://tools.ietf.org/html/bcp47) allows
* (and actually a lot more). The tag is always used unmodified.
*
* For server environments, the locale identifier has to match the following
* scheme:
*
* `ll_CC.charset\@modifier`
*
* * `ll` is the two- or three-letter language code.
* * `CC` is the optional two-letter country code.
* * `charset` is an optional character set (letters, digits, and the hyphen).
* * `modifier` is an optional variant (letters and digits).
*
* The language code is always converted to lowercase, the country code is
* converted to uppercase, variant and charset are used as is.
*
* @param locale - the locale identifier
* @returns the locale in use
*/
static set locale(locale: string);
private constructor();
/**
* A textdomain is an identifier for your application or library. It is
* the basename of your translation files which are either
* TEXTDOMAIN.mo.json or TEXTDOMAIN.mo, depending on the format you have
* chosen.
*
* FIXME! This should be a getter!
*
* @returns the textdomain
*/
textdomain(): string;
/**
* Bind a textdomain to a certain path or queries the path that a
* textdomain is bound to. The catalog file will be searched
* in `${path}/LC_MESSAGES/${domainname}.EXT` where `EXT` is the
* selected catalog format (one of `mo.json`, `mo`, or `json`).
*
* Alternatively, you can pass a [[`LocaleContainer`]] that holds the
* catalogs in memory.
*
* The returned string or `LocaleContainer` is valid until the next
* `bindtextdomain` call with an argument.
*
* @param path - the base path or [[`LocaleContainer`]] for this textdomain
*
* @returns the current base directory or [[`LocaleContainer`]] for this domain, after possibly changing it.
*/
bindtextdomain(path?: string | LocaleContainer): string | LocaleContainer;
/**
* Resolve a textdomain, i.e. load the LocaleContainer for this domain and all
* of its dependencies for the currently selected locale or the locale
* specified.
*
* The promise will always resolve. If no catalog was found, an empty
* catalog will be returned that is still usable.
*
* @param locale - an optional locale identifier, defaults to Textdomain.locale
*
* @returns a promise for a Catalog that will always resolve.
*/
resolve(locale?: string): Promise<Catalog>;
private resolve1;
/**
* Get the catalog format in use.
*
* @returns one of 'mo.json' or 'mo' (default is 'mo.json')
*/
get catalogFormat(): string;
/**
* Set the catalog format to use.
*
* @param format - one of 'mo.json' or 'mo'
*/
set catalogFormat(format: string);
/**
* Queries the user's preferred locales. On the server it queries the
* environment variables `LANGUAGE`, `LC_ALL`, `LANG`, and `LC_MESSAGES`
* (in that order). In the browser, it parses it checks the user preferences
* in the variables `navigator.languages`, `navigator.language`,
* `navigator.userLanguage`, `navigator.browserLanguage`, and
* `navigator.systemLanguage`.
*
* @returns the set of locales in order of preference
*
* Added in \@runtime 0.1.0.
*/
static userLocales(): Array<string>;
/**
* Select one of the supported locales from a list of locales accepted by
* the user.
*
* @param supported - the list of locales supported by the application
* @param requested - the list of locales accepted by the user
*
* If called with just one argument, then the list of requested locales
* is determined by calling [[Textdomain.userLocales]].
*
* @returns the negotiated locale or 'C' if not possible.
*/
static selectLocale(supported: Array<string>, requested?: Array<string>): string;
/**
* A no-op method for string marking.
*
* Sometimes you want to mark strings for translation but do not actually
* want to translate them, at least not at the time of their definition.
* This is often the case, when you have to preserve the original string.
*
* Take this example:
*
* ```
* orangeColors = [gtx.N_('coral'), gtx.N_('tomato'), gtx.N_('orangered'),
* gtx.N_('gold'), gtx.N_('orange'), gtx.N_('darkorange')]
* ```
*
* These are standard CSS colors, and you cannot translate them inside
* CSS styles. But for presentation you may want to translate them later:
*
* ```
* console.log(gtx._x("The css color '{color}' is {translated}.",
* {
* color: orangeColors[2],
* translated: gtx._(orangeColors[2]),
* }
* )
* );
* ```
*
* In other words: The method just marks strings for translation, so that
* the extractor `esgettext-xgettext` finds them but it does not actually
* translate anything.
*
* Similar methods are available for other cases (with placeholder
* expansion, context, or both). They are *not* available for plural
* methods because that would not make sense.
*
* Note that all of these methods are also available as instance methods.
*
* @param msgid - the message id
* @returns the original string
*/
static N_(msgid: string): string;
/**
* Does the same as the static method `N_()`.
*
* @param msgid - the message id
* @returns the original string
*/
N_(msgid: string): string;
/**
* Same as `N_()` but with placeholder expansion.
*
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
N_x(msgid: string, placeholders?: Placeholders): string;
/**
* Does the same as the static method `N_x()`.
*
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
static N_x(msgid: string, placeholders?: Placeholders): string;
/**
* Same as `N_()` but with context.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @returns the original string
*/
N_p(_msgctxt: string, msgid: string): string;
/**
* Does the same as the static method `N_p()`.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @returns the original string with placeholders expanded
*/
static N_p(_msgctxt: string, msgid: string): string;
/**
* Same as `N_()` but with context and placeholder expansion.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
N_px(_msgctxt: string, msgid: string, placeholders?: Placeholders): string;
/**
* Does the same as the static method `N_px()`.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
static N_px(_msgctxt: string, msgid: string, placeholders?: Placeholders): string;
}
//# sourceMappingURL=textdomain.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"textdomain.d.ts","sourceRoot":"","sources":["../../src/core/textdomain.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"textdomain.d.ts","sourceRoot":"","sources":["../../src/core/textdomain.ts"],"names":[],"mappings":"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"}

@@ -6,2 +6,10 @@ 'use strict';

let userLocalesSelected = ['C'];
/*
* Force an execution environment. By default, the environment (NodeJS or
* browser) is auto-detected. You can force the library to assume a certain
* environment with this function.
*
* @param browser - whether to assume a browser or not
* @returns the new setting.
*/
function userLocales(locales) {

@@ -14,2 +22,35 @@ if (typeof locales !== 'undefined') {

/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol */
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
/* eslint-disable @typescript-eslint/explicit-function-return-type */
class TransportHttp {

@@ -45,2 +86,9 @@ loadFile(url) {

/*
* Function for germanic plural. Returns singular (0) for 1 item, and
* 1 for everything else.
*
* @param numItems - number of items
* @returns the index into the plural translations
*/
function germanicPlural(numItems) {

@@ -50,3 +98,14 @@ return numItems === 1 ? 0 : 1;

/*
* A minimalistic buffer implementation that can only read 32 bit unsigned
* integers and strings.
*/
class DataViewlet {
/*
* Create a DataViewlet instance. All encodings that are supported by
* the runtime environments `TextDecoder` interface.
*
* @param array - a `Unit8Array` view on the binary buffer
* @param encoding - encoding of strings, defaults to utf-8
*/
constructor(array, encoding = 'utf-8') {

@@ -57,5 +116,15 @@ this.array = array;

}
/**
* Get the encoding for strings.
*
* @returns the encoding in use
*/
get encoding() {
return this._encoding;
}
/**
* Switch to a new encoding.
*
* @param encoding - new encoding to use
*/
set encoding(encoding) {

@@ -65,2 +134,11 @@ this.decoder = new TextDecoder(encoding);

}
/*
* Reads an unsigned 32-bit integer from the buffer at
* the specified offset as big-endian.
*
* @param offset - Number of bytes to skip before starting to read.
* Must satisfy `0 <= offset <= buf.length - 4`.
* Default: 0.
* @returns the 32-bit unsigned integer at position `offset`.s
*/
readUInt32BE(offset = 0) {

@@ -76,2 +154,11 @@ if (offset + 4 > this.array.byteLength + this.array.byteOffset) {

}
/*
* Reads an unsigned 32-bit integer from the buffer at
* the specified offset as little-endian.
*
* @param offset - Number of bytes to skip before starting to read.
* Must satisfy `0 <= offset <= buf.length - 4`.
* Default: 0.
* @returns the 32-bit unsigned integer at position `offset`.s
*/
readUInt32LE(offset = 0) {

@@ -87,2 +174,9 @@ if (offset + 4 > this.array.byteLength + this.array.byteOffset) {

}
/*
* Read a string at a specified offset.
*
* @param offset - to beginning of buffer in bytes
* @param length - of the string to read in bytes or to the end of the
* buffer if not specified.
*/
readString(offset = 0, length) {

@@ -100,2 +194,11 @@ if (offset + length >

/*
* Parse an MO file.
*
* An exception is thrown for invalid data.
*
* @param raw - The input as either a binary `String`, any `Array`-like byte
* storage (`Array`, `Uint8Array`, `Arguments`, `jQuery(Array)`, ...)
* @returns a Catalog
*/
function parseMoCatalog(raw) {

@@ -113,5 +216,7 @@ const catalog = {

if (magic === 0x950412de) {
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
reader = (buf, off) => buf.readUInt32LE(off);
}
else if (magic === 0xde120495) {
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
reader = (buf, off) => buf.readUInt32BE(off);

@@ -123,2 +228,4 @@ }

offset += 4;
// The revision is encoded in two shorts, major and minor. We don't care
// about the minor revision.
const major = reader(blob, offset) >> 16;

@@ -184,2 +291,6 @@ offset += 4;

function validateMoJsonCatalog(udata) {
// We could use ajv but it results in almost 300 k minimized code
// for the browser bundle. This validator instead is absolutely
// minimalistic, and only avoids exceptions that can occur, when
// accessing entries.
if (udata === null || typeof udata === 'undefined') {

@@ -192,2 +303,4 @@ throw new Error('catalog is either null or undefined');

}
// We don't care about major and minor because they are actually not
// used.
if (!Object.prototype.hasOwnProperty.call(data, 'entries')) {

@@ -217,2 +330,6 @@ throw new Error('catalog.entries does not exist');

function validateJsonCatalog(udata) {
// We could use ajv but it results in almost 300 k minimized code
// for the browser bundle. This validator instead is absolutely
// minimalistic, and only avoids exceptions that can occur, when
// accessing entries.
if (udata === null || typeof udata === 'undefined') {

@@ -223,2 +340,3 @@ throw new Error('catalog is either null or undefined');

if (entries.constructor !== Object) ;
// Convert to a regular catalog.
const catalog = {

@@ -231,2 +349,3 @@ major: 0,

for (const [msgid, msgstr] of Object.entries(entries)) {
// Just stringify all values but do not complain.
catalog.entries[msgid] = [msgstr.toString()];

@@ -277,4 +396,15 @@ }

/*
* Caches catalog lookups by path, locale, and textdomain.
*
* Failed lookups are stored as null values.
*
* It is also possible to store a Promise. In that case, if a request is
* made to bind the textdomain, the promise is settled. Note that this
* mechanism is never used for message lookup but only for loading the
* catalog via resolve.
*/
class CatalogCache {
constructor() {
/* Singleton. */
}

@@ -290,2 +420,13 @@ static getInstance() {

}
/**
* Lookup a Catalog for a given base path, locale, and textdomain.
*
* The locale key is usually the locale identifier (e.g. de-DE or sr\@latin).
* But it can also be a colon separated list of such locale identifiers.
*
*
* @param localeKey - the locale key
* @param textdomain - the textdomain
* @returns the cached Catalog, a Promise or null for failure
*/
static lookup(localeKey, textdomain) {

@@ -302,2 +443,3 @@ if (CatalogCache.cache[localeKey]) {

if (Promise.resolve(entry) !== entry) {
// Object.
entry = validateMoJsonCatalog(entry);

@@ -344,45 +486,47 @@ }

function loadCatalog(url, format) {
let transportInstance;
{
let transport;
try {
const parsedURL = new URL(url);
if (parsedURL.protocol === 'https:' ||
parsedURL.protocol === 'http:' ||
parsedURL.protocol === 'file:') {
transport = 'http';
return __awaiter(this, void 0, void 0, function* () {
let transportInstance;
{
let transport;
// Check whether this is a valid URL.
try {
const parsedURL = new URL(url);
if (parsedURL.protocol === 'https:' ||
parsedURL.protocol === 'http:' ||
parsedURL.protocol === 'file:') {
transport = 'http';
}
else {
throw new Error(`unsupported scheme ${parsedURL.protocol}`);
}
}
catch (e) {
{
transport = 'fs';
}
}
if (transport === 'http') {
transportInstance = new TransportHttp();
}
else {
throw new Error(`unsupported scheme ${parsedURL.protocol}`);
transportInstance = new TransportFs();
}
}
catch (e) {
{
transport = 'fs';
}
let validator;
if ('mo.json' === format) {
validator = parseMoJsonCatalog;
}
if (transport === 'http') {
transportInstance = new TransportHttp();
else if ('.json' === format) {
validator = parseJsonCatalog;
}
else {
transportInstance = new TransportFs();
validator = parseMoCatalog;
}
}
let validator;
if ('mo.json' === format) {
validator = parseMoJsonCatalog;
}
else if ('.json' === format) {
validator = parseJsonCatalog;
}
else {
validator = parseMoCatalog;
}
return new Promise((resolve, reject) => {
transportInstance
.loadFile(url)
.then(data => {
resolve(validator(data));
})
.catch(e => reject(e));
try {
const data = yield transportInstance.loadFile(url);
return validator(data);
}
catch (_a) {
return null;
}
});

@@ -394,75 +538,65 @@ }

function loadLanguageFromObject(ids, base, domainname) {
let catalog;
for (let i = 0; i < ids.length; ++i) {
const id = ids[0];
if (!Object.prototype.hasOwnProperty.call(base, id)) {
continue;
return __awaiter(this, void 0, void 0, function* () {
for (let i = 0; i < ids.length; ++i) {
const id = ids[i];
// Language exists?
if (!Object.prototype.hasOwnProperty.call(base, id)) {
continue;
}
// LC_MESSAGES?
if (!Object.prototype.hasOwnProperty.call(base[id], 'LC_MESSAGES')) {
continue;
}
// Textdomain?
if (!Object.prototype.hasOwnProperty.call(base[id].LC_MESSAGES, domainname)) {
continue;
}
return base[id].LC_MESSAGES[domainname];
}
if (!Object.prototype.hasOwnProperty.call(base[id], 'LC_MESSAGES')) {
continue;
return null;
});
}
/*
* First tries to load a catalog with the specified charset, then with the
* charset converted to uppercase (if it differs from the original charset),
* and finally without a charset.
*/
function loadLanguage(ids, base, domainname, format) {
return __awaiter(this, void 0, void 0, function* () {
// Check if `base` is an object (LocaleContainer).
if (typeof base === 'object' && base !== null) {
return loadLanguageFromObject(ids, base, domainname);
}
if (!Object.prototype.hasOwnProperty.call(base[id].LC_MESSAGES, domainname)) {
continue;
for (const id of ids) {
const catalog = yield loadCatalog(assemblePath(base, id, domainname, format), format);
if (catalog) {
return catalog;
}
}
catalog = base[id].LC_MESSAGES[domainname];
}
return new Promise((resolve, reject) => {
if (catalog) {
resolve(catalog);
}
else {
reject();
}
return null;
});
}
async function loadLanguage(ids, base, domainname, format) {
if (typeof base === 'object' && base !== null) {
return loadLanguageFromObject(ids, base, domainname);
}
return new Promise((resolve, reject) => {
const tries = new Array();
ids.forEach(id => {
tries.push(() => loadCatalog(assemblePath(base, id, domainname, format), format));
});
tries
.reduce((promise, fn) => promise.catch(fn), Promise.reject())
.then(value => resolve(value))
.catch(e => reject(e));
});
}
async function loadDomain(exploded, localeKey, base, domainname, format) {
const entries = {};
const catalog = {
major: 0,
minor: 0,
pluralFunction: germanicPlural,
entries,
};
const cacheHit = CatalogCache.lookup(localeKey, domainname);
if (cacheHit !== null) {
if (Promise.resolve(cacheHit) === cacheHit) {
function loadDomain(exploded, localeKey, base, domainname, format) {
return __awaiter(this, void 0, void 0, function* () {
const entries = {};
const catalog = {
major: 0,
minor: 0,
pluralFunction: germanicPlural,
entries,
};
const cacheHit = yield CatalogCache.lookup(localeKey, domainname);
if (cacheHit !== null) {
return cacheHit;
}
else {
return new Promise(resolve => resolve(cacheHit));
for (const tries of exploded) {
const result = yield loadLanguage(tries, base, domainname, format);
if (result) {
catalog.major = result.major;
catalog.minor = result.minor;
catalog.entries = Object.assign(Object.assign({}, catalog.entries), result.entries);
}
}
}
const promises = new Array();
const results = new Array();
exploded.forEach((tries, i) => {
const p = loadLanguage(tries, base, domainname, format)
.then(catalog => (results[i] = catalog))
.catch(() => {
});
promises.push(p);
return catalog;
});
await Promise.all(promises);
results.forEach(result => {
catalog.major = result.major;
catalog.minor = result.minor;
catalog.entries = Object.assign(Object.assign({}, catalog.entries), result.entries);
});
return new Promise(resolve => {
resolve(catalog);
});
}

@@ -473,2 +607,3 @@ function pluralExpression(str) {

.replace(/;$/, '')
// Do NOT allow square brackets here. JSFuck!
.split(/[<>!=]=|&&|\|\||[-!*/%+<>=?:;]/);

@@ -480,2 +615,4 @@ for (let i = 0; i < tokens.length; ++i) {

token !== 'n' &&
// Does not catch invalid octal numbers but the compiler
// takes care of that.
null === /^[0-9]+$/.exec(token)) {

@@ -486,2 +623,4 @@ throw new Error('invalid plural function');

const code = 'var nplurals = 1, plural = 0;' + str + '; return 0 + plural';
// This may throw an exception!
// eslint-disable-next-line @typescript-eslint/no-implied-eval
return new Function('n', code);

@@ -498,3 +637,8 @@ }

const code = tokens.join(':');
catalog.pluralFunction = pluralExpression(code);
try {
catalog.pluralFunction = pluralExpression(code);
}
catch (_a) {
catalog.pluralFunction = germanicPlural;
}
}

@@ -505,23 +649,17 @@ });

function resolveImpl(domainname, path, format, localeKey) {
const defaultCatalog = {
major: 0,
minor: 0,
pluralFunction: germanicPlural,
entries: {},
};
if (localeKey === 'C' || localeKey === 'POSIX') {
return new Promise(resolve => resolve(defaultCatalog));
}
return new Promise(resolve => {
return __awaiter(this, void 0, void 0, function* () {
const defaultCatalog = {
major: 0,
minor: 0,
pluralFunction: germanicPlural,
entries: {},
};
if (localeKey === 'C' || localeKey === 'POSIX') {
return defaultCatalog;
}
const exploded = explodeLocale(splitLocale(localeKey));
loadDomain(exploded, localeKey, path, domainname, format)
.then(catalog => {
setPluralFunction(catalog);
CatalogCache.store(localeKey, domainname, catalog);
resolve(catalog);
})
.catch(() => {
CatalogCache.store(localeKey, domainname, defaultCatalog);
resolve(defaultCatalog);
});
const catalog = yield loadDomain(exploded, localeKey, path, domainname, format);
setPluralFunction(catalog);
CatalogCache.store(localeKey, domainname, catalog);
return catalog;
});

@@ -606,6 +744,46 @@ }

/**
* A Textdomain is a container for an esgettext configuration and all loaded
* LocaleContainer for the textual domain selected.
*
* The actual translation methods have quite funny names like `_()` or
* `_x()`. The purpose of this naming convention is to make the
* internationalization of your programs as little obtrusive as possible.
* Most of the times you just have to exchange
*
* ```
* doSomething('Hello, world!');
* ```
*
* with
*
* ```
* doSomething(gtx._('Hello, world!'));
* ```
*
* Besides, depending on the string extractor you are using, it may be useful
* that the method names do not collide with method names from other packages.
*/
class Textdomain {
/**
* Retrieve a translation for a string.
*
* @param msgid - the string to translate
*
* @returns the translated string
*/
_(msgid) {
return gettextImpl({ msgid: msgid, catalog: this.catalog });
}
/**
* Retrieve a translation for a string containing a possible plural.
* You will almost always want to call {@link _nx} instead so that
* you can interpolate the number of items into the strings.
*
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
*
* @returns the translated string
*/
_n(msgid, msgidPlural, numItems) {

@@ -619,2 +797,10 @@ return gettextImpl({

}
/**
* Translate a string with a context.
*
* @param msgctxt - the message context
* @param msgid - the string to translate
*
* @returns the translated string
*/
_p(msgctxt, msgid) {

@@ -627,2 +813,13 @@ return gettextImpl({

}
/**
* The method `_np()` combines `_n()` with `_p()`.
* You will almost always want to call {@link _npx} instead so that
* you can interpolate the number of items into the strings.
*
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - a dictionary with placehoders
* @returns the translated string
*/
_np(msgctxt, msgid, msgidPlural, numItems) {

@@ -637,5 +834,25 @@ return gettextImpl({

}
/**
* Translate a string with placeholders. The placeholders should be
* wrapped into curly braces and must match the regular expression
* "[_a-zA-Z][_a-zA-Z0-9]*".
*
* @param msgid - the msgid to translate
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string with placeholders expanded
*/
_x(msgid, placeholders) {
return Textdomain.expand(gettextImpl({ msgid: msgid, catalog: this.catalog }), placeholders || {});
}
/**
* Translate a string with a plural expression with placeholders.
*
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string
*/
_nx(msgid, msgidPlural, numItems, placeholders) {

@@ -649,5 +866,24 @@ return Textdomain.expand(gettextImpl({

}
/**
* The method `_px()` combines `_p()` with `_x()`.
*
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_px(msgctxt, msgid, placeholders) {
return Textdomain.expand(gettextImpl({ msgctxt: msgctxt, msgid: msgid, catalog: this.catalog }), placeholders || {});
}
/**
* The method `_npx()` brings it all together. It combines `_n()` and
* `_p()` and `_x()`.
*
* @param msgctxt - the message context
* @param msgid - the message id
* @param msgidPlural - the plural string
* @param numItems - the number of items
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_npx(msgctxt, msgid, msgidPlural, numItems, placeholders) {

@@ -674,2 +910,10 @@ return Textdomain.expand(gettextImpl({

}
/**
* Retrieve a translation for a string with a fixed locale.
*
* @param locale - the locale identifier
* @param msgid - the string to translate
*
* @returns the translated string
*/
_l(locale, msgid) {

@@ -679,2 +923,15 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* Retrieve a translation for a string containing a possible plural with
* a fixed locale.
* You will almost always want to call {@link _nx} instead so that
* you can interpolate the number of items into the strings.
*
* @param locale - the locale identifier
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
*
* @returns the translated string
*/
_ln(locale, msgid, msgidPlural, numItems) {

@@ -689,2 +946,11 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* Translate a string with a context with a fixed locale.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the string to translate
*
* @returns the translated string
*/
_lp(locale, msgctxt, msgid) {

@@ -694,2 +960,14 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* The method `_lnp()` combines `_ln()` with `_lp()`.
* You will almost always want to call {@link _npx} instead so that
* you can interpolate the number of items into the strings.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - a dictionary with placehoders
* @returns the translated string
*/
_lnp(locale, msgctxt, msgid, msgidPlural, numItems) {

@@ -705,2 +983,14 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* Translate a string with placeholders for a fixed locale.
* The placeholders should be
* wrapped into curly braces and must match the regular expression
* "[_a-zA-Z][_a-zA-Z0-9]*".
*
* @param locale - the locale identifier
* @param msgid - the msgid to translate
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string with placeholders expanded
*/
_lx(locale, msgid, placeholders) {

@@ -710,2 +1000,14 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* Translate a string with a plural expression with placeholders into a
* fixed locale.
*
* @param locale - the locale identifier
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string
*/
_lnx(locale, msgid, msgidPlural, numItems, placeholders) {

@@ -720,2 +1022,11 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* The method `_lpx()` combines `_lp()` with `_lx()`.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_lpx(locale, msgctxt, msgid, placeholders) {

@@ -725,2 +1036,14 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* The method `_lnpx()` brings it all together. It combines `_ln()` and
* `_lp()` and `_lx()`.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the message id
* @param msgidPlural - the plural string
* @param numItems - the number of items
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_lnpx(locale, msgctxt, msgid, msgidPlural, numItems, placeholders) {

@@ -746,2 +1069,10 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* Instantiate a Textdomain object. Textdomain objects are singletons
* for each textdomain identifier.
*
* @param textdomain - the textdomain of your application or library.
*
* @returns a [[`Textdomain`]]
*/
static getInstance(textdomain) {

@@ -768,5 +1099,12 @@ if (typeof textdomain === 'undefined' ||

}
/**
* Delete all existing singletons. This method should usually be called
* only, when you want to free memory.
*/
static clearInstances() {
Textdomain.boundDomains = {};
}
/**
* This method is used for testing. Do not use it yourself!
*/
static forgetInstances() {

@@ -776,5 +1114,31 @@ Textdomain.clearInstances();

}
/**
* Query the locale in use.
*/
static get locale() {
return Textdomain._locale;
}
/**
* Change the locale.
*
* For the web you can use all valid language identifier tags that
* [BCP47](https://tools.ietf.org/html/bcp47) allows
* (and actually a lot more). The tag is always used unmodified.
*
* For server environments, the locale identifier has to match the following
* scheme:
*
* `ll_CC.charset\@modifier`
*
* * `ll` is the two- or three-letter language code.
* * `CC` is the optional two-letter country code.
* * `charset` is an optional character set (letters, digits, and the hyphen).
* * `modifier` is an optional variant (letters and digits).
*
* The language code is always converted to lowercase, the country code is
* converted to uppercase, variant and charset are used as is.
*
* @param locale - the locale identifier
* @returns the locale in use
*/
static set locale(locale) {

@@ -790,2 +1154,3 @@ const ucLocale = locale.toUpperCase();

}
// Node.
split.tags[0] = split.tags[0].toLowerCase();

@@ -806,7 +1171,45 @@ if (split.tags.length > 1) {

this._catalogFormat = 'mo.json';
this.catalog = undefined;
this.domain = domain;
const msg = "The property 'locale' is not an instance property but static. Use 'Textdomain.locale' instead!";
Object.defineProperty(this, 'locale', {
get: () => {
throw new Error(msg);
},
set: () => {
throw new Error(msg);
},
enumerable: true,
configurable: true,
});
}
/**
* A textdomain is an identifier for your application or library. It is
* the basename of your translation files which are either
* TEXTDOMAIN.mo.json or TEXTDOMAIN.mo, depending on the format you have
* chosen.
*
* FIXME! This should be a getter!
*
* @returns the textdomain
*/
textdomain() {
return this.domain;
}
/**
* Bind a textdomain to a certain path or queries the path that a
* textdomain is bound to. The catalog file will be searched
* in `${path}/LC_MESSAGES/${domainname}.EXT` where `EXT` is the
* selected catalog format (one of `mo.json`, `mo`, or `json`).
*
* Alternatively, you can pass a [[`LocaleContainer`]] that holds the
* catalogs in memory.
*
* The returned string or `LocaleContainer` is valid until the next
* `bindtextdomain` call with an argument.
*
* @param path - the base path or [[`LocaleContainer`]] for this textdomain
*
* @returns the current base directory or [[`LocaleContainer`]] for this domain, after possibly changing it.
*/
bindtextdomain(path) {

@@ -818,31 +1221,57 @@ if (typeof path !== 'undefined') {

}
async resolve(locale) {
const promises = [this.resolve1(locale)];
for (const td in Textdomain.domains) {
if (Object.prototype.hasOwnProperty.call(Textdomain.domains, td) &&
Textdomain.domains[td] !== this) {
promises.push(Textdomain.domains[td].resolve1(locale));
/**
* Resolve a textdomain, i.e. load the LocaleContainer for this domain and all
* of its dependencies for the currently selected locale or the locale
* specified.
*
* The promise will always resolve. If no catalog was found, an empty
* catalog will be returned that is still usable.
*
* @param locale - an optional locale identifier, defaults to Textdomain.locale
*
* @returns a promise for a Catalog that will always resolve.
*/
resolve(locale) {
return __awaiter(this, void 0, void 0, function* () {
const promises = [this.resolve1(locale)];
for (const td in Textdomain.domains) {
if (Object.prototype.hasOwnProperty.call(Textdomain.domains, td) &&
Textdomain.domains[td] !== this) {
promises.push(Textdomain.domains[td].resolve1(locale));
}
}
}
return Promise.all(promises).then(values => {
return new Promise(resolve => resolve(values[0]));
return Promise.all(promises).then(values => {
return new Promise(resolve => resolve(values[0]));
});
});
}
async resolve1(locale) {
let path = this.bindtextdomain();
if (typeof path === 'undefined' || path === null) {
const parts = ['.', 'locale'];
path = parts.join(pathSeparator);
}
const resolvedLocale = locale ? locale : Textdomain.locale;
return resolveImpl(this.domain, path, this.catalogFormat, resolvedLocale).then(catalog => {
if (!locale) {
this.catalog = catalog;
resolve1(locale) {
return __awaiter(this, void 0, void 0, function* () {
let path = this.bindtextdomain();
if (typeof path === 'undefined' || path === null) {
const parts = ['.', 'locale'];
path = parts.join(pathSeparator);
}
return new Promise(resolve => resolve(catalog));
const resolvedLocale = locale ? locale : Textdomain.locale;
return resolveImpl(this.domain, path, this.catalogFormat, resolvedLocale).then(catalog => {
if (!locale) {
this.catalog = catalog;
}
return new Promise(resolve => resolve(catalog));
});
});
}
/**
* Get the catalog format in use.
*
* @returns one of 'mo.json' or 'mo' (default is 'mo.json')
*/
get catalogFormat() {
return this._catalogFormat;
}
/**
* Set the catalog format to use.
*
* @param format - one of 'mo.json' or 'mo'
*/
set catalogFormat(format) {

@@ -860,29 +1289,143 @@ format = format.toLowerCase();

}
/**
* Queries the user's preferred locales. On the server it queries the
* environment variables `LANGUAGE`, `LC_ALL`, `LANG`, and `LC_MESSAGES`
* (in that order). In the browser, it parses it checks the user preferences
* in the variables `navigator.languages`, `navigator.language`,
* `navigator.userLanguage`, `navigator.browserLanguage`, and
* `navigator.systemLanguage`.
*
* @returns the set of locales in order of preference
*
* Added in \@runtime 0.1.0.
*/
static userLocales() {
return userLocales();
}
/**
* Select one of the supported locales from a list of locales accepted by
* the user.
*
* @param supported - the list of locales supported by the application
* @param requested - the list of locales accepted by the user
*
* If called with just one argument, then the list of requested locales
* is determined by calling [[Textdomain.userLocales]].
*
* @returns the negotiated locale or 'C' if not possible.
*/
static selectLocale(supported, requested) {
return selectLocale(supported, requested !== null && requested !== void 0 ? requested : Textdomain.userLocales());
}
/**
* A no-op method for string marking.
*
* Sometimes you want to mark strings for translation but do not actually
* want to translate them, at least not at the time of their definition.
* This is often the case, when you have to preserve the original string.
*
* Take this example:
*
* ```
* orangeColors = [gtx.N_('coral'), gtx.N_('tomato'), gtx.N_('orangered'),
* gtx.N_('gold'), gtx.N_('orange'), gtx.N_('darkorange')]
* ```
*
* These are standard CSS colors, and you cannot translate them inside
* CSS styles. But for presentation you may want to translate them later:
*
* ```
* console.log(gtx._x("The css color '{color}' is {translated}.",
* {
* color: orangeColors[2],
* translated: gtx._(orangeColors[2]),
* }
* )
* );
* ```
*
* In other words: The method just marks strings for translation, so that
* the extractor `esgettext-xgettext` finds them but it does not actually
* translate anything.
*
* Similar methods are available for other cases (with placeholder
* expansion, context, or both). They are *not* available for plural
* methods because that would not make sense.
*
* Note that all of these methods are also available as instance methods.
*
* @param msgid - the message id
* @returns the original string
*/
static N_(msgid) {
return msgid;
}
/**
* Does the same as the static method `N_()`.
*
* @param msgid - the message id
* @returns the original string
*/
N_(msgid) {
return msgid;
}
/**
* Same as `N_()` but with placeholder expansion.
*
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
N_x(msgid, placeholders) {
return Textdomain.expand(msgid, placeholders !== null && placeholders !== void 0 ? placeholders : {});
}
/**
* Does the same as the static method `N_x()`.
*
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
static N_x(msgid, placeholders) {
return Textdomain.expand(msgid, placeholders !== null && placeholders !== void 0 ? placeholders : {});
}
/**
* Same as `N_()` but with context.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @returns the original string
*/
N_p(_msgctxt, msgid) {
return msgid;
}
/**
* Does the same as the static method `N_p()`.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @returns the original string with placeholders expanded
*/
static N_p(_msgctxt, msgid) {
return msgid;
}
/**
* Same as `N_()` but with context and placeholder expansion.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
N_px(_msgctxt, msgid, placeholders) {
return Textdomain.expand(msgid, placeholders !== null && placeholders !== void 0 ? placeholders : {});
}
/**
* Does the same as the static method `N_px()`.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
static N_px(_msgctxt, msgid, placeholders) {

@@ -893,6 +1436,6 @@ return Textdomain.expand(msgid, placeholders !== null && placeholders !== void 0 ? placeholders : {});

Textdomain.domains = {};
Textdomain.cache = CatalogCache.getInstance();
Textdomain.boundDomains = {};
Textdomain._locale = 'C';
// FIXME! Windows!
if (typeof process.env.LANGUAGE !== 'undefined') {

@@ -899,0 +1442,0 @@ userLocales(process.env.LANGUAGE.split(':'));

import { readFile } from 'fs';
let userLocalesSelected = ['C'];
/*
* Force an execution environment. By default, the environment (NodeJS or
* browser) is auto-detected. You can force the library to assume a certain
* environment with this function.
*
* @param browser - whether to assume a browser or not
* @returns the new setting.
*/
function userLocales(locales) {

@@ -11,2 +19,35 @@ if (typeof locales !== 'undefined') {

/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol */
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
/* eslint-disable @typescript-eslint/explicit-function-return-type */
class TransportHttp {

@@ -42,2 +83,9 @@ loadFile(url) {

/*
* Function for germanic plural. Returns singular (0) for 1 item, and
* 1 for everything else.
*
* @param numItems - number of items
* @returns the index into the plural translations
*/
function germanicPlural(numItems) {

@@ -47,3 +95,14 @@ return numItems === 1 ? 0 : 1;

/*
* A minimalistic buffer implementation that can only read 32 bit unsigned
* integers and strings.
*/
class DataViewlet {
/*
* Create a DataViewlet instance. All encodings that are supported by
* the runtime environments `TextDecoder` interface.
*
* @param array - a `Unit8Array` view on the binary buffer
* @param encoding - encoding of strings, defaults to utf-8
*/
constructor(array, encoding = 'utf-8') {

@@ -54,5 +113,15 @@ this.array = array;

}
/**
* Get the encoding for strings.
*
* @returns the encoding in use
*/
get encoding() {
return this._encoding;
}
/**
* Switch to a new encoding.
*
* @param encoding - new encoding to use
*/
set encoding(encoding) {

@@ -62,2 +131,11 @@ this.decoder = new TextDecoder(encoding);

}
/*
* Reads an unsigned 32-bit integer from the buffer at
* the specified offset as big-endian.
*
* @param offset - Number of bytes to skip before starting to read.
* Must satisfy `0 <= offset <= buf.length - 4`.
* Default: 0.
* @returns the 32-bit unsigned integer at position `offset`.s
*/
readUInt32BE(offset = 0) {

@@ -73,2 +151,11 @@ if (offset + 4 > this.array.byteLength + this.array.byteOffset) {

}
/*
* Reads an unsigned 32-bit integer from the buffer at
* the specified offset as little-endian.
*
* @param offset - Number of bytes to skip before starting to read.
* Must satisfy `0 <= offset <= buf.length - 4`.
* Default: 0.
* @returns the 32-bit unsigned integer at position `offset`.s
*/
readUInt32LE(offset = 0) {

@@ -84,2 +171,9 @@ if (offset + 4 > this.array.byteLength + this.array.byteOffset) {

}
/*
* Read a string at a specified offset.
*
* @param offset - to beginning of buffer in bytes
* @param length - of the string to read in bytes or to the end of the
* buffer if not specified.
*/
readString(offset = 0, length) {

@@ -97,2 +191,11 @@ if (offset + length >

/*
* Parse an MO file.
*
* An exception is thrown for invalid data.
*
* @param raw - The input as either a binary `String`, any `Array`-like byte
* storage (`Array`, `Uint8Array`, `Arguments`, `jQuery(Array)`, ...)
* @returns a Catalog
*/
function parseMoCatalog(raw) {

@@ -110,5 +213,7 @@ const catalog = {

if (magic === 0x950412de) {
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
reader = (buf, off) => buf.readUInt32LE(off);
}
else if (magic === 0xde120495) {
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
reader = (buf, off) => buf.readUInt32BE(off);

@@ -120,2 +225,4 @@ }

offset += 4;
// The revision is encoded in two shorts, major and minor. We don't care
// about the minor revision.
const major = reader(blob, offset) >> 16;

@@ -181,2 +288,6 @@ offset += 4;

function validateMoJsonCatalog(udata) {
// We could use ajv but it results in almost 300 k minimized code
// for the browser bundle. This validator instead is absolutely
// minimalistic, and only avoids exceptions that can occur, when
// accessing entries.
if (udata === null || typeof udata === 'undefined') {

@@ -189,2 +300,4 @@ throw new Error('catalog is either null or undefined');

}
// We don't care about major and minor because they are actually not
// used.
if (!Object.prototype.hasOwnProperty.call(data, 'entries')) {

@@ -214,2 +327,6 @@ throw new Error('catalog.entries does not exist');

function validateJsonCatalog(udata) {
// We could use ajv but it results in almost 300 k minimized code
// for the browser bundle. This validator instead is absolutely
// minimalistic, and only avoids exceptions that can occur, when
// accessing entries.
if (udata === null || typeof udata === 'undefined') {

@@ -220,2 +337,3 @@ throw new Error('catalog is either null or undefined');

if (entries.constructor !== Object) ;
// Convert to a regular catalog.
const catalog = {

@@ -228,2 +346,3 @@ major: 0,

for (const [msgid, msgstr] of Object.entries(entries)) {
// Just stringify all values but do not complain.
catalog.entries[msgid] = [msgstr.toString()];

@@ -274,4 +393,15 @@ }

/*
* Caches catalog lookups by path, locale, and textdomain.
*
* Failed lookups are stored as null values.
*
* It is also possible to store a Promise. In that case, if a request is
* made to bind the textdomain, the promise is settled. Note that this
* mechanism is never used for message lookup but only for loading the
* catalog via resolve.
*/
class CatalogCache {
constructor() {
/* Singleton. */
}

@@ -287,2 +417,13 @@ static getInstance() {

}
/**
* Lookup a Catalog for a given base path, locale, and textdomain.
*
* The locale key is usually the locale identifier (e.g. de-DE or sr\@latin).
* But it can also be a colon separated list of such locale identifiers.
*
*
* @param localeKey - the locale key
* @param textdomain - the textdomain
* @returns the cached Catalog, a Promise or null for failure
*/
static lookup(localeKey, textdomain) {

@@ -299,2 +440,3 @@ if (CatalogCache.cache[localeKey]) {

if (Promise.resolve(entry) !== entry) {
// Object.
entry = validateMoJsonCatalog(entry);

@@ -341,45 +483,47 @@ }

function loadCatalog(url, format) {
let transportInstance;
{
let transport;
try {
const parsedURL = new URL(url);
if (parsedURL.protocol === 'https:' ||
parsedURL.protocol === 'http:' ||
parsedURL.protocol === 'file:') {
transport = 'http';
return __awaiter(this, void 0, void 0, function* () {
let transportInstance;
{
let transport;
// Check whether this is a valid URL.
try {
const parsedURL = new URL(url);
if (parsedURL.protocol === 'https:' ||
parsedURL.protocol === 'http:' ||
parsedURL.protocol === 'file:') {
transport = 'http';
}
else {
throw new Error(`unsupported scheme ${parsedURL.protocol}`);
}
}
catch (e) {
{
transport = 'fs';
}
}
if (transport === 'http') {
transportInstance = new TransportHttp();
}
else {
throw new Error(`unsupported scheme ${parsedURL.protocol}`);
transportInstance = new TransportFs();
}
}
catch (e) {
{
transport = 'fs';
}
let validator;
if ('mo.json' === format) {
validator = parseMoJsonCatalog;
}
if (transport === 'http') {
transportInstance = new TransportHttp();
else if ('.json' === format) {
validator = parseJsonCatalog;
}
else {
transportInstance = new TransportFs();
validator = parseMoCatalog;
}
}
let validator;
if ('mo.json' === format) {
validator = parseMoJsonCatalog;
}
else if ('.json' === format) {
validator = parseJsonCatalog;
}
else {
validator = parseMoCatalog;
}
return new Promise((resolve, reject) => {
transportInstance
.loadFile(url)
.then(data => {
resolve(validator(data));
})
.catch(e => reject(e));
try {
const data = yield transportInstance.loadFile(url);
return validator(data);
}
catch (_a) {
return null;
}
});

@@ -391,75 +535,65 @@ }

function loadLanguageFromObject(ids, base, domainname) {
let catalog;
for (let i = 0; i < ids.length; ++i) {
const id = ids[0];
if (!Object.prototype.hasOwnProperty.call(base, id)) {
continue;
return __awaiter(this, void 0, void 0, function* () {
for (let i = 0; i < ids.length; ++i) {
const id = ids[i];
// Language exists?
if (!Object.prototype.hasOwnProperty.call(base, id)) {
continue;
}
// LC_MESSAGES?
if (!Object.prototype.hasOwnProperty.call(base[id], 'LC_MESSAGES')) {
continue;
}
// Textdomain?
if (!Object.prototype.hasOwnProperty.call(base[id].LC_MESSAGES, domainname)) {
continue;
}
return base[id].LC_MESSAGES[domainname];
}
if (!Object.prototype.hasOwnProperty.call(base[id], 'LC_MESSAGES')) {
continue;
return null;
});
}
/*
* First tries to load a catalog with the specified charset, then with the
* charset converted to uppercase (if it differs from the original charset),
* and finally without a charset.
*/
function loadLanguage(ids, base, domainname, format) {
return __awaiter(this, void 0, void 0, function* () {
// Check if `base` is an object (LocaleContainer).
if (typeof base === 'object' && base !== null) {
return loadLanguageFromObject(ids, base, domainname);
}
if (!Object.prototype.hasOwnProperty.call(base[id].LC_MESSAGES, domainname)) {
continue;
for (const id of ids) {
const catalog = yield loadCatalog(assemblePath(base, id, domainname, format), format);
if (catalog) {
return catalog;
}
}
catalog = base[id].LC_MESSAGES[domainname];
}
return new Promise((resolve, reject) => {
if (catalog) {
resolve(catalog);
}
else {
reject();
}
return null;
});
}
async function loadLanguage(ids, base, domainname, format) {
if (typeof base === 'object' && base !== null) {
return loadLanguageFromObject(ids, base, domainname);
}
return new Promise((resolve, reject) => {
const tries = new Array();
ids.forEach(id => {
tries.push(() => loadCatalog(assemblePath(base, id, domainname, format), format));
});
tries
.reduce((promise, fn) => promise.catch(fn), Promise.reject())
.then(value => resolve(value))
.catch(e => reject(e));
});
}
async function loadDomain(exploded, localeKey, base, domainname, format) {
const entries = {};
const catalog = {
major: 0,
minor: 0,
pluralFunction: germanicPlural,
entries,
};
const cacheHit = CatalogCache.lookup(localeKey, domainname);
if (cacheHit !== null) {
if (Promise.resolve(cacheHit) === cacheHit) {
function loadDomain(exploded, localeKey, base, domainname, format) {
return __awaiter(this, void 0, void 0, function* () {
const entries = {};
const catalog = {
major: 0,
minor: 0,
pluralFunction: germanicPlural,
entries,
};
const cacheHit = yield CatalogCache.lookup(localeKey, domainname);
if (cacheHit !== null) {
return cacheHit;
}
else {
return new Promise(resolve => resolve(cacheHit));
for (const tries of exploded) {
const result = yield loadLanguage(tries, base, domainname, format);
if (result) {
catalog.major = result.major;
catalog.minor = result.minor;
catalog.entries = Object.assign(Object.assign({}, catalog.entries), result.entries);
}
}
}
const promises = new Array();
const results = new Array();
exploded.forEach((tries, i) => {
const p = loadLanguage(tries, base, domainname, format)
.then(catalog => (results[i] = catalog))
.catch(() => {
});
promises.push(p);
return catalog;
});
await Promise.all(promises);
results.forEach(result => {
catalog.major = result.major;
catalog.minor = result.minor;
catalog.entries = Object.assign(Object.assign({}, catalog.entries), result.entries);
});
return new Promise(resolve => {
resolve(catalog);
});
}

@@ -470,2 +604,3 @@ function pluralExpression(str) {

.replace(/;$/, '')
// Do NOT allow square brackets here. JSFuck!
.split(/[<>!=]=|&&|\|\||[-!*/%+<>=?:;]/);

@@ -477,2 +612,4 @@ for (let i = 0; i < tokens.length; ++i) {

token !== 'n' &&
// Does not catch invalid octal numbers but the compiler
// takes care of that.
null === /^[0-9]+$/.exec(token)) {

@@ -483,2 +620,4 @@ throw new Error('invalid plural function');

const code = 'var nplurals = 1, plural = 0;' + str + '; return 0 + plural';
// This may throw an exception!
// eslint-disable-next-line @typescript-eslint/no-implied-eval
return new Function('n', code);

@@ -495,3 +634,8 @@ }

const code = tokens.join(':');
catalog.pluralFunction = pluralExpression(code);
try {
catalog.pluralFunction = pluralExpression(code);
}
catch (_a) {
catalog.pluralFunction = germanicPlural;
}
}

@@ -502,23 +646,17 @@ });

function resolveImpl(domainname, path, format, localeKey) {
const defaultCatalog = {
major: 0,
minor: 0,
pluralFunction: germanicPlural,
entries: {},
};
if (localeKey === 'C' || localeKey === 'POSIX') {
return new Promise(resolve => resolve(defaultCatalog));
}
return new Promise(resolve => {
return __awaiter(this, void 0, void 0, function* () {
const defaultCatalog = {
major: 0,
minor: 0,
pluralFunction: germanicPlural,
entries: {},
};
if (localeKey === 'C' || localeKey === 'POSIX') {
return defaultCatalog;
}
const exploded = explodeLocale(splitLocale(localeKey));
loadDomain(exploded, localeKey, path, domainname, format)
.then(catalog => {
setPluralFunction(catalog);
CatalogCache.store(localeKey, domainname, catalog);
resolve(catalog);
})
.catch(() => {
CatalogCache.store(localeKey, domainname, defaultCatalog);
resolve(defaultCatalog);
});
const catalog = yield loadDomain(exploded, localeKey, path, domainname, format);
setPluralFunction(catalog);
CatalogCache.store(localeKey, domainname, catalog);
return catalog;
});

@@ -603,6 +741,46 @@ }

/**
* A Textdomain is a container for an esgettext configuration and all loaded
* LocaleContainer for the textual domain selected.
*
* The actual translation methods have quite funny names like `_()` or
* `_x()`. The purpose of this naming convention is to make the
* internationalization of your programs as little obtrusive as possible.
* Most of the times you just have to exchange
*
* ```
* doSomething('Hello, world!');
* ```
*
* with
*
* ```
* doSomething(gtx._('Hello, world!'));
* ```
*
* Besides, depending on the string extractor you are using, it may be useful
* that the method names do not collide with method names from other packages.
*/
class Textdomain {
/**
* Retrieve a translation for a string.
*
* @param msgid - the string to translate
*
* @returns the translated string
*/
_(msgid) {
return gettextImpl({ msgid: msgid, catalog: this.catalog });
}
/**
* Retrieve a translation for a string containing a possible plural.
* You will almost always want to call {@link _nx} instead so that
* you can interpolate the number of items into the strings.
*
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
*
* @returns the translated string
*/
_n(msgid, msgidPlural, numItems) {

@@ -616,2 +794,10 @@ return gettextImpl({

}
/**
* Translate a string with a context.
*
* @param msgctxt - the message context
* @param msgid - the string to translate
*
* @returns the translated string
*/
_p(msgctxt, msgid) {

@@ -624,2 +810,13 @@ return gettextImpl({

}
/**
* The method `_np()` combines `_n()` with `_p()`.
* You will almost always want to call {@link _npx} instead so that
* you can interpolate the number of items into the strings.
*
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - a dictionary with placehoders
* @returns the translated string
*/
_np(msgctxt, msgid, msgidPlural, numItems) {

@@ -634,5 +831,25 @@ return gettextImpl({

}
/**
* Translate a string with placeholders. The placeholders should be
* wrapped into curly braces and must match the regular expression
* "[_a-zA-Z][_a-zA-Z0-9]*".
*
* @param msgid - the msgid to translate
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string with placeholders expanded
*/
_x(msgid, placeholders) {
return Textdomain.expand(gettextImpl({ msgid: msgid, catalog: this.catalog }), placeholders || {});
}
/**
* Translate a string with a plural expression with placeholders.
*
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string
*/
_nx(msgid, msgidPlural, numItems, placeholders) {

@@ -646,5 +863,24 @@ return Textdomain.expand(gettextImpl({

}
/**
* The method `_px()` combines `_p()` with `_x()`.
*
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_px(msgctxt, msgid, placeholders) {
return Textdomain.expand(gettextImpl({ msgctxt: msgctxt, msgid: msgid, catalog: this.catalog }), placeholders || {});
}
/**
* The method `_npx()` brings it all together. It combines `_n()` and
* `_p()` and `_x()`.
*
* @param msgctxt - the message context
* @param msgid - the message id
* @param msgidPlural - the plural string
* @param numItems - the number of items
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_npx(msgctxt, msgid, msgidPlural, numItems, placeholders) {

@@ -671,2 +907,10 @@ return Textdomain.expand(gettextImpl({

}
/**
* Retrieve a translation for a string with a fixed locale.
*
* @param locale - the locale identifier
* @param msgid - the string to translate
*
* @returns the translated string
*/
_l(locale, msgid) {

@@ -676,2 +920,15 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* Retrieve a translation for a string containing a possible plural with
* a fixed locale.
* You will almost always want to call {@link _nx} instead so that
* you can interpolate the number of items into the strings.
*
* @param locale - the locale identifier
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
*
* @returns the translated string
*/
_ln(locale, msgid, msgidPlural, numItems) {

@@ -686,2 +943,11 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* Translate a string with a context with a fixed locale.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the string to translate
*
* @returns the translated string
*/
_lp(locale, msgctxt, msgid) {

@@ -691,2 +957,14 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* The method `_lnp()` combines `_ln()` with `_lp()`.
* You will almost always want to call {@link _npx} instead so that
* you can interpolate the number of items into the strings.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - a dictionary with placehoders
* @returns the translated string
*/
_lnp(locale, msgctxt, msgid, msgidPlural, numItems) {

@@ -702,2 +980,14 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* Translate a string with placeholders for a fixed locale.
* The placeholders should be
* wrapped into curly braces and must match the regular expression
* "[_a-zA-Z][_a-zA-Z0-9]*".
*
* @param locale - the locale identifier
* @param msgid - the msgid to translate
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string with placeholders expanded
*/
_lx(locale, msgid, placeholders) {

@@ -707,2 +997,14 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* Translate a string with a plural expression with placeholders into a
* fixed locale.
*
* @param locale - the locale identifier
* @param msgid - the string in the singular
* @param msgidPlural - the string in the plural
* @param numItems - the number of items
* @param placeholders - an optional dictionary of placeholders
*
* @returns the translated string
*/
_lnx(locale, msgid, msgidPlural, numItems, placeholders) {

@@ -717,2 +1019,11 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* The method `_lpx()` combines `_lp()` with `_lx()`.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the message id
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_lpx(locale, msgctxt, msgid, placeholders) {

@@ -722,2 +1033,14 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* The method `_lnpx()` brings it all together. It combines `_ln()` and
* `_lp()` and `_lx()`.
*
* @param locale - the locale identifier
* @param msgctxt - the message context
* @param msgid - the message id
* @param msgidPlural - the plural string
* @param numItems - the number of items
* @param placeholders - an optional dictionary with placehoders
* @returns the translated string
*/
_lnpx(locale, msgctxt, msgid, msgidPlural, numItems, placeholders) {

@@ -743,2 +1066,10 @@ const catalog = Textdomain.getCatalog(locale, this.textdomain());

}
/**
* Instantiate a Textdomain object. Textdomain objects are singletons
* for each textdomain identifier.
*
* @param textdomain - the textdomain of your application or library.
*
* @returns a [[`Textdomain`]]
*/
static getInstance(textdomain) {

@@ -765,5 +1096,12 @@ if (typeof textdomain === 'undefined' ||

}
/**
* Delete all existing singletons. This method should usually be called
* only, when you want to free memory.
*/
static clearInstances() {
Textdomain.boundDomains = {};
}
/**
* This method is used for testing. Do not use it yourself!
*/
static forgetInstances() {

@@ -773,5 +1111,31 @@ Textdomain.clearInstances();

}
/**
* Query the locale in use.
*/
static get locale() {
return Textdomain._locale;
}
/**
* Change the locale.
*
* For the web you can use all valid language identifier tags that
* [BCP47](https://tools.ietf.org/html/bcp47) allows
* (and actually a lot more). The tag is always used unmodified.
*
* For server environments, the locale identifier has to match the following
* scheme:
*
* `ll_CC.charset\@modifier`
*
* * `ll` is the two- or three-letter language code.
* * `CC` is the optional two-letter country code.
* * `charset` is an optional character set (letters, digits, and the hyphen).
* * `modifier` is an optional variant (letters and digits).
*
* The language code is always converted to lowercase, the country code is
* converted to uppercase, variant and charset are used as is.
*
* @param locale - the locale identifier
* @returns the locale in use
*/
static set locale(locale) {

@@ -787,2 +1151,3 @@ const ucLocale = locale.toUpperCase();

}
// Node.
split.tags[0] = split.tags[0].toLowerCase();

@@ -803,7 +1168,45 @@ if (split.tags.length > 1) {

this._catalogFormat = 'mo.json';
this.catalog = undefined;
this.domain = domain;
const msg = "The property 'locale' is not an instance property but static. Use 'Textdomain.locale' instead!";
Object.defineProperty(this, 'locale', {
get: () => {
throw new Error(msg);
},
set: () => {
throw new Error(msg);
},
enumerable: true,
configurable: true,
});
}
/**
* A textdomain is an identifier for your application or library. It is
* the basename of your translation files which are either
* TEXTDOMAIN.mo.json or TEXTDOMAIN.mo, depending on the format you have
* chosen.
*
* FIXME! This should be a getter!
*
* @returns the textdomain
*/
textdomain() {
return this.domain;
}
/**
* Bind a textdomain to a certain path or queries the path that a
* textdomain is bound to. The catalog file will be searched
* in `${path}/LC_MESSAGES/${domainname}.EXT` where `EXT` is the
* selected catalog format (one of `mo.json`, `mo`, or `json`).
*
* Alternatively, you can pass a [[`LocaleContainer`]] that holds the
* catalogs in memory.
*
* The returned string or `LocaleContainer` is valid until the next
* `bindtextdomain` call with an argument.
*
* @param path - the base path or [[`LocaleContainer`]] for this textdomain
*
* @returns the current base directory or [[`LocaleContainer`]] for this domain, after possibly changing it.
*/
bindtextdomain(path) {

@@ -815,31 +1218,57 @@ if (typeof path !== 'undefined') {

}
async resolve(locale) {
const promises = [this.resolve1(locale)];
for (const td in Textdomain.domains) {
if (Object.prototype.hasOwnProperty.call(Textdomain.domains, td) &&
Textdomain.domains[td] !== this) {
promises.push(Textdomain.domains[td].resolve1(locale));
/**
* Resolve a textdomain, i.e. load the LocaleContainer for this domain and all
* of its dependencies for the currently selected locale or the locale
* specified.
*
* The promise will always resolve. If no catalog was found, an empty
* catalog will be returned that is still usable.
*
* @param locale - an optional locale identifier, defaults to Textdomain.locale
*
* @returns a promise for a Catalog that will always resolve.
*/
resolve(locale) {
return __awaiter(this, void 0, void 0, function* () {
const promises = [this.resolve1(locale)];
for (const td in Textdomain.domains) {
if (Object.prototype.hasOwnProperty.call(Textdomain.domains, td) &&
Textdomain.domains[td] !== this) {
promises.push(Textdomain.domains[td].resolve1(locale));
}
}
}
return Promise.all(promises).then(values => {
return new Promise(resolve => resolve(values[0]));
return Promise.all(promises).then(values => {
return new Promise(resolve => resolve(values[0]));
});
});
}
async resolve1(locale) {
let path = this.bindtextdomain();
if (typeof path === 'undefined' || path === null) {
const parts = ['.', 'locale'];
path = parts.join(pathSeparator);
}
const resolvedLocale = locale ? locale : Textdomain.locale;
return resolveImpl(this.domain, path, this.catalogFormat, resolvedLocale).then(catalog => {
if (!locale) {
this.catalog = catalog;
resolve1(locale) {
return __awaiter(this, void 0, void 0, function* () {
let path = this.bindtextdomain();
if (typeof path === 'undefined' || path === null) {
const parts = ['.', 'locale'];
path = parts.join(pathSeparator);
}
return new Promise(resolve => resolve(catalog));
const resolvedLocale = locale ? locale : Textdomain.locale;
return resolveImpl(this.domain, path, this.catalogFormat, resolvedLocale).then(catalog => {
if (!locale) {
this.catalog = catalog;
}
return new Promise(resolve => resolve(catalog));
});
});
}
/**
* Get the catalog format in use.
*
* @returns one of 'mo.json' or 'mo' (default is 'mo.json')
*/
get catalogFormat() {
return this._catalogFormat;
}
/**
* Set the catalog format to use.
*
* @param format - one of 'mo.json' or 'mo'
*/
set catalogFormat(format) {

@@ -857,29 +1286,143 @@ format = format.toLowerCase();

}
/**
* Queries the user's preferred locales. On the server it queries the
* environment variables `LANGUAGE`, `LC_ALL`, `LANG`, and `LC_MESSAGES`
* (in that order). In the browser, it parses it checks the user preferences
* in the variables `navigator.languages`, `navigator.language`,
* `navigator.userLanguage`, `navigator.browserLanguage`, and
* `navigator.systemLanguage`.
*
* @returns the set of locales in order of preference
*
* Added in \@runtime 0.1.0.
*/
static userLocales() {
return userLocales();
}
/**
* Select one of the supported locales from a list of locales accepted by
* the user.
*
* @param supported - the list of locales supported by the application
* @param requested - the list of locales accepted by the user
*
* If called with just one argument, then the list of requested locales
* is determined by calling [[Textdomain.userLocales]].
*
* @returns the negotiated locale or 'C' if not possible.
*/
static selectLocale(supported, requested) {
return selectLocale(supported, requested !== null && requested !== void 0 ? requested : Textdomain.userLocales());
}
/**
* A no-op method for string marking.
*
* Sometimes you want to mark strings for translation but do not actually
* want to translate them, at least not at the time of their definition.
* This is often the case, when you have to preserve the original string.
*
* Take this example:
*
* ```
* orangeColors = [gtx.N_('coral'), gtx.N_('tomato'), gtx.N_('orangered'),
* gtx.N_('gold'), gtx.N_('orange'), gtx.N_('darkorange')]
* ```
*
* These are standard CSS colors, and you cannot translate them inside
* CSS styles. But for presentation you may want to translate them later:
*
* ```
* console.log(gtx._x("The css color '{color}' is {translated}.",
* {
* color: orangeColors[2],
* translated: gtx._(orangeColors[2]),
* }
* )
* );
* ```
*
* In other words: The method just marks strings for translation, so that
* the extractor `esgettext-xgettext` finds them but it does not actually
* translate anything.
*
* Similar methods are available for other cases (with placeholder
* expansion, context, or both). They are *not* available for plural
* methods because that would not make sense.
*
* Note that all of these methods are also available as instance methods.
*
* @param msgid - the message id
* @returns the original string
*/
static N_(msgid) {
return msgid;
}
/**
* Does the same as the static method `N_()`.
*
* @param msgid - the message id
* @returns the original string
*/
N_(msgid) {
return msgid;
}
/**
* Same as `N_()` but with placeholder expansion.
*
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
N_x(msgid, placeholders) {
return Textdomain.expand(msgid, placeholders !== null && placeholders !== void 0 ? placeholders : {});
}
/**
* Does the same as the static method `N_x()`.
*
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
static N_x(msgid, placeholders) {
return Textdomain.expand(msgid, placeholders !== null && placeholders !== void 0 ? placeholders : {});
}
/**
* Same as `N_()` but with context.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @returns the original string
*/
N_p(_msgctxt, msgid) {
return msgid;
}
/**
* Does the same as the static method `N_p()`.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @returns the original string with placeholders expanded
*/
static N_p(_msgctxt, msgid) {
return msgid;
}
/**
* Same as `N_()` but with context and placeholder expansion.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
N_px(_msgctxt, msgid, placeholders) {
return Textdomain.expand(msgid, placeholders !== null && placeholders !== void 0 ? placeholders : {});
}
/**
* Does the same as the static method `N_px()`.
*
* @param _msgctxt - the message context (not used)
* @param msgid - the message id
* @param placeholders - a dictionary of placeholders
* @returns the original string with placeholders expanded
*/
static N_px(_msgctxt, msgid, placeholders) {

@@ -890,6 +1433,6 @@ return Textdomain.expand(msgid, placeholders !== null && placeholders !== void 0 ? placeholders : {});

Textdomain.domains = {};
Textdomain.cache = CatalogCache.getInstance();
Textdomain.boundDomains = {};
Textdomain._locale = 'C';
// FIXME! Windows!
if (typeof process.env.LANGUAGE !== 'undefined') {

@@ -896,0 +1439,0 @@ userLocales(process.env.LANGUAGE.split(':'));

@@ -1,2 +0,2 @@

!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).esgettext={})}(this,(function(t){"use strict";let e=!1;function r(t){return void 0!==t&&(e=t),e}let n=["C"];function o(t){return void 0!==t&&(n=t),n}class a{loadFile(t){return new Promise(((e,r)=>{const n=new XMLHttpRequest;n.responseType="arraybuffer",n.open("GET",t,!0),n.onload=()=>{4===n.readyState&&200===n.status?e(n.response):r(new Error("get failed with status "+n.status))},n.onerror=t=>r(t),n.send()}))}}function s(t){return 1===t?0:1}class i{constructor(t,e="utf-8"){this.array=t,this.decoder=new TextDecoder(e),this._encoding=e}get encoding(){return this._encoding}set encoding(t){this.decoder=new TextDecoder(t),this._encoding=t}readUInt32BE(t=0){if(t+4>this.array.byteLength+this.array.byteOffset)throw new Error("read past array end");return(this.array[t]<<24>>>0|this.array[t+1]<<16|this.array[t+2]<<8|this.array[t+3])>>>0}readUInt32LE(t=0){if(t+4>this.array.byteLength+this.array.byteOffset)throw new Error("read past array end");return(this.array[t+3]<<24>>>0|this.array[t+2]<<16|this.array[t+1]<<8|this.array[t])>>>0}readString(t=0,e){if(t+e>this.array.byteLength+this.array.byteOffset)throw new Error("read past array end");return void 0===e&&(e=this.array.byteLength-t),this.decoder.decode(this.array.slice(t,t+e))}}function c(t){const e={major:0,minor:0,entries:{},pluralFunction:s};let r=0;const n=new i(new Uint8Array(t),"ascii"),o=n.readUInt32LE(r);let a;if(2500072158===o)a=(t,e)=>t.readUInt32LE(e);else{if(3725722773!==o)throw new Error(`invalid MO magic 0x${o.toString(16)}`);a=(t,e)=>t.readUInt32BE(e)}r+=4;const c=a(n,r)>>16;if(r+=4,c>0)throw new Error(`unsupported major revision ${c}`);const l=a(n,r);r+=4;const u=a(n,r);r+=4;const g=a(n,r);r=u;const d=[];for(let t=0;t<l;++t){const t=a(n,r);r+=4;const e=a(n,r);r+=4,d.push([t,e])}r=g;const h=[];for(let t=0;t<l;++t){const t=a(n,r);r+=4;const e=a(n,r);r+=4,h.push([t,e])}const p={};for(let t=0;t<l;++t){const o=d[t];let a=o[0];r=o[1];const s=n.readString(r,a).split("\0")[0],i=h[t];a=i[0],r=i[1];const c=n.readString(r,a).split("\0");let l,u;if(0===t&&""===s){l=c[0].split("\n");for(let t=0;t<l.length;++t)""!==l[t]&&(u=l[t].split(/[ \t]*:[ \t]*/),p[u[0].toLowerCase()]=u[1]);if(void 0!==p["content-type"]){const t=p["content-type"].replace(/.*=/,"");t!==p["content-type"]&&(n.encoding=t)}}e.entries[s]=c}return e}function l(t){if(null==t)throw new Error("catalog is either null or undefined");const e=t;if(e.constructor!==Object)throw new Error("catalog must be a dictionary");if(!Object.prototype.hasOwnProperty.call(e,"entries"))throw new Error("catalog.entries does not exist");const r=e.entries;if(null==r)throw new Error("catalog.entries are not defined or null");if(r.constructor!==Object)throw new Error("catalog.entries must be a dictionary");for(const[t,e]of Object.entries(r))if(!Array.isArray(e))throw new Error(`catalog entry for key '${t}' is not an array`);return e}function u(t){const e=(new TextDecoder).decode(t);return l(JSON.parse(e))}function g(t){const e=(new TextDecoder).decode(t);return function(t){if(null==t)throw new Error("catalog is either null or undefined");const e=t;e.constructor;const r={major:0,minor:1,pluralFunction:()=>0,entries:{}};for(const[t,n]of Object.entries(e))r.entries[t]=[n.toString()];return r}(JSON.parse(e))}const d=new RegExp("^[a-z0-9]+(?:-[a-z0-9]+)*$","i"),h=new RegExp("^[a-z0-9]+(?:_[a-z0-9]+)*$","i");function p(t){let e="",r="";const n=t.includes("_");if(t=(t=t.replace(/@([a-z]+)$/i,((t,e)=>(r=e,"")))).replace(/\.([-0-9a-z]+)$/i,((t,r)=>(e=r,""))),n){if(!h.exec(t))return null}else if(!d.exec(t))return null;const o=n?"_":"-",a={tags:t.split(o),underscoreSeparator:n};return e.length&&(a.charset=e),r.length&&(a.modifier=r),a}class m{constructor(){}static getInstance(){return m.instance||(m.instance=new m),m.instance}static clear(){m.cache={}}static lookup(t,e){if(m.cache[t]){const r=m.cache[t];if(Object.prototype.hasOwnProperty.call(r,e))return r[e]}return null}static store(t,e,r){Promise.resolve(r)!==r&&(r=l(r)),m.cache[t]||(m.cache[t]={}),m.cache[t][e]=r}}async function f(t,e,r,n){return"object"==typeof e&&null!==e?function(t,e,r){let n;for(let o=0;o<t.length;++o){const o=t[0];Object.prototype.hasOwnProperty.call(e,o)&&Object.prototype.hasOwnProperty.call(e[o],"LC_MESSAGES")&&Object.prototype.hasOwnProperty.call(e[o].LC_MESSAGES,r)&&(n=e[o].LC_MESSAGES[r])}return new Promise(((t,e)=>{n?t(n):e()}))}(t,e,r):new Promise(((o,s)=>{const i=new Array;t.forEach((t=>{i.push((()=>function(t,e){let r,n;return r=new a,n="mo.json"===e?u:".json"===e?g:c,new Promise(((e,o)=>{r.loadFile(t).then((t=>{e(n(t))})).catch((t=>o(t)))}))}(function(t,e,r,n){return`${t}/${e}/LC_MESSAGES/${r}.${n}`}(e,t,r,n),n)))})),i.reduce(((t,e)=>t.catch(e)),Promise.reject()).then((t=>o(t))).catch((t=>s(t)))}))}function w(t){if(!Object.prototype.hasOwnProperty.call(t.entries,""))return t;return t.entries[""][0].split("\n").forEach((e=>{const r=e.split(":");if("plural-forms"===r.shift().toLowerCase()){const e=r.join(":");t.pluralFunction=function(t){const e=t.replace(/[ \t\r\013\014]/g,"").replace(/;$/,"").split(/[<>!=]=|&&|\|\||[-!*/%+<>=?:;]/);for(let t=0;t<e.length;++t){const r=e[t].replace(/^\(+/,"").replace(/\)+$/,"");if("nplurals"!==r&&"plural"!==r&&"n"!==r&&null===/^[0-9]+$/.exec(r))throw new Error("invalid plural function")}return new Function("n","var nplurals = 1, plural = 0;"+t+"; return 0 + plural")}(e)}})),t}function y(t,e,r,n){const o={major:0,minor:0,pluralFunction:s,entries:{}};return new Promise("C"===n||"POSIX"===n?t=>t(o):a=>{(async function(t,e,r,n,o){const a={major:0,minor:0,pluralFunction:s,entries:{}},i=m.lookup(e,n);if(null!==i)return Promise.resolve(i)===i?i:new Promise((t=>t(i)));const c=new Array,l=new Array;return t.forEach(((t,e)=>{const a=f(t,r,n,o).then((t=>l[e]=t)).catch((()=>{}));c.push(a)})),await Promise.all(c),l.forEach((t=>{a.major=t.major,a.minor=t.minor,a.entries=Object.assign(Object.assign({},a.entries),t.entries)})),new Promise((t=>{t(a)}))})(function(t,e){const r=[],n=t.underscoreSeparator?"_":"-";let o=0;const a=void 0!==t.charset,s=void 0!==t.modifier,i=a?[t.charset]:[""];if(a){const e=t.charset,r=e.toUpperCase();r!==e&&i.push(r),i.push("")}for(;o<t.tags.length;++o){const e=t.tags.slice(0,o+1).join(n),a=new Array;i.forEach((r=>{let n=r.length?e+"."+r:e;s&&(n+="@"+t.modifier),a.push(n)})),r.push(a)}return r}(p(n)),n,e,t,r).then((e=>{w(e),m.store(n,t,e),a(e)})).catch((()=>{m.store(n,t,o),a(o)}))})}function x(t){var e;const r=void 0===t.msgctxt?t.msgid:t.msgctxt+""+t.msgid,n=t.catalog.entries[r],o=null!==(e=t.numItems)&&void 0!==e?e:1;if(n&&n.length){if(void 0===t.msgidPlural)return n[0];{let e=t.catalog.pluralFunction(o);if(e>=n.length){if(1===n.length)return n[0];e=s(o)}return n[e]}}if(void 0!==t.msgidPlural){if(1===t.catalog.pluralFunction(o))return t.msgidPlural}return t.msgid}m.cache={};const _="undefined"!=typeof process&&null!==process.versions&&null!==process.versions.node&&"win32"===process.platform?"\\":"/";function b(t,e){if(t.length!==e.length)return!1;for(let r=0;r<t.length;++r)if(t[r].toLowerCase()!==e[r].toLowerCase())return!1;return!0}class P{_(t){return x({msgid:t,catalog:this.catalog})}_n(t,e,r){return x({msgid:t,msgidPlural:e,numItems:r,catalog:this.catalog})}_p(t,e){return x({msgctxt:t,msgid:e,catalog:this.catalog})}_np(t,e,r,n){return x({msgctxt:t,msgid:e,msgidPlural:r,numItems:n,catalog:this.catalog})}_x(t,e){return P.expand(x({msgid:t,catalog:this.catalog}),e||{})}_nx(t,e,r,n){return P.expand(x({msgid:t,msgidPlural:e,numItems:r,catalog:this.catalog}),n||{})}_px(t,e,r){return P.expand(x({msgctxt:t,msgid:e,catalog:this.catalog}),r||{})}_npx(t,e,r,n,o){return P.expand(x({msgctxt:t,msgid:e,msgidPlural:r,numItems:n,catalog:this.catalog}),o||{})}static getCatalog(t,e){const r=m.lookup(t,e);return r&&Promise.resolve(r)!==r?r:{major:0,minor:0,pluralFunction:s,entries:{}}}_l(t,e){return x({msgid:e,catalog:P.getCatalog(t,this.textdomain())})}_ln(t,e,r,n){return x({msgid:e,msgidPlural:r,numItems:n,catalog:P.getCatalog(t,this.textdomain())})}_lp(t,e,r){return x({msgctxt:e,msgid:r,catalog:P.getCatalog(t,this.textdomain())})}_lnp(t,e,r,n,o){return x({msgctxt:e,msgid:r,msgidPlural:n,numItems:o,catalog:P.getCatalog(t,this.textdomain())})}_lx(t,e,r){const n=P.getCatalog(t,this.textdomain());return P.expand(x({msgid:e,catalog:n}),r||{})}_lnx(t,e,r,n,o){const a=P.getCatalog(t,this.textdomain());return P.expand(x({msgid:e,msgidPlural:r,numItems:n,catalog:a}),o||{})}_lpx(t,e,r,n){const o=P.getCatalog(t,this.textdomain());return P.expand(x({msgctxt:e,msgid:r,catalog:o}),n||{})}_lnpx(t,e,r,n,o,a){const s=P.getCatalog(t,this.textdomain());return P.expand(x({msgctxt:e,msgid:r,msgidPlural:n,numItems:o,catalog:s}),a||{})}static expand(t,e){return t.replace(/\{([a-zA-Z][0-9a-zA-Z]*)\}/g,((t,r)=>Object.prototype.hasOwnProperty.call(e,r)?e[r]:`{${r}}`))}static getInstance(t){if(null==t||""===t)throw new Error("Cannot instantiate TextDomain without a textdomain");if(Object.prototype.hasOwnProperty.call(P.domains,t))return P.domains[t];{const e=new P(t);return P.domains[t]=e,e.catalog={major:0,minor:0,pluralFunction:s,entries:{}},e}}static clearInstances(){P.boundDomains={}}static forgetInstances(){P.clearInstances(),P.domains={}}static get locale(){return P._locale}static set locale(t){const e=t.toUpperCase();if("POSIX"===e||"C"===e)return void(this._locale="POSIX");const n=p(t);if(!n)throw new Error("invalid locale identifier");if(r())return void(this._locale=t);n.tags[0]=n.tags[0].toLowerCase(),n.tags.length>1&&(n.tags[1]=n.tags[1].toUpperCase());const o=n.underscoreSeparator?"_":"-";this._locale=n.tags.join(o),void 0!==n.charset&&(this._locale+="."+n.charset),void 0!==n.modifier&&(this._locale+="@"+n.modifier)}constructor(t){this._catalogFormat="mo.json",this.domain=t}textdomain(){return this.domain}bindtextdomain(t){return void 0!==t&&(P.boundDomains[this.domain]=t),P.boundDomains[this.domain]}async resolve(t){const e=[this.resolve1(t)];for(const r in P.domains)Object.prototype.hasOwnProperty.call(P.domains,r)&&P.domains[r]!==this&&e.push(P.domains[r].resolve1(t));return Promise.all(e).then((t=>new Promise((e=>e(t[0])))))}async resolve1(t){let e=this.bindtextdomain();if(null==e){e=(r()?["","assets","locale"]:[".","locale"]).join(_)}const n=t||P.locale;return y(this.domain,e,this.catalogFormat,n).then((e=>(t||(this.catalog=e),new Promise((t=>t(e))))))}get catalogFormat(){return this._catalogFormat}set catalogFormat(t){if("mo.json"===(t=t.toLowerCase()))this._catalogFormat="mo.json";else{if("mo"!==t)throw new Error(`unsupported format ${t}`);this._catalogFormat="mo"}}static userLocales(){return o()}static selectLocale(t,e){return function(t,e){let r="";for(let n=0;n<e.length;++n){const o=p(e[n]);if(o)for(let e=0;e<t.length;++e){const n=p(t[e]);if(n){if(b(o.tags,n.tags))return t[e];r.length||o.tags[0].toLowerCase()!==n.tags[0].toLowerCase()||(r=t[e])}}}return r.length?r:"C"}(t,null!=e?e:P.userLocales())}static N_(t){return t}N_(t){return t}N_x(t,e){return P.expand(t,null!=e?e:{})}static N_x(t,e){return P.expand(t,null!=e?e:{})}N_p(t,e){return e}static N_p(t,e){return e}N_px(t,e,r){return P.expand(e,null!=r?r:{})}static N_px(t,e,r){return P.expand(e,null!=r?r:{})}}P.domains={},P.cache=m.getInstance(),P.boundDomains={},P._locale="C",r(!0);const j=new Array;window.navigator.languages&&j.push(...window.navigator.languages),void 0!==window.navigator.language&&j.push(window.navigator.language);const O=window.navigator;Object.prototype.hasOwnProperty.call(O,"userLanguage")&&O.userLanguage&&j.push(O.userLanguage),Object.prototype.hasOwnProperty.call(O,"browserLanguage")&&O.browserLanguage&&j.push(O.browserLanguage),Object.prototype.hasOwnProperty.call(O,"systemLanguage")&&O.systemLanguage&&j.push(O.systemLanguage),o(j),t.CatalogCache=m,t.Textdomain=P,t.parseJsonCatalog=g,t.parseMoCatalog=c,t.parseMoJsonCatalog=u}));
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).esgettext={})}(this,(function(t){"use strict";let e=!1;function r(t){return void 0!==t&&(e=t),e}let n=["C"];function o(t){return void 0!==t&&(n=t),n}function a(t,e,r,n){return new(r||(r=Promise))((function(o,a){function s(t){try{c(n.next(t))}catch(t){a(t)}}function i(t){try{c(n.throw(t))}catch(t){a(t)}}function c(t){var e;t.done?o(t.value):(e=t.value,e instanceof r?e:new r((function(t){t(e)}))).then(s,i)}c((n=n.apply(t,e||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;class s{loadFile(t){return new Promise(((e,r)=>{const n=new XMLHttpRequest;n.responseType="arraybuffer",n.open("GET",t,!0),n.onload=()=>{4===n.readyState&&200===n.status?e(n.response):r(new Error("get failed with status "+n.status))},n.onerror=t=>r(t),n.send()}))}}function i(t){return 1===t?0:1}class c{constructor(t,e="utf-8"){this.array=t,this.decoder=new TextDecoder(e),this._encoding=e}get encoding(){return this._encoding}set encoding(t){this.decoder=new TextDecoder(t),this._encoding=t}readUInt32BE(t=0){if(t+4>this.array.byteLength+this.array.byteOffset)throw new Error("read past array end");return(this.array[t]<<24>>>0|this.array[t+1]<<16|this.array[t+2]<<8|this.array[t+3])>>>0}readUInt32LE(t=0){if(t+4>this.array.byteLength+this.array.byteOffset)throw new Error("read past array end");return(this.array[t+3]<<24>>>0|this.array[t+2]<<16|this.array[t+1]<<8|this.array[t])>>>0}readString(t=0,e){if(t+e>this.array.byteLength+this.array.byteOffset)throw new Error("read past array end");return void 0===e&&(e=this.array.byteLength-t),this.decoder.decode(this.array.slice(t,t+e))}}function l(t){const e={major:0,minor:0,entries:{},pluralFunction:i};let r=0;const n=new c(new Uint8Array(t),"ascii"),o=n.readUInt32LE(r);let a;if(2500072158===o)a=(t,e)=>t.readUInt32LE(e);else{if(3725722773!==o)throw new Error(`invalid MO magic 0x${o.toString(16)}`);a=(t,e)=>t.readUInt32BE(e)}r+=4;const s=a(n,r)>>16;if(r+=4,s>0)throw new Error(`unsupported major revision ${s}`);const l=a(n,r);r+=4;const u=a(n,r);r+=4;const g=a(n,r);r=u;const d=[];for(let t=0;t<l;++t){const t=a(n,r);r+=4;const e=a(n,r);r+=4,d.push([t,e])}r=g;const p=[];for(let t=0;t<l;++t){const t=a(n,r);r+=4;const e=a(n,r);r+=4,p.push([t,e])}const h={};for(let t=0;t<l;++t){const o=d[t];let a=o[0];r=o[1];const s=n.readString(r,a).split("\0")[0],i=p[t];a=i[0],r=i[1];const c=n.readString(r,a).split("\0");let l,u;if(0===t&&""===s){l=c[0].split("\n");for(let t=0;t<l.length;++t)""!==l[t]&&(u=l[t].split(/[ \t]*:[ \t]*/),h[u[0].toLowerCase()]=u[1]);if(void 0!==h["content-type"]){const t=h["content-type"].replace(/.*=/,"");t!==h["content-type"]&&(n.encoding=t)}}e.entries[s]=c}return e}function u(t){if(null==t)throw new Error("catalog is either null or undefined");const e=t;if(e.constructor!==Object)throw new Error("catalog must be a dictionary");if(!Object.prototype.hasOwnProperty.call(e,"entries"))throw new Error("catalog.entries does not exist");const r=e.entries;if(null==r)throw new Error("catalog.entries are not defined or null");if(r.constructor!==Object)throw new Error("catalog.entries must be a dictionary");for(const[t,e]of Object.entries(r))if(!Array.isArray(e))throw new Error(`catalog entry for key '${t}' is not an array`);return e}function g(t){const e=(new TextDecoder).decode(t);return u(JSON.parse(e))}function d(t){const e=(new TextDecoder).decode(t);return function(t){if(null==t)throw new Error("catalog is either null or undefined");const e=t;e.constructor;const r={major:0,minor:1,pluralFunction:()=>0,entries:{}};for(const[t,n]of Object.entries(e))r.entries[t]=[n.toString()];return r}(JSON.parse(e))}const p=new RegExp("^[a-z0-9]+(?:-[a-z0-9]+)*$","i"),h=new RegExp("^[a-z0-9]+(?:_[a-z0-9]+)*$","i");function f(t){let e="",r="";const n=t.includes("_");if(t=(t=t.replace(/@([a-z]+)$/i,((t,e)=>(r=e,"")))).replace(/\.([-0-9a-z]+)$/i,((t,r)=>(e=r,""))),n){if(!h.exec(t))return null}else if(!p.exec(t))return null;const o=n?"_":"-",a={tags:t.split(o),underscoreSeparator:n};return e.length&&(a.charset=e),r.length&&(a.modifier=r),a}class m{constructor(){}static getInstance(){return m.instance||(m.instance=new m),m.instance}static clear(){m.cache={}}static lookup(t,e){if(m.cache[t]){const r=m.cache[t];if(Object.prototype.hasOwnProperty.call(r,e))return r[e]}return null}static store(t,e,r){Promise.resolve(r)!==r&&(r=u(r)),m.cache[t]||(m.cache[t]={}),m.cache[t][e]=r}}function w(t,e){return a(this,void 0,void 0,(function*(){let r,n;r=new s,n="mo.json"===e?g:".json"===e?d:l;try{return n(yield r.loadFile(t))}catch(t){return null}}))}function y(t,e,r,n){return`${t}/${e}/LC_MESSAGES/${r}.${n}`}function x(t,e,r,n){return a(this,void 0,void 0,(function*(){if("object"==typeof e&&null!==e)return function(t,e,r){return a(this,void 0,void 0,(function*(){for(let n=0;n<t.length;++n){const o=t[n];if(Object.prototype.hasOwnProperty.call(e,o)&&Object.prototype.hasOwnProperty.call(e[o],"LC_MESSAGES")&&Object.prototype.hasOwnProperty.call(e[o].LC_MESSAGES,r))return e[o].LC_MESSAGES[r]}return null}))}(t,e,r);for(const o of t){const t=yield w(y(e,o,r,n),n);if(t)return t}return null}))}function v(t){if(!Object.prototype.hasOwnProperty.call(t.entries,""))return t;return t.entries[""][0].split("\n").forEach((e=>{const r=e.split(":");if("plural-forms"===r.shift().toLowerCase()){const e=r.join(":");try{t.pluralFunction=function(t){const e=t.replace(/[ \t\r\013\014]/g,"").replace(/;$/,"").split(/[<>!=]=|&&|\|\||[-!*/%+<>=?:;]/);for(let t=0;t<e.length;++t){const r=e[t].replace(/^\(+/,"").replace(/\)+$/,"");if("nplurals"!==r&&"plural"!==r&&"n"!==r&&null===/^[0-9]+$/.exec(r))throw new Error("invalid plural function")}return new Function("n","var nplurals = 1, plural = 0;"+t+"; return 0 + plural")}(e)}catch(e){t.pluralFunction=i}}})),t}function _(t,e,r,n){return a(this,void 0,void 0,(function*(){if("C"===n||"POSIX"===n)return{major:0,minor:0,pluralFunction:i,entries:{}};const o=function(t,e){const r=[],n=t.underscoreSeparator?"_":"-";let o=0;const a=void 0!==t.charset,s=void 0!==t.modifier,i=a?[t.charset]:[""];if(a){const e=t.charset,r=e.toUpperCase();r!==e&&i.push(r),i.push("")}for(;o<t.tags.length;++o){const e=t.tags.slice(0,o+1).join(n),a=new Array;i.forEach((r=>{let n=r.length?e+"."+r:e;s&&(n+="@"+t.modifier),a.push(n)})),r.push(a)}return r}(f(n)),s=yield function(t,e,r,n,o){return a(this,void 0,void 0,(function*(){const a={major:0,minor:0,pluralFunction:i,entries:{}},s=yield m.lookup(e,n);if(null!==s)return s;for(const e of t){const t=yield x(e,r,n,o);t&&(a.major=t.major,a.minor=t.minor,a.entries=Object.assign(Object.assign({},a.entries),t.entries))}return a}))}(o,n,e,t,r);return v(s),m.store(n,t,s),s}))}function b(t){var e;const r=void 0===t.msgctxt?t.msgid:t.msgctxt+""+t.msgid,n=t.catalog.entries[r],o=null!==(e=t.numItems)&&void 0!==e?e:1;if(n&&n.length){if(void 0===t.msgidPlural)return n[0];{let e=t.catalog.pluralFunction(o);if(e>=n.length){if(1===n.length)return n[0];e=i(o)}return n[e]}}if(void 0!==t.msgidPlural){if(1===t.catalog.pluralFunction(o))return t.msgidPlural}return t.msgid}m.cache={};const O="undefined"!=typeof process&&null!==process.versions&&null!==process.versions.node&&"win32"===process.platform?"\\":"/";function j(t,e){if(t.length!==e.length)return!1;for(let r=0;r<t.length;++r)if(t[r].toLowerCase()!==e[r].toLowerCase())return!1;return!0}class E{_(t){return b({msgid:t,catalog:this.catalog})}_n(t,e,r){return b({msgid:t,msgidPlural:e,numItems:r,catalog:this.catalog})}_p(t,e){return b({msgctxt:t,msgid:e,catalog:this.catalog})}_np(t,e,r,n){return b({msgctxt:t,msgid:e,msgidPlural:r,numItems:n,catalog:this.catalog})}_x(t,e){return E.expand(b({msgid:t,catalog:this.catalog}),e||{})}_nx(t,e,r,n){return E.expand(b({msgid:t,msgidPlural:e,numItems:r,catalog:this.catalog}),n||{})}_px(t,e,r){return E.expand(b({msgctxt:t,msgid:e,catalog:this.catalog}),r||{})}_npx(t,e,r,n,o){return E.expand(b({msgctxt:t,msgid:e,msgidPlural:r,numItems:n,catalog:this.catalog}),o||{})}static getCatalog(t,e){const r=m.lookup(t,e);return r&&Promise.resolve(r)!==r?r:{major:0,minor:0,pluralFunction:i,entries:{}}}_l(t,e){return b({msgid:e,catalog:E.getCatalog(t,this.textdomain())})}_ln(t,e,r,n){return b({msgid:e,msgidPlural:r,numItems:n,catalog:E.getCatalog(t,this.textdomain())})}_lp(t,e,r){return b({msgctxt:e,msgid:r,catalog:E.getCatalog(t,this.textdomain())})}_lnp(t,e,r,n,o){return b({msgctxt:e,msgid:r,msgidPlural:n,numItems:o,catalog:E.getCatalog(t,this.textdomain())})}_lx(t,e,r){const n=E.getCatalog(t,this.textdomain());return E.expand(b({msgid:e,catalog:n}),r||{})}_lnx(t,e,r,n,o){const a=E.getCatalog(t,this.textdomain());return E.expand(b({msgid:e,msgidPlural:r,numItems:n,catalog:a}),o||{})}_lpx(t,e,r,n){const o=E.getCatalog(t,this.textdomain());return E.expand(b({msgctxt:e,msgid:r,catalog:o}),n||{})}_lnpx(t,e,r,n,o,a){const s=E.getCatalog(t,this.textdomain());return E.expand(b({msgctxt:e,msgid:r,msgidPlural:n,numItems:o,catalog:s}),a||{})}static expand(t,e){return t.replace(/\{([a-zA-Z][0-9a-zA-Z]*)\}/g,((t,r)=>Object.prototype.hasOwnProperty.call(e,r)?e[r]:`{${r}}`))}static getInstance(t){if(null==t||""===t)throw new Error("Cannot instantiate TextDomain without a textdomain");if(Object.prototype.hasOwnProperty.call(E.domains,t))return E.domains[t];{const e=new E(t);return E.domains[t]=e,e.catalog={major:0,minor:0,pluralFunction:i,entries:{}},e}}static clearInstances(){E.boundDomains={}}static forgetInstances(){E.clearInstances(),E.domains={}}static get locale(){return E._locale}static set locale(t){const e=t.toUpperCase();if("POSIX"===e||"C"===e)return void(this._locale="POSIX");const n=f(t);if(!n)throw new Error("invalid locale identifier");if(r())return void(this._locale=t);n.tags[0]=n.tags[0].toLowerCase(),n.tags.length>1&&(n.tags[1]=n.tags[1].toUpperCase());const o=n.underscoreSeparator?"_":"-";this._locale=n.tags.join(o),void 0!==n.charset&&(this._locale+="."+n.charset),void 0!==n.modifier&&(this._locale+="@"+n.modifier)}constructor(t){this._catalogFormat="mo.json",this.catalog=void 0,this.domain=t;const e="The property 'locale' is not an instance property but static. Use 'Textdomain.locale' instead!";Object.defineProperty(this,"locale",{get:()=>{throw new Error(e)},set:()=>{throw new Error(e)},enumerable:!0,configurable:!0})}textdomain(){return this.domain}bindtextdomain(t){return void 0!==t&&(E.boundDomains[this.domain]=t),E.boundDomains[this.domain]}resolve(t){return a(this,void 0,void 0,(function*(){const e=[this.resolve1(t)];for(const r in E.domains)Object.prototype.hasOwnProperty.call(E.domains,r)&&E.domains[r]!==this&&e.push(E.domains[r].resolve1(t));return Promise.all(e).then((t=>new Promise((e=>e(t[0])))))}))}resolve1(t){return a(this,void 0,void 0,(function*(){let e=this.bindtextdomain();if(null==e){e=(r()?["","assets","locale"]:[".","locale"]).join(O)}const n=t||E.locale;return _(this.domain,e,this.catalogFormat,n).then((e=>(t||(this.catalog=e),new Promise((t=>t(e))))))}))}get catalogFormat(){return this._catalogFormat}set catalogFormat(t){if("mo.json"===(t=t.toLowerCase()))this._catalogFormat="mo.json";else{if("mo"!==t)throw new Error(`unsupported format ${t}`);this._catalogFormat="mo"}}static userLocales(){return o()}static selectLocale(t,e){return function(t,e){let r="";for(let n=0;n<e.length;++n){const o=f(e[n]);if(o)for(let e=0;e<t.length;++e){const n=f(t[e]);if(n){if(j(o.tags,n.tags))return t[e];r.length||o.tags[0].toLowerCase()!==n.tags[0].toLowerCase()||(r=t[e])}}}return r.length?r:"C"}(t,null!=e?e:E.userLocales())}static N_(t){return t}N_(t){return t}N_x(t,e){return E.expand(t,null!=e?e:{})}static N_x(t,e){return E.expand(t,null!=e?e:{})}N_p(t,e){return e}static N_p(t,e){return e}N_px(t,e,r){return E.expand(e,null!=r?r:{})}static N_px(t,e,r){return E.expand(e,null!=r?r:{})}}E.domains={},E.boundDomains={},E._locale="C",r(!0);const C=new Array;window.navigator.languages&&C.push(...window.navigator.languages),void 0!==window.navigator.language&&C.push(window.navigator.language);const P=window.navigator;Object.prototype.hasOwnProperty.call(P,"userLanguage")&&P.userLanguage&&C.push(P.userLanguage),Object.prototype.hasOwnProperty.call(P,"browserLanguage")&&P.browserLanguage&&C.push(P.browserLanguage),Object.prototype.hasOwnProperty.call(P,"systemLanguage")&&P.systemLanguage&&C.push(P.systemLanguage),o(C),t.CatalogCache=m,t.Textdomain=E,t.parseJsonCatalog=d,t.parseMoCatalog=l,t.parseMoJsonCatalog=g}));
//# sourceMappingURL=esgettext.min.js.map

@@ -1,2 +0,2 @@

This software is Copyright (C) 2020 by Guido Flohr.
This software is Copyright (C) 2020-2024 by Guido Flohr.

@@ -3,0 +3,0 @@ This is free software, licensed under:

{
"name": "@esgettext/runtime",
"version": "1.1.0",
"type": "module",
"version": "1.2.0",
"description": "A gettext-like translation runtime for JavaScript aka EcmaScript",

@@ -73,2 +72,3 @@ "main": "dist/esgettext.cjs.js",

"@rollup/plugin-typescript": "^11.1.6",
"@tsconfig/recommended": "^1.0.6",
"eslint": "^8.56.0",

@@ -88,3 +88,3 @@ "jest": "^29.7.0",

},
"gitHead": "ecd3f8bfeb399c69e5e4bf13aa20f6129f3ad847"
"gitHead": "b3027a2934ec19444374e984673099f26cfccff7"
}
+17
-19

@@ -9,18 +9,18 @@ # @esgettext/runtime <!-- omit in toc -->

- [Internationalizing Hello World](#internationalizing-hello-world)
- [Choosing a Textdomain](#choosing-a-textdomain)
- [Install the Library](#install-the-library)
- [Import the Library](#import-the-library)
- [Prepare Your Sources](#prepare-your-sources)
- [Translation Methods](#translation-methods)
- [Simple Translations With `_()`](#simple-translations-with-_)
- [Variable Interpolation With `_x()`](#variable-interpolation-with-_x)
- [Plural Forms With `_nx()`](#plural-forms-with-_nx)
- [Message Context With `_p()`](#message-context-with-_p)
- [Specific Locale with `_l`](#specific-locale-with-_l)
- [TODO: Gender-Specific Translations](#todo-gender-specific-translations)
- [Selecting the Preferred Language with `selectLocale()`](#selecting-the-preferred-language-with-selectlocale)
- [Choosing a Textdomain](#choosing-a-textdomain)
- [Install the Library](#install-the-library)
- [Import the Library](#import-the-library)
- [Prepare Your Sources](#prepare-your-sources)
- [Translation Methods](#translation-methods)
- [Simple Translations With `_()`](#simple-translations-with-_)
- [Variable Interpolation With `_x()`](#variable-interpolation-with-_x)
- [Plural Forms With `_nx()`](#plural-forms-with-_nx)
- [Message Context With `_p()`](#message-context-with-_p)
- [Specific Locale with `_l`](#specific-locale-with-_l)
- [TODO: Gender-Specific Translations](#todo-gender-specific-translations)
- [Selecting the Preferred Language with `selectLocale()`](#selecting-the-preferred-language-with-selectlocale)
- [Internationalizing a Library](#internationalizing-a-library)
- [Frequently-Asked Questions](#frequently-asked-questions)
- [Why do Template Strings not Work?](#why-do-template-strings-not-work)
- [What Does the Error "template literals with embedded expressions are not allowed as arguments to gettext functions because they are not constant" Mean?](#what-does-the-error-template-literals-with-embedded-expressions-are-not-allowed-as-arguments-to-gettext-functions-because-they-are-not-constant-mean)
- [Why do Template Strings not Work?](#why-do-template-strings-not-work)
- [What Does the Error "template literals with embedded expressions are not allowed as arguments to gettext functions because they are not constant" Mean?](#what-does-the-error-template-literals-with-embedded-expressions-are-not-allowed-as-arguments-to-gettext-functions-because-they-are-not-constant-mean)
- [Copyright](#copyright)

@@ -86,3 +86,3 @@

If you have the `import` keyword:
If you have the `import` keyword (TypeScript or ES module syntax):

@@ -96,7 +96,5 @@ ```javascript

```javascript
const esgettext = require('@esgettext/runtime');
const Textdomain = esgettext.Textdomain;
const { Textdomain } = require('@esgettext/runtime');
```
_FIXME! Is this correct?_

@@ -410,3 +408,3 @@ If you are writing javascript loaded by a browser:

Copyright (C) 2020 Guido Flohr <guido.flohr@cantanea.com>, all
Copyright (C) 2020-2024 Guido Flohr <guido.flohr@cantanea.com>, all
rights reserved.

@@ -413,0 +411,0 @@

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display