UNPKG

senselogic-lingo

Version:

Text localization and processing.

1,129 lines (980 loc) 25.6 kB
// -- CONSTANTS const valueExpression = /^(.*?)([<=>]+)(.*)$/; // -- VARIABLES export let textBySlugMap = new Map(), languageSeparator = "\n¨", languageTag = "en", languageSubtag = "en", continentCode = "", countryCode = "", languageCode = "en", defaultLanguageCode = "en", substitutionPrefix = "{", substitutionSuffix = "}"; // -- FUNCTIONS export function setTextBySlug( text, textSlug ) { textBySlugMap.set( textSlug, text ); } // ~~ export function getTextBySlug( textSlug ) { if ( textBySlugMap.has( textSlug ) ) { return textBySlugMap.get( textSlug ); } else { console.warn( "Missing text slug : " + textSlug ); return ""; } } // ~~ export function getLanguageDecimalSeparator( languageCode ) { if ( languageCode === "en" || languageCode === "ja" || languageCode === "ko" || languageCode === "zh" ) { return "."; } else { return ","; } } // ~~ export function getContinentCodeFromCountryCode( countryCode ) { switch ( countryCode ) { case "AF" : return "AS"; case "AX" : return "EU"; case "AL" : return "EU"; case "DZ" : return "AF"; case "AS" : return "OC"; case "AD" : return "EU"; case "AO" : return "AF"; case "AI" : return "CA"; case "AQ" : return "AN"; case "AG" : return "CA"; case "AR" : return "SA"; case "AM" : return "EU"; case "AW" : return "CA"; case "AU" : return "OC"; case "AT" : return "EU"; case "AZ" : return "EU"; case "BS" : return "CA"; case "BH" : return "AS"; case "BD" : return "AS"; case "BB" : return "CA"; case "BY" : return "EU"; case "BE" : return "EU"; case "BZ" : return "CA"; case "BJ" : return "AF"; case "BM" : return "CA"; case "BT" : return "AS"; case "BO" : return "SA"; case "BA" : return "EU"; case "BW" : return "AF"; case "BR" : return "SA"; case "IO" : return "AF"; case "VG" : return "CA"; case "BN" : return "AS"; case "BG" : return "EU"; case "BF" : return "AF"; case "BI" : return "AF"; case "KH" : return "AS"; case "CM" : return "AF"; case "CA" : return "NA"; case "CV" : return "AF"; case "KY" : return "CA"; case "CF" : return "AF"; case "TD" : return "AF"; case "CL" : return "SA"; case "CN" : return "AS"; case "CX" : return "OC"; case "CC" : return "OC"; case "CO" : return "SA"; case "KM" : return "AF"; case "CK" : return "OC"; case "CR" : return "CA"; case "CI" : return "AF"; case "HR" : return "EU"; case "CU" : return "CA"; case "CW" : return "CA"; case "CY" : return "EU"; case "CZ" : return "EU"; case "CD" : return "AF"; case "DK" : return "EU"; case "DJ" : return "AF"; case "DM" : return "CA"; case "DO" : return "CA"; case "EC" : return "SA"; case "EG" : return "AF"; case "SV" : return "CA"; case "GQ" : return "AF"; case "ER" : return "AF"; case "EE" : return "EU"; case "ET" : return "AF"; case "FK" : return "SA"; case "FO" : return "EU"; case "FM" : return "OC"; case "FJ" : return "OC"; case "FI" : return "EU"; case "FR" : return "EU"; case "PF" : return "OC"; case "TF" : return "AN"; case "GA" : return "AF"; case "GE" : return "EU"; case "DE" : return "EU"; case "GH" : return "AF"; case "GI" : return "EU"; case "GR" : return "EU"; case "GL" : return "CA"; case "GD" : return "CA"; case "GU" : return "OC"; case "GT" : return "CA"; case "GG" : return "EU"; case "GN" : return "AF"; case "GW" : return "AF"; case "GY" : return "SA"; case "HT" : return "CA"; case "HM" : return "AN"; case "HN" : return "CA"; case "HK" : return "AS"; case "HU" : return "EU"; case "IS" : return "EU"; case "IN" : return "AS"; case "ID" : return "AS"; case "IR" : return "AS"; case "IQ" : return "AS"; case "IE" : return "EU"; case "IM" : return "EU"; case "IL" : return "AS"; case "IT" : return "EU"; case "JM" : return "CA"; case "JP" : return "AS"; case "JE" : return "EU"; case "JO" : return "AS"; case "KZ" : return "AS"; case "KE" : return "AF"; case "KI" : return "OC"; case "KO" : return "EU"; case "KW" : return "AS"; case "KG" : return "AS"; case "LA" : return "AS"; case "LV" : return "EU"; case "LB" : return "AS"; case "LS" : return "AF"; case "LR" : return "AF"; case "LY" : return "AF"; case "LI" : return "EU"; case "LT" : return "EU"; case "LU" : return "EU"; case "MO" : return "AS"; case "MK" : return "EU"; case "MG" : return "AF"; case "MW" : return "AF"; case "MY" : return "AS"; case "MV" : return "AS"; case "ML" : return "AF"; case "MT" : return "EU"; case "MH" : return "OC"; case "MR" : return "AF"; case "MU" : return "AF"; case "MX" : return "CA"; case "MD" : return "EU"; case "MC" : return "EU"; case "MN" : return "AS"; case "ME" : return "EU"; case "MS" : return "CA"; case "MA" : return "AF"; case "MZ" : return "AF"; case "MM" : return "AS"; case "NA" : return "AF"; case "NR" : return "OC"; case "NP" : return "AS"; case "NL" : return "EU"; case "NC" : return "OC"; case "NZ" : return "OC"; case "NI" : return "CA"; case "NE" : return "AF"; case "NG" : return "AF"; case "NU" : return "OC"; case "NF" : return "OC"; case "KP" : return "AS"; case "MP" : return "OC"; case "NO" : return "EU"; case "OM" : return "AS"; case "PK" : return "AS"; case "PW" : return "OC"; case "PS" : return "AS"; case "PA" : return "CA"; case "PG" : return "OC"; case "PY" : return "SA"; case "PE" : return "SA"; case "PH" : return "AS"; case "PN" : return "OC"; case "PL" : return "EU"; case "PT" : return "EU"; case "PR" : return "CA"; case "QA" : return "AS"; case "CG" : return "AF"; case "RO" : return "EU"; case "RU" : return "EU"; case "RW" : return "AF"; case "BL" : return "CA"; case "SH" : return "AF"; case "KN" : return "CA"; case "LC" : return "CA"; case "MF" : return "CA"; case "PM" : return "CA"; case "VC" : return "CA"; case "WS" : return "OC"; case "SM" : return "EU"; case "ST" : return "AF"; case "SA" : return "AS"; case "SN" : return "AF"; case "RS" : return "EU"; case "SC" : return "AF"; case "SL" : return "AF"; case "SG" : return "AS"; case "SX" : return "CA"; case "SK" : return "EU"; case "SI" : return "EU"; case "SB" : return "OC"; case "SO" : return "AF"; case "ZA" : return "AF"; case "GS" : return "AN"; case "KR" : return "AS"; case "SS" : return "AF"; case "ES" : return "EU"; case "LK" : return "AS"; case "SD" : return "AF"; case "SR" : return "SA"; case "SJ" : return "EU"; case "SZ" : return "AF"; case "SE" : return "EU"; case "CH" : return "EU"; case "SY" : return "AS"; case "TW" : return "AS"; case "TJ" : return "AS"; case "TZ" : return "AF"; case "TH" : return "AS"; case "GM" : return "AF"; case "TL" : return "AS"; case "TG" : return "AF"; case "TK" : return "OC"; case "TO" : return "OC"; case "TT" : return "CA"; case "TN" : return "AF"; case "TR" : return "EU"; case "TM" : return "AS"; case "TC" : return "CA"; case "TV" : return "OC"; case "UG" : return "AF"; case "UA" : return "EU"; case "AE" : return "AS"; case "GB" : return "EU"; case "US" : return "NA"; case "UY" : return "SA"; case "UM" : return "OC"; case "VI" : return "CA"; case "UZ" : return "AS"; case "VU" : return "OC"; case "VA" : return "EU"; case "VE" : return "SA"; case "VN" : return "AS"; case "WF" : return "OC"; case "EH" : return "AF"; case "YE" : return "AS"; case "ZM" : return "AF"; case "ZW" : return "AF"; } return ""; } // ~~ export function getContinentSlugFromContinentCode( continentCode ) { switch ( continentCode ) { case "AF" : return "africa"; case "AN" : return "antarctica"; case "AS" : return "asia"; case "OC" : return "oceania"; case "CA" : return "central-america"; case "EU" : return "europe"; case "NA" : return "north-america"; case "SA" : return "south-america"; } return ""; } // ~~ export function setLanguageSeparator( languageSeparator_ ) { languageSeparator = languageSeparator_; } // ~~ export function getLanguageSeparator( ) { return languageSeparator; } // ~~ export function setLanguageTag( languageTag_ ) { languageTag = languageTag_; } // ~~ export function getLanguageTag( ) { return languageTag; } // ~~ export function getLanguageSubtag( ) { if ( countryCode === "" ) { return languageCode; } else { return languageCode + "-" + countryCode; } } // ~~ export function updateLanguageTag( ) { languageTag = getTrimmedLanguageTag( languageCode + "-" + countryCode + "-" + continentCode ); } // ~~ export function setContinentCode( continentCode_ ) { continentCode = continentCode_; updateLanguageTag(); } // ~~ export function getContinentCode( ) { return continentCode; } // ~~ export function setCountryCode( countryCode_ ) { countryCode = countryCode_; setContinentCode( getContinentCodeFromCountryCode( countryCode_ ) ); } // ~~ export function getCountryCode( ) { return countryCode; } // ~~ export function setLanguageCode( languageCode_ ) { languageCode = languageCode_; updateLanguageTag(); } // ~~ export function getLanguageCode( ) { return languageCode; } // ~~ export function setDefaultLanguageCode( defaultLanguageCode_ ) { defaultLanguageCode = defaultLanguageCode_; } // ~~ export function getDefaultLanguageCode( ) { return defaultLanguageCode; } // ~~ export function setSubstitutionPrefix( substitutionPrefix_ ) { substitutionPrefix = substitutionPrefix_; } // ~~ export function getSubstitutionPrefix( ) { return substitutionPrefix; } // ~~ export function setSubstitutionSuffix( substitutionSuffix_ ) { substitutionSuffix = substitutionSuffix_; } // ~~ export function getSubstitutionSuffix( ) { return substitutionSuffix; } // ~~ export function getTranslatedNumber( number, { unit = "", currency = "", usesGrouping = false, minimumIntegerDigitCount = 1, minimumFractionalDigitCount = 0, maximumFractionalDigitCount = undefined } = {} ) { let numberFormat; if ( unit !== "" ) { numberFormat = new Intl.NumberFormat( getLanguageSubtag(), { style: "unit", unit: unit, minimumFractionDigits: minimumFractionalDigitCount, maximumFractionDigits: maximumFractionalDigitCount, useGrouping: usesGrouping } ); } else if ( currency !== "" ) { numberFormat = new Intl.NumberFormat( getLanguageSubtag(), { style: "currency", currency: currency, minimumFractionDigits: minimumFractionalDigitCount, maximumFractionDigits: maximumFractionalDigitCount, useGrouping: usesGrouping } ); } else { numberFormat = new Intl.NumberFormat( getLanguageSubtag(), { minimumIntegerDigits: minimumIntegerDigitCount, minimumFractionDigits: minimumFractionalDigitCount, maximumFractionDigits: maximumFractionalDigitCount, useGrouping: usesGrouping } ); } return numberFormat.format( number ); } // ~~ export function getTranslatedDate( date, { dayPattern = "d", monthPattern = "M", yearPattern = "y", timeZone = "UTC" } = {} ) { let options = { timeZone: timeZone }; if ( yearPattern === "y" ) { options.year = "numeric"; } else if ( yearPattern === "yy" ) { options.year = "2-digit"; } if ( monthPattern === "M" ) { options.month = "numeric"; } else if ( monthPattern === "MM" ) { options.month = "2-digit"; } if ( dayPattern === "d" ) { options.day = "numeric"; } else if ( dayPattern === "dd" ) { options.day = "2-digit"; } let dateTimeFormat = new Intl.DateTimeFormat( getLanguageSubtag(), options ); return dateTimeFormat.format( date ); } // ~~ export function getTranslatedTime( time, { hourPattern = "HH", minutePattern = "mm", secondPattern = "ss", timeZone = "UTC" } = {} ) { let options = { timeZone: timeZone }; if ( hourPattern === "HH" ) { options.hour = "2-digit"; options.hour12 = false; } else if ( hourPattern === "H" ) { options.hour = "numeric"; options.hour12 = false; } else if ( hourPattern === "hh" ) { options.hour = "2-digit"; options.hour12 = true; } else if ( hourPattern === "h" ) { options.hour = "numeric"; options.hour12 = true; } if ( minutePattern === "mm" ) { options.minute = "2-digit"; } else if ( minutePattern === "m" ) { options.minute = "numeric"; } if ( secondPattern === "ss" ) { options.second = "2-digit"; } else if ( secondPattern === "s" ) { options.second = "numeric"; } let dateTimeFormat = new Intl.DateTimeFormat( getLanguageSubtag(), options ); return dateTimeFormat.format( time ); } // ~~ export function getTranslatedCountryName( countryCode ) { let displayNames = new Intl.DisplayNames( [ languageTag ], { type: "region" } ); return displayNames.of( countryCode ); } // ~~ export function getTranslatedLanguageName( languageCode ) { let displayNames = new Intl.DisplayNames( [ languageTag ], { type: "language" } ); return displayNames.of( languageCode ); } // ~~ export function getTranslatedCurrencyName( currencyCode ) { let displayNames = new Intl.DisplayNames( [ languageTag ], { type: "currency" } ); return displayNames.of( currencyCode ); } // ~~ export function getBrowserLanguageCode( browserLanguageText, validLanguageCodeArray, defaultLanguageCode = "" ) { let browserLanguageArray = browserLanguageText.toLowerCase().split( "," ); for ( let browserLanguage of browserLanguageArray ) { let browserLanguageCode = browserLanguage.slice( 0, 2 ); if ( validLanguageCodeArray.indexOf( browserLanguageCode ) >= 0 ) { return browserLanguageCode; } } return defaultLanguageCode; } // ~~ export function getTrimmedLanguageTag( languageTag ) { if ( languageTag.endsWith( "--" ) ) { return languageTag.slice( 0, -2 ); } else if ( languageTag.endsWith( "-" ) ) { return languageTag.slice( 0, -1 ); } else { return languageTag; } } // ~~ export function getUntranslatedText( multilingualText ) { return multilingualText.split( languageSeparator )[ 0 ]; } // ~~ export function matchesLanguageSpecifier( languageSpecifier, languageTag ) { let languageTagPartArray = ( languageTag + "--" ).split( "-" ); for ( let languageSpecifierTag of languageSpecifier.split( "," ) ) { let languageSpecifierTagPartArray = ( languageSpecifierTag + "--" ).split( "-" ); if ( ( languageTagPartArray[ 0 ] === "" || languageSpecifierTagPartArray[ 0 ] === "" || languageTagPartArray[ 0 ] === languageSpecifierTagPartArray[ 0 ] ) && ( languageTagPartArray[ 1 ] === "" || languageSpecifierTagPartArray[ 1 ] === "" || languageTagPartArray[ 1 ] === languageSpecifierTagPartArray[ 1 ] ) && ( languageTagPartArray[ 2 ] === "" || languageSpecifierTagPartArray[ 2 ] === "" || languageTagPartArray[ 2 ] === languageSpecifierTagPartArray[ 2 ] ) ) { return true; } } return false; } // ~~ export function matchesValueSpecifier( valueSpecifier, valueByNameMap ) { if ( valueByNameMap !== undefined ) { let match = valueSpecifier.match( valueExpression ); if ( match ) { let valueName = match[ 1 ]; let operator = match[ 2 ]; let otherValue = match[ 3 ]; if ( valueByNameMap !== undefined && valueName in valueByNameMap ) { let value = valueByNameMap[ valueName ]; if ( typeof value === "number" ) { otherValue = Number( otherValue ); } if ( ( operator === "=" && value === otherValue ) || ( operator === "<" && value < otherValue ) || ( operator === "<=" && value <= otherValue ) || ( operator === ">=" && value >= otherValue ) || ( operator === ">" && value > otherValue ) || ( operator === "<>" && value !== otherValue ) ) { return true; } else { return false; } } } } console.warn( "Bad value specifier : " + valueSpecifier ); return false; } // ~~ export function matchesConditionSpecifier( specifier, valueByNameMap ) { for ( let valueSpecifier of specifier.split( "," ) ) { if ( matchesValueSpecifier( valueSpecifier, valueByNameMap ) ) { return true; } } return false; } // ~~ export function matchesTranslationSpecifier( translationSpecifier, valueByNameMap, languageTag ) { let conditionSpecifierArray = translationSpecifier.split( "?" ); if ( matchesLanguageSpecifier( conditionSpecifierArray[ 0 ], languageTag ) ) { for ( let conditionSpecifierIndex = 1; conditionSpecifierIndex < conditionSpecifierArray.length; ++conditionSpecifierIndex ) { if ( !matchesConditionSpecifier( conditionSpecifierArray[ conditionSpecifierIndex ], valueByNameMap ) ) { return false; } } return true; } return false; } // ~~ export function getSubstitutedText( text, valueByNameMap ) { if ( valueByNameMap !== undefined ) { for ( let [ name, value ] of Object.entries( valueByNameMap ) ) { text = text.replaceAll( substitutionPrefix + name + substitutionSuffix, value ); } } return text; } // ~~ export function getTranslatedText( multilingualText, valueByNameMap, languageTag_, defaultLanguageTag ) { if ( languageTag_ !== undefined && typeof valueByNameMap === "string" ) { languageTag_ = valueByNameMap; valueByNameMap = undefined; } let translatedTextArray = multilingualText.split( languageSeparator ); if ( languageTag_ === undefined ) { languageTag_ = languageTag; } if ( languageTag_ !== defaultLanguageTag ) { for ( let translatedTextIndex = translatedTextArray.length - 1; translatedTextIndex >= 1; --translatedTextIndex ) { let translatedText = translatedTextArray[ translatedTextIndex ]; let colonCharacterIndex = translatedText.indexOf( ":" ); if ( colonCharacterIndex >= 0 ) { if ( matchesTranslationSpecifier( translatedText.slice( 0, colonCharacterIndex ), valueByNameMap, languageTag_ ) ) { return getSubstitutedText( translatedText.slice( colonCharacterIndex + 1 ), valueByNameMap ); } } } } return getSubstitutedText( translatedTextArray[ 0 ], valueByNameMap ); } // ~~ export function isMultilingualText( multilingualText ) { return multilingualText.indexOf( languageSeparator ) >= 0; } // ~~ export function getTranslationArray( multilingualText ) { let translatedTextArray = multilingualText.split( languageSeparator ); let translationArray = []; translationArray.push( { specifier : "", data : translatedTextArray[ 0 ] } ); for ( let translatedTextIndex = 1; translatedTextIndex < translatedTextArray.length; ++translatedTextIndex ) { let translatedText = translatedTextArray[ translatedTextIndex ]; let colonCharacterIndex = translatedText.indexOf( ":" ); if ( colonCharacterIndex >= 0 ) { translationArray.push( { specifier : translatedText.slice( 0, colonCharacterIndex ), data : translatedText.slice( colonCharacterIndex + 1 ) } ); } } return translationArray; } // ~~ export function getNextLanguageTag( languageTagArray, translationArray ) { for ( let languageTagIndex = 1; languageTagIndex < languageTagArray.length; ++languageTagIndex ) { let languageTag = languageTagArray[ languageTagIndex ]; for ( let translationIndex = 0; translationIndex < translationArray.length; ++translationIndex ) { let translation = translationArray[ translationIndex ]; if ( translation.specifier.indexOf( languageTag ) >= 0 ) { languageTag = ""; break; } } if ( languageTag !== "" ) { return languageTag; } } return ""; } // ~~ export function getMultilingualText( translationArray ) { let multilingualText = ""; if ( translationArray.length > 0 ) { multilingualText = translationArray[ 0 ].data; for ( let translationIndex = 1; translationIndex < translationArray.length; ++translationIndex ) { let translation = translationArray[ translationIndex ]; multilingualText += languageSeparator + translation.specifier + ":" + translation.data; } } return multilingualText; } // ~~ export function getLocalizedText( text, valueByNameMap, languageTag, defaultLanguageTag ) { if ( isMultilingualText( text ) ) { return getTranslatedText( text, valueByNameMap, languageTag, defaultLanguageTag ); } else { return text; } } // ~~ export function getLocalizedTextBySlug( textSlug, valueByNameMap, languageTag, defaultLanguageTag ) { if ( textBySlugMap.has( textSlug ) ) { return getLocalizedText( textBySlugMap.get( textSlug ), valueByNameMap, languageTag, defaultLanguageTag ); } else { console.warn( "Missing text slug : " + textSlug ); return textSlug; } }