senselogic-lingo
Version:
Text localization and processing.
1,129 lines (980 loc) • 25.6 kB
JavaScript
// -- 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
&& isString( valueByNameMap ) )
{
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;
}
}