import { generateFilePath } from "@nextcloud/router"; import DOMPurify from "dompurify"; import escapeHTML from "escape-html"; /*! * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: GPL-3.0-or-later */ function getLocale() { return document.documentElement.dataset.locale || "en"; } function getCanonicalLocale() { return getLocale().replace(/_/g, "-"); } function getLanguage() { return document.documentElement.lang || "en"; } function isRTL(language) { const languageCode = language || getLanguage(); const rtlLanguages = [ /* eslint-disable no-multi-spaces */ "ae", // Avestan "ar", // 'العربية', Arabic "arc", // Aramaic "arz", // 'مصرى', Egyptian "bcc", // 'بلوچی مکرانی', Southern Balochi "bqi", // 'بختياري', Bakthiari "ckb", // 'Soranî / کوردی', Sorani "dv", // Dhivehi "fa", // 'فارسی', Persian "glk", // 'گیلکی', Gilaki "ha", // 'هَوُسَ', Hausa "he", // 'עברית', Hebrew "khw", // 'کھوار', Khowar "ks", // 'कॉशुर / کٲشُر', Kashmiri "ku", // 'Kurdî / كوردی', Kurdish "mzn", // 'مازِرونی', Mazanderani "nqo", // 'ߒߞߏ', N’Ko "pnb", // 'پنجابی', Western Punjabi "ps", // 'پښتو', Pashto, "sd", // 'سنڌي', Sindhi "ug", // 'Uyghurche / ئۇيغۇرچە', Uyghur "ur", // 'اردو', Urdu "ur-PK", // 'اردو', Urdu (nextcloud BCP47 variant) "uz-AF", // 'اوزبیکی', Uzbek Afghan "yi" // 'ייִדיש', Yiddish /* eslint-enable no-multi-spaces */ ]; return rtlLanguages.includes(languageCode); } /*! * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: GPL-3.0-or-later */ function hasAppTranslations(appId) { return window._oc_l10n_registry_translations?.[appId] !== void 0 && window._oc_l10n_registry_plural_functions?.[appId] !== void 0; } function registerAppTranslations(appId, translations, pluralFunction) { if (appId === "__proto__" || appId === "constructor" || appId === "prototype") { throw new Error("Invalid appId"); } window._oc_l10n_registry_translations = Object.assign( window._oc_l10n_registry_translations || {}, { [appId]: Object.assign(window._oc_l10n_registry_translations?.[appId] || {}, translations) } ); window._oc_l10n_registry_plural_functions = Object.assign( window._oc_l10n_registry_plural_functions || {}, { [appId]: pluralFunction } ); } function unregisterAppTranslations(appId) { delete window._oc_l10n_registry_translations?.[appId]; delete window._oc_l10n_registry_plural_functions?.[appId]; } function getAppTranslations(appId) { return { translations: window._oc_l10n_registry_translations?.[appId] ?? {}, pluralFunction: window._oc_l10n_registry_plural_functions?.[appId] ?? ((number) => number) }; } /*! * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: GPL-3.0-or-later */ function translate(app, text, placeholdersOrNumber, optionsOrNumber, options) { const vars = typeof placeholdersOrNumber === "object" ? placeholdersOrNumber : void 0; const number = typeof optionsOrNumber === "number" ? optionsOrNumber : typeof placeholdersOrNumber === "number" ? placeholdersOrNumber : void 0; const allOptions = { // defaults escape: true, sanitize: true, // overwrite with user config ...typeof options === "object" ? options : typeof optionsOrNumber === "object" ? optionsOrNumber : {} }; const identity = (value) => value; const optSanitize = allOptions.sanitize ? DOMPurify.sanitize : identity; const optEscape = allOptions.escape ? escapeHTML : identity; const isValidReplacement = (value) => typeof value === "string" || typeof value === "number"; const _build = (text2, vars2, number2) => { return text2.replace(/%n/g, "" + number2).replace(/{([^{}]*)}/g, (match, key) => { if (vars2 === void 0 || !(key in vars2)) { return optEscape(match); } const replacement = vars2[key]; if (isValidReplacement(replacement)) { return optEscape(`${replacement}`); } else if (typeof replacement === "object" && isValidReplacement(replacement.value)) { const escape = replacement.escape !== false ? escapeHTML : identity; return escape(`${replacement.value}`); } else { return optEscape(match); } }); }; const bundle = options?.bundle ?? getAppTranslations(app); let translation = bundle.translations[text] || text; translation = Array.isArray(translation) ? translation[0] : translation; if (typeof vars === "object" || number !== void 0) { return optSanitize(_build( translation, vars, number )); } else { return optSanitize(translation); } } function translatePlural(app, textSingular, textPlural, number, vars, options) { const identifier = "_" + textSingular + "_::_" + textPlural + "_"; const bundle = options?.bundle ?? getAppTranslations(app); const value = bundle.translations[identifier]; if (typeof value !== "undefined") { const translation = value; if (Array.isArray(translation)) { const plural = bundle.pluralFunction(number); return translate(app, translation[plural], vars, number, options); } } if (number === 1) { return translate(app, textSingular, vars, number, options); } else { return translate(app, textPlural, vars, number, options); } } function loadTranslations(appName, callback) { if (hasAppTranslations(appName) || getLocale() === "en") { return Promise.resolve().then(callback); } const url = generateFilePath(appName, "l10n", getLocale() + ".json"); const promise = new Promise((resolve, reject) => { const request = new XMLHttpRequest(); request.open("GET", url, true); request.onerror = () => { reject(new Error(request.statusText || "Network error")); }; request.onload = () => { if (request.status >= 200 && request.status < 300) { try { const bundle = JSON.parse(request.responseText); if (typeof bundle.translations === "object") resolve(bundle); } catch (error) { } reject(new Error("Invalid content of translation bundle")); } else { reject(new Error(request.statusText)); } }; request.send(); }); return promise.then((result) => { register(appName, result.translations); return result; }).then(callback); } function register(appName, bundle) { registerAppTranslations(appName, bundle, getPlural); } function unregister(appName) { return unregisterAppTranslations(appName); } function getPlural(number, language = getLanguage()) { if (language === "pt-BR") { language = "xbr"; } if (language.length > 3) { language = language.substring(0, language.lastIndexOf("-")); } switch (language) { case "az": case "bo": case "dz": case "id": case "ja": case "jv": case "ka": case "km": case "kn": case "ko": case "ms": case "th": case "tr": case "vi": case "zh": return 0; case "af": case "bn": case "bg": case "ca": case "da": case "de": case "el": case "en": 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 number === 1 ? 0 : 1; case "am": case "bh": case "fil": case "fr": case "gun": case "hi": case "hy": case "ln": case "mg": case "nso": case "xbr": case "ti": case "wa": return number === 0 || number === 1 ? 0 : 1; case "be": case "bs": case "hr": case "ru": case "sh": case "sr": case "uk": return number % 10 === 1 && number % 100 !== 11 ? 0 : number % 10 >= 2 && number % 10 <= 4 && (number % 100 < 10 || number % 100 >= 20) ? 1 : 2; case "cs": case "sk": return number === 1 ? 0 : number >= 2 && number <= 4 ? 1 : 2; case "ga": return number === 1 ? 0 : number === 2 ? 1 : 2; case "lt": return number % 10 === 1 && number % 100 !== 11 ? 0 : number % 10 >= 2 && (number % 100 < 10 || number % 100 >= 20) ? 1 : 2; case "sl": return number % 100 === 1 ? 0 : number % 100 === 2 ? 1 : number % 100 === 3 || number % 100 === 4 ? 2 : 3; case "mk": return number % 10 === 1 ? 0 : 1; case "mt": return number === 1 ? 0 : number === 0 || number % 100 > 1 && number % 100 < 11 ? 1 : number % 100 > 10 && number % 100 < 20 ? 2 : 3; case "lv": return number === 0 ? 0 : number % 10 === 1 && number % 100 !== 11 ? 1 : 2; case "pl": return number === 1 ? 0 : number % 10 >= 2 && number % 10 <= 4 && (number % 100 < 12 || number % 100 > 14) ? 1 : 2; case "cy": return number === 1 ? 0 : number === 2 ? 1 : number === 8 || number === 11 ? 2 : 3; case "ro": return number === 1 ? 0 : number === 0 || number % 100 > 0 && number % 100 < 20 ? 1 : 2; case "ar": return number === 0 ? 0 : number === 1 ? 1 : number === 2 ? 2 : number % 100 >= 3 && number % 100 <= 10 ? 3 : number % 100 >= 11 && number % 100 <= 99 ? 4 : 5; default: return 0; } } export { getLocale as a, getLanguage as b, translatePlural as c, getPlural as d, getCanonicalLocale as g, isRTL as i, loadTranslations as l, register as r, translate as t, unregister as u };