mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-11-03 18:58:24 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			284 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			284 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import { IntlMessageFormat } from 'intl-messageformat';
 | 
						|
 | 
						|
function strtr(string, replacePairs) {
 | 
						|
    const regex = Object.entries(replacePairs).map(([from]) => {
 | 
						|
        return from.replace(/([-[\]{}()*+?.\\^$|#,])/g, '\\$1');
 | 
						|
    });
 | 
						|
    if (regex.length === 0) {
 | 
						|
        return string;
 | 
						|
    }
 | 
						|
    return string.replace(new RegExp(regex.join('|'), 'g'), (matched) => replacePairs[matched].toString());
 | 
						|
}
 | 
						|
 | 
						|
function format(id, parameters, locale) {
 | 
						|
    if (null === id || '' === id) {
 | 
						|
        return '';
 | 
						|
    }
 | 
						|
    if (typeof parameters['%count%'] === 'undefined' || Number.isNaN(parameters['%count%'])) {
 | 
						|
        return strtr(id, parameters);
 | 
						|
    }
 | 
						|
    const number = Number(parameters['%count%']);
 | 
						|
    let parts = [];
 | 
						|
    if (/^\|+$/.test(id)) {
 | 
						|
        parts = id.split('|');
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        parts = id.match(/(?:\|\||[^|])+/g) || [];
 | 
						|
    }
 | 
						|
    const intervalRegex = /^(?<interval>({\s*(-?\d+(\.\d+)?[\s*,\s*\-?\d+(.\d+)?]*)\s*})|(?<left_delimiter>[[\]])\s*(?<left>-Inf|-?\d+(\.\d+)?)\s*,\s*(?<right>\+?Inf|-?\d+(\.\d+)?)\s*(?<right_delimiter>[[\]]))\s*(?<message>.*?)$/s;
 | 
						|
    const standardRules = [];
 | 
						|
    for (let part of parts) {
 | 
						|
        part = part.trim().replace(/\|\|/g, '|');
 | 
						|
        const matches = part.match(intervalRegex);
 | 
						|
        if (matches) {
 | 
						|
            const matchGroups = matches.groups || {};
 | 
						|
            if (matches[2]) {
 | 
						|
                for (const n of matches[3].split(',')) {
 | 
						|
                    if (number === Number(n)) {
 | 
						|
                        return strtr(matchGroups.message, parameters);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                const leftNumber = '-Inf' === matchGroups.left ? Number.NEGATIVE_INFINITY : Number(matchGroups.left);
 | 
						|
                const rightNumber = ['Inf', '+Inf'].includes(matchGroups.right)
 | 
						|
                    ? Number.POSITIVE_INFINITY
 | 
						|
                    : Number(matchGroups.right);
 | 
						|
                if (('[' === matchGroups.left_delimiter ? number >= leftNumber : number > leftNumber) &&
 | 
						|
                    (']' === matchGroups.right_delimiter ? number <= rightNumber : number < rightNumber)) {
 | 
						|
                    return strtr(matchGroups.message, parameters);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            const ruleMatch = part.match(/^\w+:\s*(.*?)$/);
 | 
						|
            standardRules.push(ruleMatch ? ruleMatch[1] : part);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    const position = getPluralizationRule(number, locale);
 | 
						|
    if (typeof standardRules[position] === 'undefined') {
 | 
						|
        if (1 === parts.length && typeof standardRules[0] !== 'undefined') {
 | 
						|
            return strtr(standardRules[0], parameters);
 | 
						|
        }
 | 
						|
        throw new Error(`Unable to choose a translation for "${id}" with locale "${locale}" for value "${number}". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %count% apples").`);
 | 
						|
    }
 | 
						|
    return strtr(standardRules[position], parameters);
 | 
						|
}
 | 
						|
function getPluralizationRule(number, locale) {
 | 
						|
    number = Math.abs(number);
 | 
						|
    let _locale = locale;
 | 
						|
    if (locale === 'pt_BR' || locale === 'en_US_POSIX') {
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
    _locale = _locale.length > 3 ? _locale.substring(0, _locale.indexOf('_')) : _locale;
 | 
						|
    switch (_locale) {
 | 
						|
        case 'af':
 | 
						|
        case 'bn':
 | 
						|
        case 'bg':
 | 
						|
        case 'ca':
 | 
						|
        case 'da':
 | 
						|
        case 'de':
 | 
						|
        case 'el':
 | 
						|
        case 'en':
 | 
						|
        case 'en_US_POSIX':
 | 
						|
        case 'eo':
 | 
						|
        case 'es':
 | 
						|
        case 'et':
 | 
						|
        case 'eu':
 | 
						|
        case 'fa':
 | 
						|
        case 'fi':
 | 
						|
        case 'fo':
 | 
						|
        case 'fur':
 | 
						|
        case 'fy':
 | 
						|
        case 'gl':
 | 
						|
        case 'gu':
 | 
						|
        case 'ha':
 | 
						|
        case 'he':
 | 
						|
        case 'hu':
 | 
						|
        case 'is':
 | 
						|
        case 'it':
 | 
						|
        case 'ku':
 | 
						|
        case 'lb':
 | 
						|
        case 'ml':
 | 
						|
        case 'mn':
 | 
						|
        case 'mr':
 | 
						|
        case 'nah':
 | 
						|
        case 'nb':
 | 
						|
        case 'ne':
 | 
						|
        case 'nl':
 | 
						|
        case 'nn':
 | 
						|
        case 'no':
 | 
						|
        case 'oc':
 | 
						|
        case 'om':
 | 
						|
        case 'or':
 | 
						|
        case 'pa':
 | 
						|
        case 'pap':
 | 
						|
        case 'ps':
 | 
						|
        case 'pt':
 | 
						|
        case 'so':
 | 
						|
        case 'sq':
 | 
						|
        case 'sv':
 | 
						|
        case 'sw':
 | 
						|
        case 'ta':
 | 
						|
        case 'te':
 | 
						|
        case 'tk':
 | 
						|
        case 'ur':
 | 
						|
        case 'zu':
 | 
						|
            return 1 === number ? 0 : 1;
 | 
						|
        case 'am':
 | 
						|
        case 'bh':
 | 
						|
        case 'fil':
 | 
						|
        case 'fr':
 | 
						|
        case 'gun':
 | 
						|
        case 'hi':
 | 
						|
        case 'hy':
 | 
						|
        case 'ln':
 | 
						|
        case 'mg':
 | 
						|
        case 'nso':
 | 
						|
        case 'pt_BR':
 | 
						|
        case 'ti':
 | 
						|
        case 'wa':
 | 
						|
            return number < 2 ? 0 : 1;
 | 
						|
        case 'be':
 | 
						|
        case 'bs':
 | 
						|
        case 'hr':
 | 
						|
        case 'ru':
 | 
						|
        case 'sh':
 | 
						|
        case 'sr':
 | 
						|
        case 'uk':
 | 
						|
            return 1 === number % 10 && 11 !== number % 100
 | 
						|
                ? 0
 | 
						|
                : number % 10 >= 2 && number % 10 <= 4 && (number % 100 < 10 || number % 100 >= 20)
 | 
						|
                    ? 1
 | 
						|
                    : 2;
 | 
						|
        case 'cs':
 | 
						|
        case 'sk':
 | 
						|
            return 1 === number ? 0 : number >= 2 && number <= 4 ? 1 : 2;
 | 
						|
        case 'ga':
 | 
						|
            return 1 === number ? 0 : 2 === number ? 1 : 2;
 | 
						|
        case 'lt':
 | 
						|
            return 1 === number % 10 && 11 !== number % 100
 | 
						|
                ? 0
 | 
						|
                : number % 10 >= 2 && (number % 100 < 10 || number % 100 >= 20)
 | 
						|
                    ? 1
 | 
						|
                    : 2;
 | 
						|
        case 'sl':
 | 
						|
            return 1 === number % 100 ? 0 : 2 === number % 100 ? 1 : 3 === number % 100 || 4 === number % 100 ? 2 : 3;
 | 
						|
        case 'mk':
 | 
						|
            return 1 === number % 10 ? 0 : 1;
 | 
						|
        case 'mt':
 | 
						|
            return 1 === number
 | 
						|
                ? 0
 | 
						|
                : 0 === number || (number % 100 > 1 && number % 100 < 11)
 | 
						|
                    ? 1
 | 
						|
                    : number % 100 > 10 && number % 100 < 20
 | 
						|
                        ? 2
 | 
						|
                        : 3;
 | 
						|
        case 'lv':
 | 
						|
            return 0 === number ? 0 : 1 === number % 10 && 11 !== number % 100 ? 1 : 2;
 | 
						|
        case 'pl':
 | 
						|
            return 1 === number
 | 
						|
                ? 0
 | 
						|
                : number % 10 >= 2 && number % 10 <= 4 && (number % 100 < 12 || number % 100 > 14)
 | 
						|
                    ? 1
 | 
						|
                    : 2;
 | 
						|
        case 'cy':
 | 
						|
            return 1 === number ? 0 : 2 === number ? 1 : 8 === number || 11 === number ? 2 : 3;
 | 
						|
        case 'ro':
 | 
						|
            return 1 === number ? 0 : 0 === number || (number % 100 > 0 && number % 100 < 20) ? 1 : 2;
 | 
						|
        case 'ar':
 | 
						|
            return 0 === number
 | 
						|
                ? 0
 | 
						|
                : 1 === number
 | 
						|
                    ? 1
 | 
						|
                    : 2 === number
 | 
						|
                        ? 2
 | 
						|
                        : number % 100 >= 3 && number % 100 <= 10
 | 
						|
                            ? 3
 | 
						|
                            : number % 100 >= 11 && number % 100 <= 99
 | 
						|
                                ? 4
 | 
						|
                                : 5;
 | 
						|
        default:
 | 
						|
            return 0;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
function formatIntl(id, parameters, locale) {
 | 
						|
    if (id === '') {
 | 
						|
        return '';
 | 
						|
    }
 | 
						|
    const intlMessage = new IntlMessageFormat(id, [locale.replace('_', '-')], undefined, { ignoreTag: true });
 | 
						|
    parameters = { ...parameters };
 | 
						|
    Object.entries(parameters).forEach(([key, value]) => {
 | 
						|
        if (key.includes('%') || key.includes('{')) {
 | 
						|
            delete parameters[key];
 | 
						|
            parameters[key.replace(/[%{} ]/g, '').trim()] = value;
 | 
						|
        }
 | 
						|
    });
 | 
						|
    return intlMessage.format(parameters);
 | 
						|
}
 | 
						|
 | 
						|
let _locale = null;
 | 
						|
let _localeFallbacks = {};
 | 
						|
let _throwWhenNotFound = false;
 | 
						|
function setLocale(locale) {
 | 
						|
    _locale = locale;
 | 
						|
}
 | 
						|
function getLocale() {
 | 
						|
    return (_locale ||
 | 
						|
        document.documentElement.getAttribute('data-symfony-ux-translator-locale') ||
 | 
						|
        (document.documentElement.lang ? document.documentElement.lang.replace('-', '_') : null) ||
 | 
						|
        'en');
 | 
						|
}
 | 
						|
function throwWhenNotFound(enabled) {
 | 
						|
    _throwWhenNotFound = enabled;
 | 
						|
}
 | 
						|
function setLocaleFallbacks(localeFallbacks) {
 | 
						|
    _localeFallbacks = localeFallbacks;
 | 
						|
}
 | 
						|
function getLocaleFallbacks() {
 | 
						|
    return _localeFallbacks;
 | 
						|
}
 | 
						|
function trans(message, parameters = {}, domain = 'messages', locale = null) {
 | 
						|
    if (typeof domain === 'undefined') {
 | 
						|
        domain = 'messages';
 | 
						|
    }
 | 
						|
    if (typeof locale === 'undefined' || null === locale) {
 | 
						|
        locale = getLocale();
 | 
						|
    }
 | 
						|
    if (typeof message.translations === 'undefined') {
 | 
						|
        return message.id;
 | 
						|
    }
 | 
						|
    const localesFallbacks = getLocaleFallbacks();
 | 
						|
    const translationsIntl = message.translations[`${domain}+intl-icu`];
 | 
						|
    if (typeof translationsIntl !== 'undefined') {
 | 
						|
        while (typeof translationsIntl[locale] === 'undefined') {
 | 
						|
            locale = localesFallbacks[locale];
 | 
						|
            if (!locale) {
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (locale) {
 | 
						|
            return formatIntl(translationsIntl[locale], parameters, locale);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    const translations = message.translations[domain];
 | 
						|
    if (typeof translations !== 'undefined') {
 | 
						|
        while (typeof translations[locale] === 'undefined') {
 | 
						|
            locale = localesFallbacks[locale];
 | 
						|
            if (!locale) {
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (locale) {
 | 
						|
            return format(translations[locale], parameters, locale);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (_throwWhenNotFound) {
 | 
						|
        throw new Error(`No translation message found with id "${message.id}".`);
 | 
						|
    }
 | 
						|
    return message.id;
 | 
						|
}
 | 
						|
 | 
						|
export { getLocale, getLocaleFallbacks, setLocale, setLocaleFallbacks, throwWhenNotFound, trans };
 |