i18n:Replace qstr with Translation.tr and update the translation file

This commit is contained in:
月月 2025-07-12 22:46:24 +08:00
parent af5d25b575
commit fb0d3f7f40
8 changed files with 196 additions and 20 deletions

View file

@ -0,0 +1,170 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import "root:/modules/common/"
Singleton {
id: root
property var translations: ({})
property string currentLanguage: "en_US"
property var availableLanguages: ["en_US"]
property bool isScanning: false
property bool isLoading: false
Process {
id: scanLanguagesProcess
command: ["find", Qt.resolvedUrl(Directories.config + "/quickshell/translations/").toString().replace("file://", ""), "-name", "*.json", "-exec", "basename", "{}", ".json", ";"]
running: false
stdout: SplitParser {
onRead: data => {
if (data.trim().length === 0) return
var files = data.trim().split('\n')
for (var i = 0; i < files.length; i++) {
var lang = files[i].trim()
if (lang.length > 0 && root.availableLanguages.indexOf(lang) === -1) {
root.availableLanguages.push(lang)
}
}
}
}
onExited: (exitCode, exitStatus) => {
root.isScanning = false
if (exitCode !== 0) {
root.availableLanguages = ["en_US"]
}
root.loadTranslations()
}
}
FileView {
id: translationFileView
onLoaded: {
var textContent = ""
try {
textContent = text()
} catch (e) {
root.translations = {}
root.isLoading = false
return
}
if (textContent.length === 0) {
root.translations = {}
root.isLoading = false
return
}
try {
var jsonData = JSON.parse(textContent)
root.translations = jsonData
root.isLoading = false
} catch (e) {
root.translations = {}
root.isLoading = false
}
}
onLoadFailed: (error) => {
root.translations = {}
root.isLoading = false
}
}
function detectSystemLanguage() {
var locale = Qt.locale().name
return locale
}
function getLanguageCode() {
var configLang = "auto"
try {
configLang = ConfigOptions.language.ui
} catch (e) {
configLang = "auto"
}
if (configLang === "auto") {
return detectSystemLanguage()
} else {
if (root.availableLanguages.indexOf(configLang) !== -1) {
return configLang
} else {
return detectSystemLanguage()
}
}
}
function loadTranslations() {
if (root.isScanning) {
return
}
var targetLang = getLanguageCode()
root.currentLanguage = targetLang
// Use empty translations for English (default language)
if (targetLang === "en_US" || targetLang === "en") {
root.translations = {}
return
}
// Check if target language is available
if (root.availableLanguages.indexOf(targetLang) === -1) {
root.currentLanguage = "en_US"
root.translations = {}
return
}
// Load translation file
root.isLoading = true
var translationsPath = Qt.resolvedUrl(Directories.config + "/quickshell/translations/" + targetLang + ".json")
translationFileView.path = translationsPath
}
function tr(text) {
if (!text) {
return ""
}
var key = text.toString()
if (root.isLoading) {
return key
}
if (root.currentLanguage === "en_US" || root.currentLanguage === "en" || !root.translations) {
return key
}
if (root.translations.hasOwnProperty(key)) {
var translation = root.translations[key]
if (translation && translation.toString().trim().length > 0) {
return translation.toString()
} else {
return translation.toString()
}
}
return key // Fallback to key name
}
function reloadTranslations() {
root.scanLanguages()
}
function scanLanguages() {
var translationsDir = Qt.resolvedUrl(Directories.config + "/quickshell/translations/").toString().replace("file://", "")
root.isScanning = true
scanLanguagesProcess.running = true
}
Component.onCompleted: {
root.scanLanguages()
}
}

View file

