mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2024-12-15 10:48:36 +01:00
128 lines
4.7 KiB
JavaScript
128 lines
4.7 KiB
JavaScript
import { registerDebugFunction } from "./power-user.js";
|
|
import { waitUntilCondition } from "./utils.js";
|
|
|
|
const storageKey = "language";
|
|
export const localeData = await fetch("i18n.json").then(response => response.json());
|
|
|
|
function getMissingTranslations() {
|
|
const missingData = [];
|
|
|
|
for (const language of localeData.lang) {
|
|
$(document).find("[data-i18n]").each(function () {
|
|
const keys = $(this).data("i18n").split(';'); // Multi-key entries are ; delimited
|
|
for (const key of keys) {
|
|
const attributeMatch = key.match(/\[(\S+)\](.+)/); // [attribute]key
|
|
if (attributeMatch) { // attribute-tagged key
|
|
const localizedValue = localeData?.[language]?.[attributeMatch[2]];
|
|
if (!localizedValue) {
|
|
missingData.push({ key, language, value: $(this).attr(attributeMatch[1]) });
|
|
}
|
|
} else { // No attribute tag, treat as 'text'
|
|
const localizedValue = localeData?.[language]?.[key];
|
|
if (!localizedValue) {
|
|
missingData.push({ key, language, value: $(this).text().trim() });
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Remove duplicates
|
|
const uniqueMissingData = [];
|
|
for (const { key, language, value } of missingData) {
|
|
if (!uniqueMissingData.some(x => x.key === key && x.language === language && x.value === value)) {
|
|
uniqueMissingData.push({ key, language, value });
|
|
}
|
|
}
|
|
|
|
// Sort by language, then key
|
|
uniqueMissingData.sort((a, b) => a.language.localeCompare(b.language) || a.key.localeCompare(b.key));
|
|
|
|
// Map to { language: { key: value } }
|
|
const missingDataMap = {};
|
|
for (const { key, language, value } of uniqueMissingData) {
|
|
if (!missingDataMap[language]) {
|
|
missingDataMap[language] = {};
|
|
}
|
|
missingDataMap[language][key] = value;
|
|
}
|
|
|
|
console.table(uniqueMissingData);
|
|
console.log(missingDataMap);
|
|
|
|
toastr.success(`Found ${uniqueMissingData.length} missing translations. See browser console for details.`);
|
|
}
|
|
|
|
export function applyLocale(root = document) {
|
|
const overrideLanguage = localStorage.getItem("language");
|
|
var language = overrideLanguage || navigator.language || navigator.userLanguage;
|
|
language = language.toLowerCase();
|
|
//load the appropriate language file
|
|
if (localeData.lang.indexOf(language) < 0) language = "en";
|
|
|
|
const $root = root instanceof Document ? $(root) : $(new DOMParser().parseFromString(root, "text/html"));
|
|
|
|
//find all the elements with `data-i18n` attribute
|
|
$root.find("[data-i18n]").each(function () {
|
|
//read the translation from the language data
|
|
const keys = $(this).data("i18n").split(';'); // Multi-key entries are ; delimited
|
|
for (const key of keys) {
|
|
const attributeMatch = key.match(/\[(\S+)\](.+)/); // [attribute]key
|
|
if (attributeMatch) { // attribute-tagged key
|
|
const localizedValue = localeData?.[language]?.[attributeMatch[2]];
|
|
if (localizedValue) {
|
|
$(this).attr(attributeMatch[1], localizedValue);
|
|
}
|
|
} else { // No attribute tag, treat as 'text'
|
|
const localizedValue = localeData?.[language]?.[key];
|
|
if (localizedValue) {
|
|
$(this).text(localizedValue);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
if (root !== document) {
|
|
return $root.get(0).body.innerHTML;
|
|
}
|
|
}
|
|
|
|
function addLanguagesToDropdown() {
|
|
if (!Array.isArray(localeData?.lang)) {
|
|
return;
|
|
}
|
|
|
|
for (const lang of localeData.lang) {
|
|
const option = document.createElement('option');
|
|
option.value = lang;
|
|
option.innerText = lang;
|
|
$('#ui_language_select').append(option);
|
|
}
|
|
|
|
const selectedLanguage = localStorage.getItem(storageKey);
|
|
if (selectedLanguage) {
|
|
$('#ui_language_select').val(selectedLanguage);
|
|
}
|
|
}
|
|
|
|
jQuery(async () => {
|
|
waitUntilCondition(() => !!localeData);
|
|
applyLocale();
|
|
addLanguagesToDropdown();
|
|
|
|
$('#ui_language_select').on('change', async function () {
|
|
const language = String($(this).val());
|
|
|
|
if (language) {
|
|
localStorage.setItem(storageKey, language);
|
|
} else {
|
|
localStorage.removeItem(storageKey);
|
|
}
|
|
|
|
location.reload();
|
|
});
|
|
|
|
registerDebugFunction('getMissingTranslations', 'Get missing translations', 'Detects missing localization data and dumps the data into the browser console.', getMissingTranslations);
|
|
registerDebugFunction('applyLocale', 'Apply locale', 'Reapplies the currently selected locale to the page.', applyLocale);
|
|
});
|