translation of all project, and new translation mechanism
This commit is contained in:
@@ -9,14 +9,14 @@ Window {
|
||||
height: 720
|
||||
visible: true
|
||||
flags: Qt.Window
|
||||
title: qsTr("Minecraft Launcher")
|
||||
title: Loc.t.app.title
|
||||
|
||||
// ── Backend ────────────────────────────────────────────────────────────
|
||||
LauncherBackend {
|
||||
id: backend
|
||||
|
||||
onLaunched: (profileName, buildName, serverUrl) => {
|
||||
window.showToast(qsTr("Запущено: %1 — %2").arg(profileName).arg(buildName), "#4b7a1f")
|
||||
window.showToast(Loc.t.launch.status.started.arg(profileName).arg(buildName), "#4b7a1f")
|
||||
}
|
||||
onLaunchProgress: (message) => window.showToast(message, "#3a5a8c", 0)
|
||||
onLaunchError: (message) => window.showToast(message, "#cc3333", 8000)
|
||||
@@ -27,20 +27,20 @@ Window {
|
||||
}
|
||||
onGameFinished: (exitCode, crashed) => {
|
||||
window.showToast(crashed || exitCode !== 0
|
||||
? qsTr("Игра завершилась с ошибкой (код %1)").arg(exitCode)
|
||||
: qsTr("Игра закрыта"),
|
||||
? Loc.t.game.status.crashed.arg(exitCode)
|
||||
: Loc.t.game.status.closed,
|
||||
crashed || exitCode !== 0 ? "#cc3333" : "#555555")
|
||||
}
|
||||
onMicrosoftLoginUrlReady: (url) => window.openMicrosoftLogin(url)
|
||||
// Выбор в списке здесь не трогаем: новый профиль уже выбран тем, кто
|
||||
// его создал, а повторный вход мог быть и не в последний профиль.
|
||||
onMicrosoftLoginSucceeded: (playerName) =>
|
||||
window.showToast(qsTr("Вход выполнен: %1").arg(playerName), "#4b7a1f")
|
||||
window.showToast(Loc.t.auth.status.signedInAs.arg(playerName), "#4b7a1f")
|
||||
onMicrosoftLoginFailed: (message) => window.showToast(message, "#cc3333", 8000)
|
||||
onMicrosoftReloginRequired: (profileIndex) => backend.startMicrosoftLogin(profileIndex)
|
||||
onGameOutput: (line) => console.log(line)
|
||||
onSeasonalInstallFinished: (seasonalId, buildName) => {
|
||||
window.showToast(qsTr("Сборка «%1» установлена — можно запускать").arg(buildName),
|
||||
window.showToast(Loc.t.seasonal.status.readyToLaunch.arg(buildName),
|
||||
"#4b7a1f", 8000)
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ Window {
|
||||
const component = Qt.createComponent("MicrosoftLoginDialog.qml")
|
||||
if (component.status !== Component.Ready) {
|
||||
backend.cancelMicrosoftLogin()
|
||||
window.showToast(qsTr("Окно входа Microsoft недоступно: сборка без Qt WebEngine"),
|
||||
window.showToast(Loc.t.auth.msa.error.windowUnavailable,
|
||||
"#cc3333", 8000)
|
||||
return
|
||||
}
|
||||
@@ -134,11 +134,11 @@ Window {
|
||||
anchors.leftMargin: 24
|
||||
anchors.bottomMargin: 24
|
||||
|
||||
title: qsTr("Загрузка %1").arg(backend.downloadVersion)
|
||||
title: Loc.t.common.progress.downloadingNamed.arg(backend.downloadVersion)
|
||||
fraction: backend.downloadProgress
|
||||
status: backend.downloadStatus
|
||||
detail: backend.downloadBytesTotal > 0
|
||||
? qsTr("%1 — %2 / %3 МБ").arg(backend.downloadStatus)
|
||||
? Loc.t.common.progress.bytes.arg(backend.downloadStatus)
|
||||
.arg(window.formatMb(backend.downloadBytesDone))
|
||||
.arg(window.formatMb(backend.downloadBytesTotal))
|
||||
: ""
|
||||
@@ -201,8 +201,8 @@ Window {
|
||||
// висела бы поверх собственного меню.
|
||||
ToolTip.visible: profileBox.hovered && !profileBox.down
|
||||
ToolTip.text: backend.profileNames.length === 0
|
||||
? qsTr("Профили игрока — добавьте первый профиль")
|
||||
: qsTr("Профиль игрока: %1").arg(profileBox.displayText)
|
||||
? Loc.t.profile.hint.addFirst
|
||||
: Loc.t.profile.label.current.arg(profileBox.displayText)
|
||||
|
||||
contentItem: Text {
|
||||
id: profileText
|
||||
@@ -263,7 +263,7 @@ Window {
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "+ Добавить профиль"
|
||||
text: Loc.t.profile.button.add
|
||||
color: "#91B315"
|
||||
font.pixelSize: 12
|
||||
}
|
||||
@@ -394,7 +394,7 @@ Window {
|
||||
|
||||
contentItem: Text {
|
||||
text: backend.activeBuildName !== "" ? backend.activeBuildName
|
||||
: qsTr("Сборка не выбрана")
|
||||
: Loc.t.common.status.noBuildSelected
|
||||
color: "#ffffff"
|
||||
font: buildButton.font
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
@@ -424,7 +424,7 @@ Window {
|
||||
}
|
||||
|
||||
ToolTip.visible: hovered && !buildsDialog.opened
|
||||
ToolTip.text: qsTr("Пользовательские сборки")
|
||||
ToolTip.text: Loc.t.common.title.customBuilds
|
||||
|
||||
onClicked: buildsDialog.open()
|
||||
}
|
||||
@@ -450,7 +450,7 @@ Window {
|
||||
}
|
||||
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Открыть папку с модами Minecraft")
|
||||
ToolTip.text: Loc.t.app.tooltip.openMods
|
||||
|
||||
onClicked: backend.openMinecraftFolder()
|
||||
}
|
||||
@@ -478,7 +478,7 @@ Window {
|
||||
}
|
||||
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Настройки запуска: Java, память, папка игры")
|
||||
ToolTip.text: Loc.t.app.tooltip.settings
|
||||
|
||||
onClicked: settingsDialog.load()
|
||||
}
|
||||
@@ -497,7 +497,7 @@ Window {
|
||||
hoverEnabled: true
|
||||
|
||||
contentItem: Text {
|
||||
text: qsTr("Сезонные сборки")
|
||||
text: Loc.t.common.title.seasonalBuilds
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 14
|
||||
elide: Text.ElideRight
|
||||
@@ -513,7 +513,7 @@ Window {
|
||||
}
|
||||
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Готовые сборки с сервера: моды, конфиги и Java одной кнопкой")
|
||||
ToolTip.text: Loc.t.app.tooltip.seasonal
|
||||
|
||||
onClicked: seasonalDialog.openCatalog()
|
||||
}
|
||||
@@ -548,7 +548,7 @@ Window {
|
||||
implicitHeight: 52 // tells Dialog how tall the header is
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "Новый профиль"
|
||||
text: Loc.t.profile.title.new
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 17
|
||||
font.bold: true
|
||||
@@ -570,7 +570,7 @@ Window {
|
||||
id: pfName
|
||||
x: 20
|
||||
width: parent.width - 40
|
||||
placeholderText: "Имя профиля"
|
||||
placeholderText: Loc.t.profile.placeholder.name
|
||||
color: "#ffffff"
|
||||
placeholderTextColor: "#666666"
|
||||
background: Rectangle {
|
||||
@@ -587,7 +587,7 @@ Window {
|
||||
width: parent.width - 40
|
||||
// Ник лицензионного профиля приходит из аккаунта: поля здесь нет.
|
||||
visible: pfAuth.currentIndex !== 2
|
||||
placeholderText: "Логин"
|
||||
placeholderText: Loc.t.profile.placeholder.login
|
||||
color: "#ffffff"
|
||||
placeholderTextColor: "#666666"
|
||||
background: Rectangle {
|
||||
@@ -603,7 +603,7 @@ Window {
|
||||
x: 20
|
||||
width: parent.width - 40
|
||||
visible: pfAuth.currentIndex === 1
|
||||
placeholderText: "Пароль Ely.by"
|
||||
placeholderText: Loc.t.profile.placeholder.elyPassword
|
||||
echoMode: TextInput.Password
|
||||
color: "#ffffff"
|
||||
placeholderTextColor: "#666666"
|
||||
@@ -620,8 +620,8 @@ Window {
|
||||
x: 20
|
||||
width: parent.width - 40
|
||||
model: backend.microsoftAvailable
|
||||
? ["Офлайн (без пароля)", "Ely.by", "Microsoft (лицензия)"]
|
||||
: ["Офлайн (без пароля)", "Ely.by"]
|
||||
? Loc.t.profile.authTypes
|
||||
: Loc.t.profile.authTypes.slice(0, 2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -638,7 +638,7 @@ Window {
|
||||
spacing: 12
|
||||
|
||||
Button {
|
||||
text: "Отмена"
|
||||
text: Loc.t.common.button.cancel
|
||||
width: 110; height: 36
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
@@ -654,7 +654,7 @@ Window {
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Добавить"
|
||||
text: Loc.t.common.button.add
|
||||
width: 110; height: 36
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
@@ -736,7 +736,7 @@ Window {
|
||||
implicitHeight: 52
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "Редактирование профиля"
|
||||
text: Loc.t.profile.title.edit
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 17
|
||||
font.bold: true
|
||||
@@ -758,7 +758,7 @@ Window {
|
||||
id: epName
|
||||
x: 20
|
||||
width: parent.width - 40
|
||||
placeholderText: "Имя профиля"
|
||||
placeholderText: Loc.t.profile.placeholder.name
|
||||
color: "#ffffff"
|
||||
placeholderTextColor: "#666666"
|
||||
background: Rectangle {
|
||||
@@ -775,7 +775,7 @@ Window {
|
||||
width: parent.width - 40
|
||||
// Для лицензии логин не вводят: ниже показан ник из аккаунта.
|
||||
visible: epAuth.currentIndex !== 2
|
||||
placeholderText: "Логин"
|
||||
placeholderText: Loc.t.profile.placeholder.login
|
||||
color: "#ffffff"
|
||||
placeholderTextColor: "#666666"
|
||||
background: Rectangle {
|
||||
@@ -810,7 +810,7 @@ Window {
|
||||
x: 20
|
||||
width: parent.width - 40
|
||||
visible: epAuth.currentIndex === 1
|
||||
placeholderText: "Пароль Ely.by"
|
||||
placeholderText: Loc.t.profile.placeholder.elyPassword
|
||||
echoMode: TextInput.Password
|
||||
color: "#ffffff"
|
||||
placeholderTextColor: "#666666"
|
||||
@@ -829,8 +829,8 @@ Window {
|
||||
// Тип уже сохранённого профиля показываем всегда: иначе в
|
||||
// сборке без WebEngine он молча стал бы офлайновым.
|
||||
model: (backend.microsoftAvailable || editProfileDialog.msProfile)
|
||||
? ["Офлайн (без пароля)", "Ely.by", "Microsoft (лицензия)"]
|
||||
: ["Офлайн (без пароля)", "Ely.by"]
|
||||
? Loc.t.profile.authTypes
|
||||
: Loc.t.profile.authTypes.slice(0, 2)
|
||||
}
|
||||
|
||||
// Состояние аккаунта Microsoft и кнопка повторного входа: токен
|
||||
@@ -842,8 +842,8 @@ Window {
|
||||
visible: epAuth.currentIndex === 2
|
||||
|
||||
Text {
|
||||
text: editProfileDialog.msLinked ? qsTr("Вход выполнен")
|
||||
: qsTr("Вход не выполнен")
|
||||
text: editProfileDialog.msLinked ? Loc.t.auth.status.signedIn
|
||||
: Loc.t.auth.status.signedOut
|
||||
color: editProfileDialog.msLinked ? "#91B315" : "#aaaaaa"
|
||||
font.pixelSize: 13
|
||||
}
|
||||
@@ -888,7 +888,7 @@ Window {
|
||||
spacing: 12
|
||||
|
||||
Button {
|
||||
text: "Отмена"
|
||||
text: Loc.t.common.button.cancel
|
||||
width: 110; height: 36
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
@@ -904,7 +904,7 @@ Window {
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "ОК"
|
||||
text: Loc.t.common.button.ok
|
||||
width: 110; height: 36
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
@@ -972,7 +972,7 @@ Window {
|
||||
implicitHeight: 52
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "Двухфакторная аутентификация"
|
||||
text: Loc.t.auth.ely.title.twoFactor
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 15
|
||||
font.bold: true
|
||||
@@ -993,7 +993,7 @@ Window {
|
||||
Text {
|
||||
x: 20
|
||||
width: parent.width - 40
|
||||
text: qsTr("Введите код из приложения-аутентификатора для «%1»")
|
||||
text: Loc.t.auth.ely.hint.enterCode
|
||||
.arg(twoFactorDialog.profileName)
|
||||
color: "#aaaaaa"
|
||||
font.pixelSize: 12
|
||||
@@ -1031,7 +1031,7 @@ Window {
|
||||
spacing: 12
|
||||
|
||||
Button {
|
||||
text: "Отмена"
|
||||
text: Loc.t.common.button.cancel
|
||||
width: 110; height: 36
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
@@ -1047,7 +1047,7 @@ Window {
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Войти"
|
||||
text: Loc.t.common.button.signIn
|
||||
width: 110; height: 36
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
@@ -1080,6 +1080,9 @@ Window {
|
||||
// Выбранная сборка Java живёт в свойстве, а не в поле ввода: её выбирают
|
||||
// в отдельном окне, а записывается она только по «Сохранить».
|
||||
property string javaRuntimeId: ""
|
||||
// Раскрытый путь к папке игры: хранится свойством, а не присваивается
|
||||
// тексту напрямую, — иначе подпись не пережила бы смену языка.
|
||||
property string resolvedGameDir: ""
|
||||
// Не привязка: javaRuntimeInfo() — обычный вызов, и сам он не
|
||||
// пересчитается, когда сборка докачается. Обновляем по событиям.
|
||||
property var javaRuntimeInfo: null
|
||||
@@ -1107,8 +1110,8 @@ Window {
|
||||
stWidth.text = String(s.windowWidth)
|
||||
stHeight.text = String(s.windowHeight)
|
||||
stFullscreen.checked = s.fullscreen === true
|
||||
stResolved.text = qsTr("Папка игры: %1").arg(s.resolvedGameDir)
|
||||
stJavaList.text = backend.detectedJava().join("\n") || qsTr("Java не найдена")
|
||||
stLanguage.currentIndex = Math.max(0, stLanguage.codes.indexOf(s.language || "system"))
|
||||
settingsDialog.resolvedGameDir = s.resolvedGameDir
|
||||
open()
|
||||
}
|
||||
|
||||
@@ -1123,7 +1126,7 @@ Window {
|
||||
implicitHeight: 52
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "Настройки запуска"
|
||||
text: Loc.t.settings.title
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 17
|
||||
font.bold: true
|
||||
@@ -1141,19 +1144,43 @@ Window {
|
||||
topPadding: 18
|
||||
bottomPadding: 18
|
||||
|
||||
// Язык — настройка уровня приложения, поэтому стоит над параметрами
|
||||
// запуска. Подписи в модели переводятся, коды рядом — нет.
|
||||
Column {
|
||||
x: 20
|
||||
width: parent.width - 40
|
||||
spacing: 3
|
||||
|
||||
Text {
|
||||
text: Loc.t.settings.language.label
|
||||
color: "#aaaaaa"
|
||||
font.pixelSize: 11
|
||||
}
|
||||
|
||||
DarkCombo {
|
||||
id: stLanguage
|
||||
width: parent.width
|
||||
height: 32
|
||||
readonly property var codes: ["system", "ru", "en"]
|
||||
model: [Loc.t.settings.language.system,
|
||||
Loc.t.settings.language.ru,
|
||||
Loc.t.settings.language.en]
|
||||
}
|
||||
}
|
||||
|
||||
LabelledField {
|
||||
id: stGameDir
|
||||
x: 20
|
||||
width: parent.width - 40
|
||||
label: "Папка .minecraft"
|
||||
placeholder: "по умолчанию"
|
||||
label: Loc.t.settings.label.gameDir
|
||||
placeholder: Loc.t.settings.placeholder.gameDir
|
||||
}
|
||||
LabelledField {
|
||||
id: stJavaPath
|
||||
x: 20
|
||||
width: parent.width - 40
|
||||
label: "Путь к Java"
|
||||
placeholder: "автоопределение"
|
||||
label: Loc.t.settings.label.javaPath
|
||||
placeholder: Loc.t.settings.placeholder.javaPath
|
||||
}
|
||||
|
||||
// Сборка Java из папки лаунчера. Выбрана — запуск идёт ей, а не тем,
|
||||
@@ -1164,7 +1191,7 @@ Window {
|
||||
spacing: 3
|
||||
|
||||
Text {
|
||||
text: "Версия Java из папки лаунчера"
|
||||
text: Loc.t.settings.label.javaRuntime
|
||||
color: "#aaaaaa"
|
||||
font.pixelSize: 11
|
||||
}
|
||||
@@ -1186,12 +1213,12 @@ Window {
|
||||
color: settingsDialog.javaRuntimeId === "" ? "#666666" : "#ffffff"
|
||||
text: {
|
||||
if (settingsDialog.javaRuntimeId === "")
|
||||
return qsTr("не выбрана — искать в системе")
|
||||
return Loc.t.settings.status.javaRuntimeNone
|
||||
const info = settingsDialog.javaRuntimeInfo
|
||||
if (!info)
|
||||
return settingsDialog.javaRuntimeId
|
||||
return info.installed ? info.label
|
||||
: qsTr("%1 — скачивается").arg(info.label)
|
||||
: Loc.t.settings.status.javaRuntimeDownloading.arg(info.label)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1199,7 +1226,7 @@ Window {
|
||||
anchors.right: clearJava.left
|
||||
anchors.rightMargin: 12
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Выбрать…")
|
||||
text: Loc.t.common.button.choose
|
||||
color: "#91B315"
|
||||
font.pixelSize: 12
|
||||
}
|
||||
@@ -1240,25 +1267,25 @@ Window {
|
||||
LabelledField {
|
||||
id: stMinMemory
|
||||
width: 100
|
||||
label: "-Xms, МБ"
|
||||
label: Loc.t.settings.label.minMemory
|
||||
validator: IntValidator { bottom: 0; top: 1048576 }
|
||||
}
|
||||
LabelledField {
|
||||
id: stMaxMemory
|
||||
width: 100
|
||||
label: "-Xmx, МБ"
|
||||
label: Loc.t.settings.label.maxMemory
|
||||
validator: IntValidator { bottom: 0; top: 1048576 }
|
||||
}
|
||||
LabelledField {
|
||||
id: stWidth
|
||||
width: 100
|
||||
label: "Ширина окна"
|
||||
label: Loc.t.settings.label.windowWidth
|
||||
validator: IntValidator { bottom: 0; top: 16384 }
|
||||
}
|
||||
LabelledField {
|
||||
id: stHeight
|
||||
width: 100
|
||||
label: "Высота окна"
|
||||
label: Loc.t.settings.label.windowHeight
|
||||
validator: IntValidator { bottom: 0; top: 16384 }
|
||||
}
|
||||
}
|
||||
@@ -1267,14 +1294,14 @@ Window {
|
||||
id: stJvmArgs
|
||||
x: 20
|
||||
width: parent.width - 40
|
||||
label: "Дополнительные аргументы JVM"
|
||||
label: Loc.t.settings.label.jvmArgs
|
||||
placeholder: "-XX:+UseG1GC …"
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: stFullscreen
|
||||
x: 20
|
||||
text: "Запускать в полноэкранном режиме"
|
||||
text: Loc.t.settings.label.fullscreen
|
||||
|
||||
// Индикатор Basic-стиля — крупный светлый квадрат, на тёмном
|
||||
// фоне диалога он не читается. Рисуем свой в палитре окна.
|
||||
@@ -1307,6 +1334,7 @@ Window {
|
||||
|
||||
Text {
|
||||
id: stResolved
|
||||
text: Loc.t.settings.status.resolvedGameDir.arg(settingsDialog.resolvedGameDir)
|
||||
x: 20
|
||||
width: parent.width - 40
|
||||
color: "#888888"
|
||||
@@ -1315,6 +1343,7 @@ Window {
|
||||
}
|
||||
Text {
|
||||
id: stJavaList
|
||||
text: backend.detectedJava().join("\n") || Loc.t.settings.status.javaNotFound
|
||||
x: 20
|
||||
width: parent.width - 40
|
||||
color: "#888888"
|
||||
@@ -1336,7 +1365,7 @@ Window {
|
||||
spacing: 12
|
||||
|
||||
Button {
|
||||
text: "Отмена"
|
||||
text: Loc.t.common.button.cancel
|
||||
width: 110; height: 36
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
@@ -1352,7 +1381,7 @@ Window {
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Сохранить"
|
||||
text: Loc.t.common.button.save
|
||||
width: 110; height: 36
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
@@ -1378,7 +1407,8 @@ Window {
|
||||
"jvmArgs": stJvmArgs.text.trim(),
|
||||
"windowWidth": parseInt(stWidth.text) || 0,
|
||||
"windowHeight": parseInt(stHeight.text) || 0,
|
||||
"fullscreen": stFullscreen.checked
|
||||
"fullscreen": stFullscreen.checked,
|
||||
"language": stLanguage.codes[stLanguage.currentIndex]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user