// Use strict "use strict"; // Classes // Language class class Language { // Public // Initialize static initialize() { // Check if language hasn't already been initialized and available languages exist if(typeof Language.currentLanguage === "undefined" && typeof AVAILABLE_LANGUAGES !== "undefined") { // Get language display var languageDisplay = $("div.language"); // Get body display var bodyDisplay = $("body"); // Get language display button var languageDisplayButton = languageDisplay.children().children("button"); // Get language display list var languageDisplayList = languageDisplay.children().children("div"); // Get language display select var languageDisplaySelect = languageDisplay.children().children("select"); // Update language display select's size languageDisplaySelect.width(languageDisplayButton.width()); languageDisplaySelect.height(languageDisplayButton.height()); // Check if language is saved in local storage and it is valid var savedLanguage = localStorage.getItem(Language.LOCAL_STORAGE_NAME); if(savedLanguage !== Common.INVALID_LOCAL_STORAGE_ITEM && savedLanguage in AVAILABLE_LANGUAGES === true) { // Set current language to saved language Language.currentLanguage = savedLanguage; // Check if HTML language isn't the saved language if(savedLanguage !== $("html").attr("lang")) { // Change language to saved language Language.changeLanguage(savedLanguage); // Go through all language display list buttons languageDisplayList.children("button").each(function() { // Get button var button = $(this); // Check if button is the saved language if(button.attr(Common.DATA_ATTRIBUTE_PREFIX + "language") === savedLanguage) // Disable button button.disable(); // Otherwise else // Enable button button.enable(); }); // Update language display select value languageDisplaySelect.val(savedLanguage); // Update language display select options languageDisplaySelect.children("option").enable().filter(":selected").disable(); } // Otherwise else { // Change language to current language Language.changeLanguage(Language.currentLanguage, false); } } // Otherwise check if is an extension else if(Common.isExtension() === true && (typeof browser !== "undefined" || typeof chrome !== "undefined")) { // Get extension locale code var extensionLocaleCode = (typeof browser !== "undefined") ? browser["i18n"].getUILanguage() : chrome["i18n"].getUILanguage(); // Set language found to false var languageFound = false; // Go through all available laguages for(var availableLanguage in AVAILABLE_LANGUAGES) { if(AVAILABLE_LANGUAGES.hasOwnProperty(availableLanguage) === true) { // Check if available language's extension locale code matches the extension's if("Constants" in AVAILABLE_LANGUAGES[availableLanguage] === true && "Extension Locale Code" in AVAILABLE_LANGUAGES[availableLanguage]["Constants"] === true && AVAILABLE_LANGUAGES[availableLanguage]["Constants"]["Extension Locale Code"] === extensionLocaleCode) { // Set extension language var extensionLanguage = availableLanguage; // Set language found to true languageFound = true; // Break break; } } } // Check if language was found if(languageFound === true) { // Set current language to extension language Language.currentLanguage = extensionLanguage; // Check if HTML language isn't the extension language if(extensionLanguage !== $("html").attr("lang")) { // Change language to extension language Language.changeLanguage(extensionLanguage); // Go through all language display list buttons languageDisplayList.children("button").each(function() { // Get button var button = $(this); // Check if button is the extension language if(button.attr(Common.DATA_ATTRIBUTE_PREFIX + "language") === extensionLanguage) // Disable button button.disable(); // Otherwise else // Enable button button.enable(); }); // Update language display select value languageDisplaySelect.val(extensionLanguage); // Update language display select options languageDisplaySelect.children("option").enable().filter(":selected").disable(); } // Otherwise else { // Change language to current language Language.changeLanguage(Language.currentLanguage, false); } } // Otherwise else { // Get current language from HTML language Language.currentLanguage = $("html").attr("lang"); // Change language to current language Language.changeLanguage(Language.currentLanguage, false); } } // Otherwise else { // Get current language from HTML language Language.currentLanguage = $("html").attr("lang"); // Change language to current language Language.changeLanguage(Language.currentLanguage, false); } // Set cookie Language.setCookie(); // Set local storage Language.setLocalStorage(); // Language display button click event languageDisplayButton.on("click", function() { // Check if language display list is hidden if(languageDisplayList.hasClass("hide") === true) { // Reset language display list scroll position languageDisplayList.scrollTop(0); // Show language display list languageDisplayList.removeClass("hide").parent().addClass("shadow"); // Make language display button transition and set that it is clicked languageDisplayButton.addClass("transition clicked"); } // Otherwise else { // Hide language display list languageDisplayList.addClass("hide").parent().removeClass("shadow"); // Make language display button not transition and set that it isn't clicked languageDisplayButton.removeClass("transition clicked"); } // Language display button language change event }).on(Language.CHANGE_EVENT, function() { // Update language display select's size languageDisplaySelect.width(languageDisplayButton.width()); languageDisplaySelect.height(languageDisplayButton.height()); }); // Language display focus out event languageDisplay.on("focusout", function(event) { // Check if element with focus isn't part of the language display if(typeof event !== "object" || event === null || "originalEvent" in event === false || typeof event["originalEvent"] !== "object" || event["originalEvent"] === null || "relatedTarget" in event["originalEvent"] === false || languageDisplay.has(event["originalEvent"]["relatedTarget"])["length"] === 0) { // Check if language display list is shown and not blocking input if(languageDisplayList.hasClass("hide") === false && bodyDisplay.hasClass("blockInput") === false) { // Hide language display list languageDisplayList.addClass("hide").parent().removeClass("shadow"); // Set that language display button isn't clicked languageDisplayButton.removeClass("clicked").blur(); // Language display list transition end or timeout event languageDisplayList.transitionEndOrTimeout(function() { // Make language display button not transition languageDisplayButton.removeClass("transition"); }, "opacity"); } } }); // Language display list mouse down event languageDisplayList.on("mousedown", function(event) { // Prevent causing focus out event event.preventDefault(); // Trigger focus change event languageDisplayList.trigger(Common.FOCUS_CHANGE_EVENT); }); // Language display list button click and touch end event languageDisplayList.children("button").on("click touchend", function(event) { // Check if event is touch end if("type" in event["originalEvent"] === true && event["originalEvent"]["type"] === "touchend") { // Check if address copy isn't under the touch area var changedTouch = event["originalEvent"]["changedTouches"][0]; if(this !== document.elementFromPoint(changedTouch["clientX"], changedTouch["clientY"])) { // Return return; } } // Get button var button = $(this); // Check if button isn't disabled if(button.is(":disabled") === false) { // Block input bodyDisplay.addClass("blockInput"); // Set that button is clicked button.addClass("clicked"); // Set timeout setTimeout(function() { // Get new language var newLanguage = button.attr(Common.DATA_ATTRIBUTE_PREFIX + "language"); // Log message Log.logMessage(Language.getDefaultTranslation('Language changed to %1$y.'), [ // Language AVAILABLE_LANGUAGES[newLanguage]["Constants"]["Language"] ]); // Change language Language.changeLanguage(newLanguage); // Update language display select value languageDisplaySelect.val(newLanguage); // Update language display select options languageDisplaySelect.children().enable().filter(":selected").disable(); // Request animation frame or timeout Common.requestAnimationFrameOrTimeout(function() { // Unblock input bodyDisplay.removeClass("blockInput"); // Trigger langauge display focus out event languageDisplay.trigger("focusout"); // Language display list transition end or timeout event languageDisplayList.transitionEndOrTimeout(function() { // Disable button and enable its siblings button.disable().siblings().enable(); // Set that button isn't clicked button.removeClass("clicked"); }, "opacity"); }); }, ("type" in event["originalEvent"] === true && event["originalEvent"]["type"] === "touchend") ? 0 : Language.CHANGE_LANGUAGE_DELAY_MILLISECONDS); } }); // Language display select input event languageDisplaySelect.on("input", function() { // Get new language var newLanguage = languageDisplaySelect.val(); // Check if new language isn't the current language if(newLanguage !== Language.currentLanguage) { // Block input bodyDisplay.addClass("blockInput"); // Set timeout setTimeout(function() { // Log message Log.logMessage(Language.getDefaultTranslation('Language changed to %1$y.'), [ // Language AVAILABLE_LANGUAGES[newLanguage]["Constants"]["Language"] ]); // Change language Language.changeLanguage(newLanguage); // Go through all language display list buttons languageDisplayList.children("button").each(function() { // Get button var button = $(this); // Check if button is the new language if(button.attr(Common.DATA_ATTRIBUTE_PREFIX + "language") === newLanguage) // Disable button button.disable(); // Otherwise else // Enable button button.enable(); }); // Update language display select options languageDisplaySelect.children().enable().filter(":selected").disable(); // Request animation frame requestAnimationFrame(function() { // Unblock input bodyDisplay.removeClass("blockInput"); }); // Blur language display select languageDisplaySelect.blur(); }, 0); } }); // Document key down event $(document).on("keydown", function(event) { // Check if blocking input and key tab is pressed if(bodyDisplay.hasClass("blockInput") === true && event["which"] === "\t".charCodeAt(0)) // Prevent default event.preventDefault(); }); // Document mouse down, focus in, touch start, and focus change event $(document).on("mousedown focusin touchstart " + Common.FOCUS_CHANGE_EVENT, function(event) { // Check if language display list is shown and element with focus isn't part of the language display or the block input if(languageDisplayList.hasClass("hide") === false && languageDisplay.has(event["target"])["length"] === 0 && $(event["target"]).hasClass("blockInput") === false) { // Trigger langauge display focus out event languageDisplay.trigger("focusout"); } }); // Window blur event $(window).on("blur", function() { // Check if language display list is shown if(languageDisplayList.hasClass("hide") === false) // Trigger langauge display focus out event languageDisplay.trigger("focusout"); // Window storage event }).on("storage", function(event) { // Check if language was changed if(event["originalEvent"]["key"] === Language.LOCAL_STORAGE_NAME && event["originalEvent"]["oldValue"] !== event["originalEvent"]["newValue"]) { // Log message Log.logMessage(Language.getDefaultTranslation('Language changed to %1$y.'), [ // Language AVAILABLE_LANGUAGES[event["originalEvent"]["newValue"]]["Constants"]["Language"] ]); // Change language Language.changeLanguage(event["originalEvent"]["newValue"]); // Go through all language display list buttons languageDisplayList.children("button").each(function() { // Get button var button = $(this); // Check if button is the new language if(button.attr(Common.DATA_ATTRIBUTE_PREFIX + "language") === event["originalEvent"]["newValue"]) // Disable button button.disable(); // Otherwise else // Enable button button.enable(); }); // Update language display select value languageDisplaySelect.val(event["originalEvent"]["newValue"]); } // Windows resize event }).on("resize", function() { // Update language display select's size languageDisplaySelect.width(languageDisplayButton.width()); languageDisplaySelect.height(languageDisplayButton.height()); }); } } // Set get displayed currency static setGetDisplayedCurrency(getDisplayedCurrency) { // Set language get displayed currency Language.getDisplayedCurrency = getDisplayedCurrency; } // Set get price static setGetPrice(prices) { // Set language get price Language.getPrice = function(currency) { // Return currency's price return prices.getPrice(currency); }; // Prices change event $(prices).on(Prices.CHANGE_EVENT, function(event, prices) { // Check if translated currency display values exist var translatedCurrencyDisplayValues = $(".translatedCurrencyDisplayValue"); if(translatedCurrencyDisplayValues["length"] !== 0) { // Go through all translated currency display values translatedCurrencyDisplayValues.each(function() { // Translate the translatable container that the translated currency display value is in Language.translateElement($(this).closest(".translatable")); }); // Trigger resize event $(window).trigger("resize"); } }); } // Get translation static getTranslation(text, textArguments = [], encodeHtml = false) { // Set applicable language var applicableLanguage = Language.currentLanguage; // Check if text isn't a standalone placeholder if(Language.PLACEHOLDER_PATTERN.test(text) === false) { // Loop while a value isn't found while(true) { // Check if applicable language is available if(typeof AVAILABLE_LANGUAGES !== "undefined" && applicableLanguage in AVAILABLE_LANGUAGES === true) { // Check if text exist for the applicable language and the specified text exists if("Text" in AVAILABLE_LANGUAGES[applicableLanguage] === true && text in AVAILABLE_LANGUAGES[applicableLanguage]["Text"] === true) { // Set text to the text for the applicable language text = AVAILABLE_LANGUAGES[applicableLanguage]["Text"][text]; // Break break; } // Otherwise check if applicable language provides a fallback language else if(applicableLanguage !== DEFAULT_LANGUAGE && "Constants" in AVAILABLE_LANGUAGES[applicableLanguage] === true && "Fallback" in AVAILABLE_LANGUAGES[applicableLanguage]["Constants"] === true) // Set applicable language to the language's fallback language applicableLanguage = AVAILABLE_LANGUAGES[applicableLanguage]["Constants"]["Fallback"]; // Otherwise check if the applicable language is not the default language else if(applicableLanguage !== DEFAULT_LANGUAGE) // Set applicable language to default language applicableLanguage = DEFAULT_LANGUAGE; // Otherwise else // Break break; } // Otherwise check if the applicable language is not the default language else if(applicableLanguage !== DEFAULT_LANGUAGE) // Set applicable language to default language applicableLanguage = DEFAULT_LANGUAGE; // Otherwise else // Break break; } } // Initialize formatter locales var formatterLocales = [ applicableLanguage ]; // Loop while applicable language isn't the default language while(applicableLanguage !== DEFAULT_LANGUAGE) { // Check if applicable language provides a fallback language if(typeof AVAILABLE_LANGUAGES !== "undefined" && applicableLanguage in AVAILABLE_LANGUAGES === true && "Constants" in AVAILABLE_LANGUAGES[applicableLanguage] === true && "Fallback" in AVAILABLE_LANGUAGES[applicableLanguage]["Constants"] === true) // Set applicable language to the language's fallback language applicableLanguage = AVAILABLE_LANGUAGES[applicableLanguage]["Constants"]["Fallback"]; // Otherwise check if the applicable language is not the default language else if(applicableLanguage !== DEFAULT_LANGUAGE) // Set applicable language to default language applicableLanguage = DEFAULT_LANGUAGE; // Otherwise else // Break break; // Append applicable language to formatter locales list formatterLocales.push(applicableLanguage); } // Append default formatter locale to list formatterLocales.push(Language.DEFAULT_FORMATTER_LOCALE); // Initialize result var result = ""; // Go through all characters in the text var placeholderStart = Language.NO_PLACEHOLDER_START; for(var i = 0; i < text["length"]; ++i) { // Check if character is an escaped escape character if(placeholderStart !== Language.NO_PLACEHOLDER_START && i > 1 && text[i] === Language.ESCAPE_CHARACTER && text[i - 1] === Language.ESCAPE_CHARACTER) { // Clear placeholder start placeholderStart = Language.NO_PLACEHOLDER_START; // Append character to result and encode it if specified result += (encodeHtml === false) ? text[i] : Common.htmlEncode(text[i]); } // Otherwise check if character is an escape character else if(text[i] === Language.ESCAPE_CHARACTER) // Set placeholder start placeholderStart = i; // Otherwise check if placeholder start exists else if(placeholderStart !== Language.NO_PLACEHOLDER_START) { // Get place holder var placeholder = text.substring(placeholderStart, i + 1).match(Language.PLACEHOLDER_PATTERN); // Check if placeholder exists if(placeholder !== Common.NO_MATCH_FOUND) { // Clear placeholder start placeholderStart = Language.NO_PLACEHOLDER_START; // Check if the placeholder's argument index is valid var argumentIndex = parseInt(placeholder[Common.FIRST_MATCH_RESULT_INDEX], Common.DECIMAL_NUMBER_BASE) - 1; if(argumentIndex >= 0 && argumentIndex < textArguments["length"]) { // Check placeholder's type switch(placeholder[2]) { // Number case Language.NUMBER_PLACEHOLDER_TYPE: // Get number formatter var numberFormatter = new Intl.NumberFormat(formatterLocales, Language.NUMBER_FORMAT); // Check if argument contains a fractional part var fractionIndex = textArguments[argumentIndex].indexOf(Language.INTEGER_FRACTION_SEPARATOR); if(fractionIndex !== Common.INDEX_NOT_FOUND) { // Truncate fractional part after the maximum number of fraction digits textArguments[argumentIndex] = textArguments[argumentIndex].substring(0, fractionIndex + Language.INTEGER_FRACTION_SEPARATOR["length"] + numberFormatter.resolvedOptions()["maximumFractionDigits"]); } // Get argument formatted as a number var formattedArgumentNumber = numberFormatter.format(textArguments[argumentIndex]); // Append argument formatted as a number to result and encode it if specified result += (encodeHtml === false) ? formattedArgumentNumber : Common.htmlEncode(formattedArgumentNumber); // Break break; // Currency case Language.CURRENCY_PLACEHOLDER_TYPE: // Check if text argument is an array if(Array.isArray(textArguments[argumentIndex]) === true) { // Get text argument number, currency, and display value var textArgumentNumber = textArguments[argumentIndex][Language.CURRENCY_NUMBER_ARGUMENT_INDEX]; var textArgumentCurrency = textArguments[argumentIndex][Language.CURRENCY_CURRENCY_ARGUMENT_INDEX]; var textArgumentDisplayValue = (textArguments[argumentIndex]["length"] > Language.CURRENCY_DISPLAY_VALUE_ARGUMENT_INDEX) ? textArguments[argumentIndex][Language.CURRENCY_DISPLAY_VALUE_ARGUMENT_INDEX] : false; } // Otherwise else { // Get text argument number, use default currency, and don't display value var textArgumentNumber = textArguments[argumentIndex]; var textArgumentCurrency = Language.DEFAULT_CURRENCY; var textArgumentDisplayValue = false; } // Get text argument number as integer and fraction parts var argumentParts = textArgumentNumber.split(Language.INTEGER_FRACTION_SEPARATOR); // Check if text argument number has a fraction part if(argumentParts["length"] > 1) { // Get formatted argument currency integer parts using text argument currency var currencyIntegerFormatter = new Intl.NumberFormat(formatterLocales, Language.getCurrencyIntegerFormat(textArgumentCurrency)); var formattedArgumentCurrencyIntegerParts = currencyIntegerFormatter.formatToParts(argumentParts[0]); // Go through all formatted argument currency integer parts var integerStartingFractionIndex = Language.NO_FRACTION_INDEX; var integerEndingFractionIndex = Language.NO_FRACTION_INDEX; for(var j = 0; j < formattedArgumentCurrencyIntegerParts["length"]; ++j) { // Check if part is a fraction if(formattedArgumentCurrencyIntegerParts[j]["type"] === "fraction") { // Check if integer starting fraction index doesn't exist if(integerStartingFractionIndex === Language.NO_FRACTION_INDEX) // Set integer starting fraction index integerStartingFractionIndex = j; // Set integer ending fraction index integerEndingFractionIndex = j; } } // Get formatted argument currency fraction parts using text argument currency var currencyFractionFormatter = new Intl.NumberFormat(formatterLocales, Language.getCurrencyFractionFormat(textArgumentCurrency)); var formattedArgumentCurrencyFractionParts = currencyFractionFormatter.formatToParts(Language.INTEGER_FRACTION_SEPARATOR + argumentParts[1].substring(0, currencyFractionFormatter.resolvedOptions()["maximumFractionDigits"])); // Go through all formatted argument currency fraction parts var fractionStartingFractionIndex = Language.NO_FRACTION_INDEX; var fractionEndingFractionIndex = Language.NO_FRACTION_INDEX; for(var j = 0; j < formattedArgumentCurrencyFractionParts["length"]; ++j) { // Check if part is a fraction if(formattedArgumentCurrencyFractionParts[j]["type"] === "fraction") { // Check if fraction starting fraction index doesn't exist if(fractionStartingFractionIndex === Language.NO_FRACTION_INDEX) // Set fraction starting fraction index fractionStartingFractionIndex = j; // Set fraction ending fraction index fractionEndingFractionIndex = j; } } // Check if no fraction starting fraction index exists if(fractionStartingFractionIndex === Language.NO_FRACTION_INDEX) // Set formatted argument currency parts to the formatted argument integer without the fraction var formattedArgumentCurrencyParts = formattedArgumentCurrencyIntegerParts.slice(0, integerStartingFractionIndex - 1).concat(formattedArgumentCurrencyIntegerParts.slice(integerEndingFractionIndex + 1)); // Otherwise else // Set formatted argument currency parts to a combination of formatted argument integer and fraction parts to prevent large numbers from having their fraction parts truncated var formattedArgumentCurrencyParts = formattedArgumentCurrencyIntegerParts.slice(0, integerStartingFractionIndex).concat(formattedArgumentCurrencyFractionParts.slice(fractionStartingFractionIndex, fractionEndingFractionIndex + 1)).concat(formattedArgumentCurrencyIntegerParts.slice(integerEndingFractionIndex + 1)); } // Otherwise else { // Get formatted argument as currency using text argument currency var currencyFormatter = new Intl.NumberFormat(formatterLocales, Language.getCurrencyFormat(textArgumentCurrency)); // Set formatted argument currency parts var formattedArgumentCurrencyParts = currencyFormatter.formatToParts(textArgumentNumber); } // Get argument formatted as a currency var formattedArgumentCurrency = formattedArgumentCurrencyParts.map(function(part) { // Check part's type switch(part["type"]) { // Currency case "currency": // Check text argument currency switch(textArgumentCurrency) { // Currency name case Consensus.CURRENCY_NAME: // Check wallet type switch(Consensus.getWalletType()) { // MWC wallet case Consensus.MWC_WALLET_TYPE: // Return currency symbol and encode it if specified return (encodeHtml === false) ? Consensus.CURRENCY_NAME : ("" + Common.htmlEncode(Consensus.CURRENCY_NAME) + ""); // GRIN wallet case Consensus.GRIN_WALLET_TYPE: // Return currency symbol and encode it if specified return (encodeHtml === false) ? Consensus.CURRENCY_NAME : ("" + Common.htmlEncode(Consensus.CURRENCY_NAME) + ""); // EPIC wallet case Consensus.EPIC_WALLET_TYPE: // Return currency symbol and encode it if specified return (encodeHtml === false) ? Consensus.CURRENCY_NAME : ("" + Common.htmlEncode(Consensus.CURRENCY_NAME) + ""); } // Break break; // Bitcoin currency name case Prices.BITCOIN_CURRENCY_NAME: // Return Bitcoin currency symbol and encode it if specified return (encodeHtml === false) ? Prices.BITCOIN_CURRENCY_NAME : ("" + Common.htmlEncode(Prices.BITCOIN_CURRENCY_NAME) + ""); // Ethereum currency name case Prices.ETHEREUM_CURRENCY_NAME: // Return Ethereum currency symbol and encode it if specified return (encodeHtml === false) ? Prices.ETHEREUM_CURRENCY_NAME : ("" + Common.htmlEncode(Prices.ETHEREUM_CURRENCY_NAME) + ""); // Default default: // Return part's value and encode it if specified return (encodeHtml === false) ? part["value"] : Common.htmlEncode(part["value"]); } // Break break; // Default default: // Return part's value and encode it if specified return (encodeHtml === false) ? part["value"] : Common.htmlEncode(part["value"]); } }).reduce(function(parts, part) { // Combine parts return parts + part; }); // Append argument formatted as a currency to result result += formattedArgumentCurrency; // Check if displaying text argument value and text argument currency is the currency if(textArgumentDisplayValue === true && textArgumentCurrency === Consensus.CURRENCY_NAME) { // Check if language get displayed currency and get price exist if(typeof Language.getDisplayedCurrency !== "undefined" && typeof Language.getPrice !== "undefined") { // Get currency var currency = Language.getDisplayedCurrency(); // Get price in the currency var price = Language.getPrice(currency); // Check if price exists if(price !== Prices.NO_PRICE_FOUND) { // Get formatted argument display value var formattedArgumentDisplayValue = Language.getTranslation(Language.getDefaultTranslation(' (%1$c)'), [ [ // Amount (new BigNumber(textArgumentNumber)).multipliedBy(price).toFixed(), // Currency currency ] ], encodeHtml); // Append formatted argument display value to result and encode it if specified result += (encodeHtml === false) ? formattedArgumentDisplayValue : ("" + formattedArgumentDisplayValue + ""); } // Otherwise else { // Append hidden formatted argument display value to result and encode it if specified result += (encodeHtml === false) ? "" : (""); } } } // Break break; // Translated text case Language.TRANSLATED_TEXT_PLACEHOLDER_TYPE: // Get translated text argument var translatedTextArgumentText = Language.getTranslation(Language.escapeText(textArguments[argumentIndex])); // Append argument to result and encode it if specified result += (encodeHtml === false) ? translatedTextArgumentText : Common.htmlEncode(translatedTextArgumentText); // Break break; // Not translated text case Language.NOT_TRANSLATED_TEXT_PLACEHOLDER_TYPE: // Check if not translated text argument is an array if(Array.isArray(textArguments[argumentIndex]) === true) { // Get not translated text argument text and is raw data var notTranslatedTextArgumentText = textArguments[argumentIndex][Language.NOT_TRANSLATED_TEXT_TEXT_ARGUMENT_INDEX]; var notTranslatedTextArgumentIsRawData = textArguments[argumentIndex][Language.NOT_TRANSLATED_TEXT_IS_RAW_DATA_ARGUMENT_INDEX]; } // Otherwise else { // Get not translated text argument text and use default is raw data var notTranslatedTextArgumentText = textArguments[argumentIndex]; var notTranslatedTextArgumentIsRawData = false; } // Append argument to result and encode it if specified result += (encodeHtml === false) ? notTranslatedTextArgumentText : ((notTranslatedTextArgumentIsRawData === true) ? "" + Common.htmlEncode(notTranslatedTextArgumentText) + "" : Common.htmlEncode(notTranslatedTextArgumentText)); // Break break; // Time case Language.TIME_PLACEHOLDER_TYPE: // Get time argument var timeArgument = new Date(parseInt(textArguments[argumentIndex], Common.DECIMAL_NUMBER_BASE) * Common.MILLISECONDS_IN_A_SECOND); // Get argument formatted as time var timeFormatter = new Intl.DateTimeFormat(formatterLocales, Language.TIME_FORMAT); var formattedArgumentTime = timeFormatter.format(timeArgument); // Append argument formatted as time to result and encode it if specified result += (encodeHtml === false) ? formattedArgumentTime : ""; // Break break; // Date case Language.DATE_PLACEHOLDER_TYPE: // Get date argument var dateArgument = new Date(parseInt(textArguments[argumentIndex], Common.DECIMAL_NUMBER_BASE) * Common.MILLISECONDS_IN_A_SECOND); // Get argument formatted as a date var dateFormatter = new Intl.DateTimeFormat(formatterLocales, Language.DATE_FORMAT); var formattedArgumentDate = dateFormatter.format(dateArgument); // Append argument formatted as a date to result and encode it if specified result += (encodeHtml === false) ? formattedArgumentDate : ""; // Break break; // Timestamp case Language.TIMESTAMP_PLACEHOLDER_TYPE: // Get timestamp argument var timestampArgument = new Date(parseInt(textArguments[argumentIndex], Common.DECIMAL_NUMBER_BASE)); // Get argument formatted as a timestamp var dateFormatter = new Intl.DateTimeFormat(formatterLocales, Language.TIMESTAMP_FORMAT); var formattedArgumentDate = dateFormatter.format(timestampArgument); // Append argument formatted as a timestamp to result and encode it if specified result += (encodeHtml === false) ? formattedArgumentDate : ""; // Break break; // Translated link case Language.TRANSLATED_LINK_PLACEHOLDER_TYPE: // Get translated text argument text, URL, and is external var translatedTextArgumentText = Language.getTranslation(Language.escapeText(textArguments[argumentIndex][Language.LINK_TEXT_ARGUMENT_INDEX])); var translatedTextArgumentUrl = textArguments[argumentIndex][Language.LINK_URL_ARGUMENT_INDEX]; var translatedTextArgumentIsExternal = textArguments[argumentIndex][Language.LINK_IS_EXTERNAL_ARGUMENT_INDEX]; var translatedTextArgumentIsBlob = textArguments[argumentIndex][Language.LINK_IS_BLOB_ARGUMENT_INDEX]; // Check if loading from file and translated text argument URL is a relative path if(location["protocol"] === Common.FILE_PROTOCOL && translatedTextArgumentUrl.substring(0, "./"["length"]) === "./") { // Set translated text argument URL to be an absolute path translatedTextArgumentUrl = HTTPS_SERVER_ADDRESS + translatedTextArgumentUrl.substring("."["length"]); } // Append argument to result and encode it if specified result += (encodeHtml === false) ? translatedTextArgumentText : ("" + Common.htmlEncode(translatedTextArgumentText) + ""); // Break break; // Not translated link case Language.NOT_TRANSLATED_LINK_PLACEHOLDER_TYPE: // Get not translated text argument text, URL, and is external var notTranslatedTextArgumentText = textArguments[argumentIndex][Language.LINK_TEXT_ARGUMENT_INDEX]; var notTranslatedTextArgumentUrl = textArguments[argumentIndex][Language.LINK_URL_ARGUMENT_INDEX]; var notTranslatedTextArgumentIsExternal = textArguments[argumentIndex][Language.LINK_IS_EXTERNAL_ARGUMENT_INDEX]; var notTranslatedTextArgumentIsBlob = textArguments[argumentIndex][Language.LINK_IS_BLOB_ARGUMENT_INDEX]; // Check if loading from file and not translated text argument URL is a relative path if(location["protocol"] === Common.FILE_PROTOCOL && notTranslatedTextArgumentUrl.substring(0, "./"["length"]) === "./") { // Set not translated text argument URL to be an absolute path notTranslatedTextArgumentUrl = HTTPS_SERVER_ADDRESS + notTranslatedTextArgumentUrl.substring("."["length"]); } // Append argument to result and encode it if specified result += (encodeHtml === false) ? notTranslatedTextArgumentText : ("" + Common.htmlEncode(notTranslatedTextArgumentText) + ""); // Break break; // Version case Language.VERSION_PLACEHOLDER_TYPE: // Get argument formatted as a number var numberFormatter = new Intl.NumberFormat(formatterLocales, Language.NUMBER_FORMAT); // Get text argument number as version number parts var argumentParts = textArguments[argumentIndex].split(Language.VERSION_NUMBER_PART_SEPARATOR); // Go through all argument parts for(var j = 0; j < argumentParts["length"]; ++j) { // Get argument part as subparts var argumentPartSubparts = argumentParts[j].split(Language.VERSION_NUMBER_PART_SUBPART_SEPARATOR); // Go through all argument part subparts for(var k = 0; k < argumentPartSubparts["length"]; ++k) { // Check if argument part subpart is a numeric string if(Language.NUMERIC_STRING_PATTERN.test(argumentPartSubparts[k]) === true) { // Get argument part subpart formatted as a number argumentPartSubparts[k] = numberFormatter.format(argumentPartSubparts[k]); } } // Combine argument part subparts argumentParts[j] = argumentPartSubparts.join(Language.VERSION_NUMBER_PART_SUBPART_SEPARATOR); } // Combine argument parts var formattedArgumentNumber = argumentParts.join(Language.VERSION_NUMBER_PART_SEPARATOR); // Append argument formatted as a number to result and encode it if specified result += (encodeHtml === false) ? formattedArgumentNumber : Common.htmlEncode(formattedArgumentNumber); // Break break; } } // Otherwise else // Return empty string return ""; } } // Otherwise else // Append character to result and encode it if specified result += (encodeHtml === false) ? text[i] : Common.htmlEncode(text[i]); } // Check if last placeholder is invalid if(placeholderStart !== Language.NO_PLACEHOLDER_START) // Return empty string return ""; // Return result return result; } // Get constant static getConstant(constant, language = Language.NO_LANGUAGE) { // Set applicable language to the language if provided otherwise the current language var applicableLanguage = (language === Language.NO_LANGUAGE) ? Language.currentLanguage : language; // Loop while a value isn't found while(true) { // Check if applicable language is available if(typeof AVAILABLE_LANGUAGES !== "undefined" && applicableLanguage in AVAILABLE_LANGUAGES === true) { // Check if constants exist for the applicable language and the specified constant exists if("Constants" in AVAILABLE_LANGUAGES[applicableLanguage] === true && constant in AVAILABLE_LANGUAGES[applicableLanguage]["Constants"] === true) // Return the constant for the applicable language return AVAILABLE_LANGUAGES[applicableLanguage]["Constants"][constant]; // Otherwise check if applicable language provides a fallback language else if(applicableLanguage !== DEFAULT_LANGUAGE && "Constants" in AVAILABLE_LANGUAGES[applicableLanguage] === true && "Fallback" in AVAILABLE_LANGUAGES[applicableLanguage]["Constants"] === true) // Set applicable language to the language's fallback language applicableLanguage = AVAILABLE_LANGUAGES[applicableLanguage]["Constants"]["Fallback"]; // Otherwise check if the available language is not the default language else if(applicableLanguage !== DEFAULT_LANGUAGE) // Set applicable language to default language applicableLanguage = DEFAULT_LANGUAGE; // Otherwise else // Return empty string return ""; } // Otherwise check if the applicable language is not the default language else if(applicableLanguage !== DEFAULT_LANGUAGE) // Set applicable language to default language applicableLanguage = DEFAULT_LANGUAGE; // Otherwise else // Return empty string return ""; } } // Get default translation static getDefaultTranslation(text) { // Return text return text; } // Create translatable container static createTranslatableContainer(type, text, textArguments = [], classes = "", textIsTitle = false) { // Create container var container = $(type); // Make container translatable container.addClass("translatable"); container.attr(Common.DATA_ATTRIBUTE_PREFIX + "text", text); container.attr(Common.DATA_ATTRIBUTE_PREFIX + "arguments", JSON.stringify(textArguments)); // Check if type is meta if(type === "") // Set container's content to translation container.attr("content", Language.getTranslation(text, textArguments)); // Otherwise check if text is title else if(textIsTitle === true) // Set container's title to translation container.attr("title", Language.getTranslation(text, textArguments)); // Otherwise check if type is input else if(type === "") // Set container's placeholder to translation container.attr("placeholder", Language.getTranslation(text, textArguments)); // Otherwise else // Set container's HTML to translation container.html(Language.getTranslation(text, textArguments, true)); // Add provided classes to text container.addClass(classes); // Return container's outer HTML return container.outerHtml(); } // Show display static showDisplay(delayShow = false) { // Check if more than one language exists if(typeof AVAILABLE_LANGUAGES !== "undefined" && Object.keys(AVAILABLE_LANGUAGES)["length"] > 1) { // Check if delay show if(delayShow === true) // Set language display to transition at a slower speed $("div.language").removeClass("normalTransitionSpeed"); // Show language display $("div.language").removeClass("hide"); // Make room for language display $("main").addClass("languagesAvailable"); } } // Translate element static translateElement(element) { // Change language for element Language.changeLanguage(Language.currentLanguage, false, element); } // Change event static get CHANGE_EVENT() { // Return change event return "LanguageChangeEvent"; } // Before change event static get BEFORE_CHANGE_EVENT() { // Return before change event return "LanguageBeforeChangeEvent"; } // Currency constant static get CURRENCY_CONSTANT() { // Return currency constant return "Currency"; } // Currency number argument index static get CURRENCY_NUMBER_ARGUMENT_INDEX() { // Return currency number argument index return 0; } // Currency currency argument index static get CURRENCY_CURRENCY_ARGUMENT_INDEX() { // Return currency currency argument index return Language.CURRENCY_NUMBER_ARGUMENT_INDEX + 1; } // Currency display value argument index static get CURRENCY_DISPLAY_VALUE_ARGUMENT_INDEX() { // Return currency display value argument index return Language.CURRENCY_CURRENCY_ARGUMENT_INDEX + 1; } // Not translated text argument text index static get NOT_TRANSLATED_TEXT_TEXT_ARGUMENT_INDEX() { // Return not translated text argument text index return 0; } // Not translated text argument is raw data index static get NOT_TRANSLATED_TEXT_IS_RAW_DATA_ARGUMENT_INDEX() { // Return not translated text argument is raw data index return Language.NOT_TRANSLATED_TEXT_TEXT_ARGUMENT_INDEX + 1; } // Private // Change language static changeLanguage(newLanguage, languageIsDifferent = true, root = $("html")) { // Check if translating everything if(root.is("html") === true) { // Trigger language before change event $(document).trigger(Language.BEFORE_CHANGE_EVENT); // Set current language Language.currentLanguage = newLanguage; // Set cookie Language.setCookie(); // Set local storage Language.setLocalStorage(); // Check if language is different if(languageIsDifferent === true) { // Log message console.log("%c%s", "color: red; font-size: 30px; text-transform: uppercase;", Language.getTranslation('If someone asked you to copy/paste something here you are being scammed!!!')); } } // Go through all translatable elements root.find(".translatable").addBack(".translatable").each(function() { // Get element var element = $(this); // Check elements tag switch(element.prop("tagName")) { // HTML case "HTML": // Set element's language attribute element.attr("lang", Language.currentLanguage); // Set element's direction attribute element.attr("dir", Language.getConstant("Direction", Language.currentLanguage)); // Break break; // Link case "LINK": // Check if language is different if(languageIsDifferent === true) { // Check if element has an href var href = element.attr("href"); if(href !== Common.NO_ATTRIBUTE) { // Set element's href element.removeAttr("href"); // Set timeout setTimeout(function() { // Restore element's href element.attr("href", href); }, 0); } } // Break break; // Meta case "META": // Check if element has a data text attribute if(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "text") !== Common.NO_ATTRIBUTE) // Set element's content attribute element.attr("content", Language.getTranslation(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "text"), (element.attr(Common.DATA_ATTRIBUTE_PREFIX + "arguments") !== Common.NO_ATTRIBUTE) ? JSON.parse(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "arguments")) : [])); // Break break; // Input case "INPUT": // Check if element has a data text attribute if(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "text") !== Common.NO_ATTRIBUTE) { // Check if element is hidden if(element.attr("type") === "hidden") // Set element's value element.val(Language.getTranslation(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "text"), (element.attr(Common.DATA_ATTRIBUTE_PREFIX + "arguments") !== Common.NO_ATTRIBUTE) ? JSON.parse(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "arguments")) : [])); // Otherwise else // Set element's placeholder attribute element.attr("placeholder", Language.getTranslation(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "text"), (element.attr(Common.DATA_ATTRIBUTE_PREFIX + "arguments") !== Common.NO_ATTRIBUTE) ? JSON.parse(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "arguments")) : [])); } // Break break; // Default default: // Check if element has a data text attribute if(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "text") !== Common.NO_ATTRIBUTE) { // Check if element has a title attribute if(element.attr("title") !== Common.NO_ATTRIBUTE) // Set element's title attribute element.attr("title", Language.getTranslation(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "text"), (element.attr(Common.DATA_ATTRIBUTE_PREFIX + "arguments") !== Common.NO_ATTRIBUTE) ? JSON.parse(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "arguments")) : [])); // Otherwise check if element has its title currently saved else if(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "title") !== Common.NO_ATTRIBUTE) // Set element's saved title attribute element.attr(Common.DATA_ATTRIBUTE_PREFIX + "title", Language.getTranslation(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "text"), (element.attr(Common.DATA_ATTRIBUTE_PREFIX + "arguments") !== Common.NO_ATTRIBUTE) ? JSON.parse(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "arguments")) : [])); // Otherwise else // Set element's HTML element.html(Language.getTranslation(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "text"), (element.attr(Common.DATA_ATTRIBUTE_PREFIX + "arguments") !== Common.NO_ATTRIBUTE) ? JSON.parse(element.attr(Common.DATA_ATTRIBUTE_PREFIX + "arguments")) : [], true)); } // Break break; } // Check if tab is disabled for the element if(element.attr("tabindex") === Common.NO_TAB_INDEX) { // Disable tabbing to element's children element.find("*").disableTab(); } // Check if element is a title tag if(element.prop("tagName") === "TITLE") { // Try try { // Trigger language change event on the element element.get(0).dispatchEvent(new Event(Language.CHANGE_EVENT)); } // Catch errors catch(error) { // Trigger language change event on the element element.trigger(Language.CHANGE_EVENT); } } // Otherwise else { // Trigger language change event on the element element.trigger(Language.CHANGE_EVENT); } }); } // Set cookie static setCookie() { // Set language cookie as current language document["cookie"] = Language.COOKIE_NAME + "=" + Language.currentLanguage + "; max-age=" + Language.COOKIE_MAX_AGE.toFixed() + "; secure; samesite=lax; priority=high; path=/; partitioned"; } // Set local storage static setLocalStorage() { // Try try { // Save current language in local storage localStorage.setItem(Language.LOCAL_STORAGE_NAME, Language.currentLanguage); } // Catch errors catch(error) { // Check if fatal errors can be triggered if(typeof FatalError !== "undefined") // Trigger a fatal error new FatalError(FatalError.LOCAL_STORAGE_ERROR); } } // Get currency integer format static getCurrencyIntegerFormat(currency = Language.DEFAULT_CURRENCY) { // Check currency switch(currency) { // Currency name, Bitcoin currency name, Ethereum currency name case Consensus.CURRENCY_NAME: case Prices.BITCOIN_CURRENCY_NAME: case Prices.ETHEREUM_CURRENCY_NAME: // Return Bitcoin and Ethereum currency integer format return { // Style "style": "currency", // Currency "currency": Language.DEFAULT_CURRENCY, // Currency display "currencyDisplay": "symbol", // Notation "notation": "standard", // Minimum fraction digits "minimumFractionDigits": 1, // Maximum fraction digits "maximumFractionDigits": 1, // Use grouping "useGrouping": true }; // Default default: // Return default currency integer format return { // Style "style": "currency", // Currency "currency": currency, // Currency display "currencyDisplay": "symbol", // Notation "notation": "standard", // Minimum fraction digits "minimumFractionDigits": 1, // Maximum fraction digits "maximumFractionDigits": 1, // Use grouping "useGrouping": true }; } } // Get currency fraction format static getCurrencyFractionFormat(currency = Language.DEFAULT_CURRENCY) { // Check currency switch(currency) { // Currency name case Consensus.CURRENCY_NAME: // Return currency fraction format return { // Style "style": "currency", // Currency "currency": Language.DEFAULT_CURRENCY, // Currency display "currencyDisplay": "symbol", // Notation "notation": "standard", // Minimum fraction digits "minimumFractionDigits": 0, // Maximum fraction digits "maximumFractionDigits": Consensus.VALUE_NUMBER_BASE.toFixed()["length"] - 1, // Use grouping "useGrouping": true }; // Bitcoin currency name case Prices.BITCOIN_CURRENCY_NAME: // Return Bitcoin currency fraction format return { // Style "style": "currency", // Currency "currency": Language.DEFAULT_CURRENCY, // Currency display "currencyDisplay": "symbol", // Notation "notation": "standard", // Minimum fraction digits "minimumFractionDigits": 0, // Maximum fraction digits "maximumFractionDigits": Prices.BITCOIN_NUMBER_BASE.toFixed()["length"] - 1, // Use grouping "useGrouping": true }; // Ethereum currency name case Prices.ETHEREUM_CURRENCY_NAME: // Return Ethereum currency fraction format return { // Style "style": "currency", // Currency "currency": Language.DEFAULT_CURRENCY, // Currency display "currencyDisplay": "symbol", // Notation "notation": "standard", // Minimum fraction digits "minimumFractionDigits": 0, // Maximum fraction digits "maximumFractionDigits": Prices.ETHEREUM_NUMBER_BASE.toFixed()["length"] - 1, // Use grouping "useGrouping": true }; // Default default: // Return default currency fraction format return { // Style "style": "currency", // Currency "currency": currency, // Currency display "currencyDisplay": "symbol", // Notation "notation": "standard", // Use grouping "useGrouping": true }; } } // Get currency format static getCurrencyFormat(currency = Language.DEFAULT_CURRENCY) { // Return currency format return Language.getCurrencyFractionFormat(currency); } // Escape text static escapeText(text) { // Return text with all escape characters escaped return text.replace(Language.ESCAPE_CHARACTER_PATTERN, Language.ESCAPE_CHARACTER + Language.ESCAPE_CHARACTER); } // Escape character static get ESCAPE_CHARACTER() { // Return escape character return "%"; } // Escape character pattern static get ESCAPE_CHARACTER_PATTERN() { // Return escape character pattern return /%/gu; } // Cookie name static get COOKIE_NAME() { // Return cookie name return "__Host-Language"; } // Cookie max age static get COOKIE_MAX_AGE() { // Return cookie max age return 5 * Common.WEEKS_IN_A_YEAR * Common.DAYS_IN_A_WEEK * Common.HOURS_IN_A_DAY * Common.MINUTES_IN_AN_HOUR * Common.SECONDS_IN_A_MINUTE; } // Local storage name static get LOCAL_STORAGE_NAME() { // Return local storage name return "Language"; } // No placeholder start static get NO_PLACEHOLDER_START() { // Return no placeholder start return null; } // Number placeholder type static get NUMBER_PLACEHOLDER_TYPE() { // Return number placeholder type return "s"; } // Currency placeholder type static get CURRENCY_PLACEHOLDER_TYPE() { // Return currency placeholder type return "c"; } // Translated text placeholder type static get TRANSLATED_TEXT_PLACEHOLDER_TYPE() { // Return translated text placeholder type return "x"; } // Not translated text placeholder type static get NOT_TRANSLATED_TEXT_PLACEHOLDER_TYPE() { // Return not translated text placeholder type return "y"; } // Time placeholder type static get TIME_PLACEHOLDER_TYPE() { // Return time placeholder type return "t"; } // Date placeholder type static get DATE_PLACEHOLDER_TYPE() { // Return date placeholder type return "d"; } // Timestamp placeholder type static get TIMESTAMP_PLACEHOLDER_TYPE() { // Return timestamp placeholder type return "u"; } // Translated link placeholder type static get TRANSLATED_LINK_PLACEHOLDER_TYPE() { // Return translated link placeholder type return "l"; } // Not translated link placeholder type static get NOT_TRANSLATED_LINK_PLACEHOLDER_TYPE() { // Return not translated link placeholder type return "m"; } // Version placeholder type static get VERSION_PLACEHOLDER_TYPE() { // Return version placeholder type return "v"; } // Placeholder pattern static get PLACEHOLDER_PATTERN() { // Return placeholder pattern return new RegExp("^" + Common.escapeRegularExpression(Language.ESCAPE_CHARACTER) + "([1-9]\\d*)\\$([" + Common.escapeRegularExpression(Language.NUMBER_PLACEHOLDER_TYPE + Language.CURRENCY_PLACEHOLDER_TYPE + Language.TRANSLATED_TEXT_PLACEHOLDER_TYPE + Language.NOT_TRANSLATED_TEXT_PLACEHOLDER_TYPE + Language.TIME_PLACEHOLDER_TYPE + Language.DATE_PLACEHOLDER_TYPE + Language.TIMESTAMP_PLACEHOLDER_TYPE + Language.TRANSLATED_LINK_PLACEHOLDER_TYPE + Language.NOT_TRANSLATED_LINK_PLACEHOLDER_TYPE + Language.VERSION_PLACEHOLDER_TYPE) + "])$", "u"); } // Default formatter locale static get DEFAULT_FORMATTER_LOCALE() { // Return default formatter locale return "default"; } // Number format static get NUMBER_FORMAT() { // Return number format return { // Style "style": "decimal", // Notation "notation": "standard", // Minimum fraction digits "minimumFractionDigits": 0, // Maximum fraction digits "maximumFractionDigits": Language.NUMBER_MAX_FRACTIONAL_DIGITS, // Use grouping "useGrouping": false }; } // Number max fractional digits static get NUMBER_MAX_FRACTIONAL_DIGITS() { // Return number max fractional digits return 9; } // Time format static get TIME_FORMAT() { // Return time format return { // Hour "hour": "numeric", // Minute "minute": "numeric" }; } // Date format static get DATE_FORMAT() { // Return date format return { // Year "year": "numeric", // Month "month": "long", // Day "day": "numeric" }; } // Timestamp format static get TIMESTAMP_FORMAT() { // Return timestamp format return { // Year "year": "numeric", // Month "month": "2-digit", // Day "day": "2-digit", // Hour "hour": "2-digit", // Minute "minute": "2-digit", // Second "second": "2-digit", // Fractional second digits "fractionalSecondDigits": "3" }; } // No fraction index static get NO_FRACTION_INDEX() { // Return no fraction index return null; } // Integer fraction separator static get INTEGER_FRACTION_SEPARATOR() { // Return integer fraction separator return "."; } // Version number part separator static get VERSION_NUMBER_PART_SEPARATOR() { // Return version number part separator return "."; } // Version number part subpart separator static get VERSION_NUMBER_PART_SUBPART_SEPARATOR() { // Return version number part subpart separator return "-"; } // No language static get NO_LANGUAGE() { // Return no language return null; } // Default currency static get DEFAULT_CURRENCY() { // Return default currency return Language.getConstant(Language.CURRENCY_CONSTANT, DEFAULT_LANGUAGE); } // Link text argument index static get LINK_TEXT_ARGUMENT_INDEX() { // Return link text argument index return 0; } // Link URL argument index static get LINK_URL_ARGUMENT_INDEX() { // Return link URL argument index return Language.LINK_TEXT_ARGUMENT_INDEX + 1; } // Link is external argument index static get LINK_IS_EXTERNAL_ARGUMENT_INDEX() { // Return link is external argument index return Language.LINK_URL_ARGUMENT_INDEX + 1; } // Link is blob argument index static get LINK_IS_BLOB_ARGUMENT_INDEX() { // Return link is blob argument index return Language.LINK_IS_EXTERNAL_ARGUMENT_INDEX + 1; } // Change language delay milliseconds static get CHANGE_LANGUAGE_DELAY_MILLISECONDS() { // Return change language delay milliseconds return 100; } // Time hour length static get TIME_HOUR_LENGTH() { // Return time hour length return 2; } // Time minute length static get TIME_MINUTE_LENGTH() { // Return time minute length return 2; } // Time second length static get TIME_SECOND_LENGTH() { // Return time second length return 2; } // Time millisecond length static get TIME_MILLISECOND_LENGTH() { // Return time millisecond length return 3; } // Time component padding static get TIME_COMPONENT_PADDING() { // Return time component padding return "0"; } // Date month length static get DATE_MONTH_LENGTH() { // Return date month length return 2; } // Date day length static get DATE_DAY_LENGTH() { // Return date day length return 2; } // Date component padding static get DATE_COMPONENT_PADDING() { // Return date component padding return "0"; } // Numeric string pattern static get NUMERIC_STRING_PATTERN() { // Return numeric string pattern return /^(?:0|[1-9]\d*)$/u; } } // Main function // Set global object's language globalThis["Language"] = Language; // Initialize language Language.initialize();