Files
illogical-impulse/dots/.config/quickshell/ii/services/Translation.qml
T
2025-10-30 19:37:28 +01:00

147 lines
4.8 KiB
QML

pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import qs.modules.common
Singleton {
id: root
property var translations: ({})
property var generatedTranslations: ({})
property var availableLanguages: ["en_US"]
property var availableGeneratedLanguages: []
property var allAvailableLanguages: {
const combined = new Set([...root.availableLanguages, ...root.availableGeneratedLanguages]);
return Array.from(combined).sort();
}
property bool isScanning: scanLanguagesProcess.running
property bool isLoading: false
property string translationKeepSuffix: "/*keep*/"
property string translationsDir: Quickshell.shellPath("translations")
property string generatedTranslationsDir: Directories.shellConfig + "/translations"
property string languageCode: {
var configLang = Config?.options.language.ui ?? "auto";
if (configLang !== "auto")
return configLang;
return Qt.locale().name;
}
TranslationScanner {
id: scanLanguagesProcess
translationsDir: root.translationsDir
onLanguagesScanned: (languages) => {
root.availableLanguages = [...languages];
}
}
TranslationScanner {
id: scanGeneratedLanguagesProcess
translationsDir: root.generatedTranslationsDir
onLanguagesScanned: (languages) => {
root.availableGeneratedLanguages = [...languages];
}
}
onLanguageCodeChanged: {
print("[Translation] Language changed to", root.languageCode);
translationFileView.languageCode = root.languageCode;
generatedTranslationFileView.languageCode = root.languageCode;
translationFileView.reread();
generatedTranslationFileView.reread();
}
TranslationReader {
id: translationFileView
translationsDir: root.translationsDir
languageCode: root.languageCode
onContentLoaded: (data) => {
root.translations = data;
root.isLoading = false;
}
}
TranslationReader {
id: generatedTranslationFileView
translationsDir: root.generatedTranslationsDir
languageCode: root.languageCode
onContentLoaded: (data) => {
root.generatedTranslations = data;
root.isLoading = false;
}
}
function tr(text) {
// Special cases
if (!text) return "";
var key = text.toString();
if (root.isLoading || (!root?.translations?.hasOwnProperty(key) && !root?.generatedTranslations?.hasOwnProperty(key)))
return key;
// Normal cases
var translation = root.translations[key] || root.generatedTranslations[key] || key;
// print(key, "-> [", root.translations[key], root.generatedTranslations[key], key, "] ->", translation);
if (translation.endsWith(root.translationKeepSuffix)) {
translation = translation.substring(0, translation.length - root.translationKeepSuffix.length).trim();
}
return translation;
}
component TranslationScanner: Process {
id: translationScanner
required property string translationsDir
signal languagesScanned(var languages)
command: ["find", translationScanner.translationsDir, "-name", "*.json", "-exec", "basename", "{}", ".json", ";"]
running: true
stdout: StdioCollector {
id: languagesCollector
onStreamFinished: {
const output = languagesCollector.text;
const files = output.trim().split('\n').map(f => f.trim());
translationScanner.languagesScanned(files);
}
}
onExited: (exitCode, exitStatus) => {
if (exitCode !== 0) {
translationScanner.languagesScanned(["en_US"]);
}
}
}
component TranslationReader: FileView {
id: translationReader
required property string translationsDir
property string languageCode: root.languageCode
signal contentLoaded(var data)
function reread() { // Proper reload in case the file was incorrect before
translationReader.path = "";
translationReader.path = `${translationReader.translationsDir}/${translationReader.languageCode}.json`;
translationReader.reload();
}
path: ""
onLoaded: {
var textContent = "";
try {
textContent = text();
var jsonData = JSON.parse(textContent);
translationReader.contentLoaded(jsonData);
} catch (e) {
console.log("[Translation] Failed to load translations:", e);
translationReader.contentLoaded({});
}
}
onLoadFailed: error => {
translationReader.contentLoaded({});
}
}
}