@ -73,7 +73,7 @@ Item {
},
{
name: "save",
description: qsTr("Save chat"),
description: Translation.tr("Save chat"),
execute: (args) => {
const joinedArgs = args.join(" ")
if (joinedArgs.trim().length == 0) {
@ -85,7 +85,7 @@ Item {
},
{
name: "load",
description: qsTr("Load chat"),
description: Translation.tr("Load chat"),
execute: (args) => {
const joinedArgs = args.join(" ")
if (joinedArgs.trim().length == 0) {
@ -97,7 +97,7 @@ Item {
},
{
name: "clear",
description: qsTr("Clear chat history"),
description: Translation.tr("Clear chat history"),
execute: () => {
Ai.clearMessages();
}

View file

@ -47,7 +47,7 @@ Item { // Tag suggestion description
}
StyledText {
visible: root.showArrows && root.showTab
text: qsTr("or")
text: Translation.tr("or")
font.pixelSize: Appearance.font.pixelSize.smaller
}
KeyboardKey {

View file

@ -19,9 +19,9 @@ Item {
required property var scopeRoot
anchors.fill: parent
property var tabButtonList: [
...(Config.options.policies.ai !== 0 ? [{"icon": "neurology", "name": qsTr("Intelligence")}] : []),
{"icon": "translate", "name": qsTr("Translator")},
...(Config.options.policies.weeb === 1 ? [{"icon": "bookmark_heart", "name": qsTr("Anime")}] : [])
...(Config.options.policies.ai !== 0 ? [{"icon": "neurology", "name": Translation.tr("Intelligence")}] : []),
{"icon": "translate", "name": Translation.tr("Translator")},
...(Config.options.policies.weeb === 1 ? [{"icon": "bookmark_heart", "name": Translation.tr("Anime")}] : [])
]
property int selectedTab: 0

View file

@ -17,8 +17,8 @@ Rectangle {
property int selectedTab: 0
property bool collapsed: Persistent.states.sidebar.bottomGroup.collapsed
property var tabs: [
{"type": "calendar", "name": "Calendar", "icon": "calendar_month", "widget": calendarWidget},
{"type": "todo", "name": "To Do", "icon": "done_outline", "widget": todoWidget}
{"type": "calendar", "name": Translation.tr("Calendar"), "icon": "calendar_month", "widget": calendarWidget},
{"type": "todo", "name": Translation.tr("To Do"), "icon": "done_outline", "widget": todoWidget}
]
Behavior on implicitHeight {

View file

@ -85,7 +85,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 10
horizontalAlignment: Text.AlignHCenter
text: `${Notifications.list.length} notifications`
text: `${Notifications.list.length} ${Translation.tr("notifications")}`
opacity: Notifications.list.length > 0 ? 1 : 0
visible: opacity > 0

View file

@ -96,8 +96,6 @@
"Run command": "Run command",
"Save": "Save",
"Save to Downloads": "Save to Downloads",
"Scroll to change brightness": "Scroll to change brightness",
"Scroll to change volume": "Scroll to change volume",
"Search": "Search",
"Search the web": "Search the web",
"Search, calculate or run": "Search, calculate or run",
@ -106,8 +104,6 @@
"Set API key": "Set API key",
"Set temperature (randomness) of the model. Values range between 0 to 2 for Gemini, 0 to 1 for other models. Default is 0.5.": "Set temperature (randomness) of the model. Values range between 0 to 2 for Gemini, 0 to 1 for other models. Default is 0.5.",
"Set the current API provider": "Set the current API provider",
"Shell configuration created": "Shell configuration created",
"Shell configuration failed to load": "Shell configuration failed to load",
"Shutdown": "Shutdown",
"Silent": "Silent",
"Sleep": "Sleep",
@ -169,5 +165,12 @@
"Experimental | Online | Google's model\nCan do a little more but doesn't search quickly": "Experimental | Online | Google's model\nCan do a little more but doesn't search quickly",
"Message the model... \"{0}\" for commands": "Message the model... \"{0}\" for commands",
"To set an API key, pass it with the command\n\nTo view the key, pass \"get\" with the command<br/>\n\n### For {0}:\n\n**Link**: {1}\n\n{2}": "To set an API key, pass it with the command\n\nTo view the key, pass \"get\" with the command<br/>\n\n### For {0}:\n\n**Link**: {1}\n\n{2}",
"Settings": "Settings"
"Settings": "Settings",
"Save chat": "Save chat",
"Load chat": "Load chat",
"or": "or",
"Set the system prompt for the model.": "Set the system prompt for the model.",
"To Do": "To Do",
"Calendar": "Calendar",
"notifications": "notifications"
}

View file

@ -96,8 +96,6 @@
"Run command": "运行命令",
"Save": "保存",
"Save to Downloads": "保存到下载文件夹",
"Scroll to change brightness": "滚动调节亮度",
"Scroll to change volume": "滚动调节音量",
"Search": "搜索",
"Search the web": "搜索网络",
"Search, calculate or run": "搜索、计算或运行",
@ -106,8 +104,6 @@
"Set API key": "设置 API 密钥",
"Set temperature (randomness) of the model. Values range between 0 to 2 for Gemini, 0 to 1 for other models. Default is 0.5.": "设置模型的温度随机性。Gemini 模型范围为 0 到 2其他模型为 0 到 1。默认值为 0.5。",
"Set the current API provider": "设置当前 API 提供商",
"Shell configuration created": "Shell 配置已创建",
"Shell configuration failed to load": "Shell 配置加载失败",
"Shutdown": "关机",
"Silent": "静音",
"Sleep": "睡眠",
@ -169,5 +165,12 @@
"Online via {0} | {1}'s model": "通过 {0} 在线 | {1} 的模型",
"That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number": "没有找到结果。提示:\n- 检查您的标签和 NSFW 设置\n- 如果没有想到标签,请输入页码",
"Online | Google's model\nGives up-to-date information with search.": "在线 | Google 模型\n通过搜索提供最新信息。",
"Settings": "设置"
"Settings": "设置",
"Save chat": "保存对话",
"Load chat": "加载对话",
"or": "或",
"Set the system prompt for the model.": "为模型设置系统提示。",
"To Do": "待办",
"Calendar": "日历",
"notifications": "条通知"
}