mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +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 };
|