1
Fork 0
mirror of https://github.com/redstrate/Novus.git synced 2025-04-26 05:37:46 +00:00

armoury: Support localization

This commit is contained in:
Joshua Goins 2024-02-04 15:13:46 -05:00
parent 1c0712bdbf
commit 98036249fb
8 changed files with 60 additions and 51 deletions

View file

@ -2,11 +2,12 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "cmpeditor.h"
#include <KLocalizedString>
CmpEditor::CmpEditor(GameData *data, QWidget *parent)
: CmpPart(data, parent)
{
setWindowTitle(QStringLiteral("CMP Editor"));
setWindowTitle(i18nc("@title:window CMP is an abbreviation", "CMP Editor"));
load(physis_gamedata_extract_file(data, "chara/xls/charamake/human.cmp"));
}

View file

@ -5,6 +5,7 @@
#include "boneeditor.h"
#include "magic_enum.hpp"
#include <KLocalizedString>
#include <QCloseEvent>
#include <QFileDialog>
#include <QFormLayout>
@ -17,7 +18,7 @@ FullModelViewer::FullModelViewer(GameData *data, FileCache &cache, QWidget *pare
: QMainWindow(parent)
, data(data)
{
setWindowTitle(QStringLiteral("Full Model Viewer"));
setWindowTitle(i18nc("@title:window", "Full Model Viewer"));
setMinimumWidth(1280);
setMinimumHeight(720);
setAttribute(Qt::WA_DeleteOnClose, false);
@ -28,13 +29,15 @@ FullModelViewer::FullModelViewer(GameData *data, FileCache &cache, QWidget *pare
auto layout = new QVBoxLayout();
dummyWidget->setLayout(layout);
auto fileMenu = menuBar()->addMenu(QStringLiteral("File"));
auto fileMenu = menuBar()->addMenu(i18nc("@title:menu", "File"));
auto datOpenAction = fileMenu->addAction(QStringLiteral("Load character DAT..."));
auto datOpenAction = fileMenu->addAction(i18nc("@action:inmenu DAT is an abbreviation", "Load Character DAT..."));
datOpenAction->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
connect(datOpenAction, &QAction::triggered, [this] {
auto fileName =
QFileDialog::getOpenFileName(nullptr, QStringLiteral("Open DAT File"), QStringLiteral("~"), QStringLiteral("FFXIV Character DAT File (*.dat)"));
auto fileName = QFileDialog::getOpenFileName(nullptr,
i18nc("@title:window DAT is an abbreviation", "Open DAT File"),
QStringLiteral("~"),
i18nc("DAT is an abbreviation", "FFXIV Character DAT File (*.dat)"));
auto buffer = physis_read_file(fileName.toStdString().c_str());
@ -72,7 +75,7 @@ FullModelViewer::FullModelViewer(GameData *data, FileCache &cache, QWidget *pare
const float scale = (float)position / 100.0f;
updateHeightScaling(scale);
});
characterEditorLayout->addRow(QStringLiteral("Height"), characterHeight);
characterEditorLayout->addRow(i18nc("@label:slider Character height", "Height"), characterHeight);
auto bustSize = new QSlider();
bustSize->setOrientation(Qt::Horizontal);
@ -81,7 +84,7 @@ FullModelViewer::FullModelViewer(GameData *data, FileCache &cache, QWidget *pare
const float scale = (float)position / 100.0f;
updateBustScaling(scale);
});
characterEditorLayout->addRow(QStringLiteral("Bust Size"), bustSize);
characterEditorLayout->addRow(i18nc("@label:slider Character breast size", "Bust Size"), bustSize);
characterEditorLayout->addWidget(addFaceGroup());
characterEditorLayout->addWidget(addHairGroup());
@ -89,8 +92,8 @@ FullModelViewer::FullModelViewer(GameData *data, FileCache &cache, QWidget *pare
characterEditorLayout->addWidget(addTailGroup());
auto tabWidget = new QTabWidget();
tabWidget->addTab(new BoneEditor(gearView), QStringLiteral("Bone Editor"));
tabWidget->addTab(characterEditorWidget, QStringLiteral("Character Editor"));
tabWidget->addTab(new BoneEditor(gearView), i18nc("@title:tab", "Bone Editor"));
tabWidget->addTab(characterEditorWidget, i18nc("@title:tab", "Character Editor"));
viewportLayout->addWidget(tabWidget);
auto controlLayout = new QHBoxLayout();
@ -291,23 +294,23 @@ void FullModelViewer::updateSupportedSubraces()
QGroupBox *FullModelViewer::addFaceGroup()
{
auto faceGroup = new QGroupBox(QStringLiteral("Face"));
auto faceGroup = new QGroupBox(i18nc("@title:group", "Face"));
auto faceGroupLayout = new QVBoxLayout();
faceGroup->setLayout(faceGroupLayout);
auto faceRadio1 = new QRadioButton(QStringLiteral("Face 1"));
auto faceRadio1 = new QRadioButton(i18nc("@option:radio", "Face 1"));
connect(faceRadio1, &QRadioButton::clicked, this, [this] {
gearView->setFace(1);
});
faceGroupLayout->addWidget(faceRadio1);
auto faceRadio2 = new QRadioButton(QStringLiteral("Face 2"));
auto faceRadio2 = new QRadioButton(i18nc("@option:radio", "Face 2"));
connect(faceRadio2, &QRadioButton::clicked, this, [this] {
gearView->setFace(2);
});
faceGroupLayout->addWidget(faceRadio2);
auto faceRadio3 = new QRadioButton(QStringLiteral("Face 3"));
auto faceRadio3 = new QRadioButton(i18nc("@option:radio", "Face 3"));
connect(faceRadio3, &QRadioButton::clicked, this, [this] {
gearView->setFace(3);
});
@ -318,23 +321,23 @@ QGroupBox *FullModelViewer::addFaceGroup()
QGroupBox *FullModelViewer::addHairGroup()
{
auto hairGroup = new QGroupBox(QStringLiteral("Hair"));
auto hairGroup = new QGroupBox(i18nc("@title:group", "Hair"));
auto hairGroupLayout = new QVBoxLayout();
hairGroup->setLayout(hairGroupLayout);
auto hairRadio1 = new QRadioButton(QStringLiteral("Hair 1"));
auto hairRadio1 = new QRadioButton(i18nc("@option:radio", "Hair 1"));
connect(hairRadio1, &QRadioButton::clicked, this, [this] {
gearView->setHair(1);
});
hairGroupLayout->addWidget(hairRadio1);
auto hairRadio2 = new QRadioButton(QStringLiteral("Hair 2"));
auto hairRadio2 = new QRadioButton(i18nc("@option:radio", "Hair 2"));
connect(hairRadio2, &QRadioButton::clicked, this, [this] {
gearView->setHair(2);
});
hairGroupLayout->addWidget(hairRadio2);
auto hairRadio3 = new QRadioButton(QStringLiteral("Hair 3"));
auto hairRadio3 = new QRadioButton(i18nc("@option:radio", "Hair 3"));
connect(hairRadio3, &QRadioButton::clicked, this, [this] {
gearView->setHair(3);
});
@ -345,23 +348,23 @@ QGroupBox *FullModelViewer::addHairGroup()
QGroupBox *FullModelViewer::addEarGroup()
{
auto earGroup = new QGroupBox(QStringLiteral("Ears"));
auto earGroup = new QGroupBox(i18nc("@title:group", "Ears"));
auto earGroupLayout = new QVBoxLayout();
earGroup->setLayout(earGroupLayout);
auto earRadio1 = new QRadioButton(QStringLiteral("Ears 1"));
auto earRadio1 = new QRadioButton(i18nc("@option:radio", "Ears 1"));
connect(earRadio1, &QRadioButton::clicked, this, [this] {
gearView->setEar(1);
});
earGroupLayout->addWidget(earRadio1);
auto earRadio2 = new QRadioButton(QStringLiteral("Ears 2"));
auto earRadio2 = new QRadioButton(i18nc("@option:radio", "Ears 2"));
connect(earRadio2, &QRadioButton::clicked, this, [this] {
gearView->setEar(2);
});
earGroupLayout->addWidget(earRadio2);
auto earRadio3 = new QRadioButton(QStringLiteral("Ears 3"));
auto earRadio3 = new QRadioButton(i18nc("@option:radio", "Ears 3"));
connect(earRadio3, &QRadioButton::clicked, this, [this] {
gearView->setEar(3);
});
@ -372,23 +375,23 @@ QGroupBox *FullModelViewer::addEarGroup()
QGroupBox *FullModelViewer::addTailGroup()
{
auto tailGroup = new QGroupBox(QStringLiteral("Tail"));
auto tailGroup = new QGroupBox(i18nc("@title:group", "Tail"));
auto tailGroupLayout = new QVBoxLayout();
tailGroup->setLayout(tailGroupLayout);
auto tailRadio1 = new QRadioButton(QStringLiteral("Tail 1"));
auto tailRadio1 = new QRadioButton(i18nc("@option:radio", "Tail 1"));
connect(tailRadio1, &QRadioButton::clicked, this, [this] {
gearView->setTail(1);
});
tailGroupLayout->addWidget(tailRadio1);
auto tailRadio2 = new QRadioButton(QStringLiteral("Tail 2"));
auto tailRadio2 = new QRadioButton(i18nc("@option:radio", "Tail 2"));
connect(tailRadio2, &QRadioButton::clicked, this, [this] {
gearView->setTail(2);
});
tailGroupLayout->addWidget(tailRadio2);
auto tailRadio3 = new QRadioButton(QStringLiteral("Tail 3"));
auto tailRadio3 = new QRadioButton(i18nc("@option:radio", "Tail 3"));
connect(tailRadio3, &QRadioButton::clicked, this, [this] {
gearView->setTail(3);
});

View file

@ -3,6 +3,7 @@
#include "gearlistmodel.h"
#include <KLocalizedString>
#include <QtConcurrent>
#include <magic_enum.hpp>
@ -128,7 +129,7 @@ QVariant GearListModel::headerData(int section, Qt::Orientation orientation, int
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
if (section == 0) {
return QStringLiteral("Name");
return i18nc("@title:column Item name", "Name");
}
}

View file

@ -3,6 +3,7 @@
#include "gearlistwidget.h"
#include <KLocalizedString>
#include <QLineEdit>
#include <QSortFilterProxyModel>
#include <QVBoxLayout>
@ -24,7 +25,7 @@ GearListWidget::GearListWidget(GameData *data, QWidget *parent)
searchModel->setFilterCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
auto searchEdit = new QLineEdit();
searchEdit->setPlaceholderText(QStringLiteral("Search..."));
searchEdit->setPlaceholderText(i18nc("@info:placeholder Search through items", "Search…"));
searchEdit->setClearButtonEnabled(true);
searchEdit->setProperty("_breeze_borders_sides", QVariant::fromValue(QFlags{Qt::BottomEdge}));
connect(searchEdit, &QLineEdit::textChanged, this, [=](const QString &text) {

View file

@ -34,6 +34,7 @@ GearView::GearView(GameData *data, FileCache &cache, QWidget *parent)
ImGui::SetWindowPos(ImVec2(0, 0));
ImGui::SetWindowSize(io.DisplaySize);
// TODO: localize
const char *loadingLabel{"Loading gear..."};
ImGui::SetCursorPosX((io.DisplaySize.x - ImGui::CalcTextSize(loadingLabel).x) * 0.5f);
ImGui::SetCursorPosY((io.DisplaySize.y - ImGui::CalcTextSize(loadingLabel).y) * 0.5f);

View file

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include <KLocalizedString>
#include <QApplication>
#include <physis.hpp>
@ -13,10 +14,7 @@ int main(int argc, char *argv[])
{
QApplication app(argc, argv);
customizeAboutData(QStringLiteral("armoury"),
QStringLiteral("zone.xiv.armoury"),
QStringLiteral("Gear Editor"),
QStringLiteral("Program to view FFXIV gear."));
customizeAboutData(QStringLiteral("armoury"), QStringLiteral("zone.xiv.armoury"), QStringLiteral("Gear Editor"), i18n("Program to view FFXIV gear."));
// Default to a sensible message pattern
if (qEnvironmentVariableIsEmpty("QT_MESSAGE_PATTERN")) {

View file

@ -8,6 +8,7 @@
#include <QTableWidget>
#include <QTimer>
#include <KLocalizedString>
#include <QAction>
#include <QApplication>
#include <QDesktopServices>
@ -53,9 +54,9 @@ MainWindow::MainWindow(GameData *in_data)
metadataView = new MetadataView(&data);
auto tabWidget = new QTabWidget();
tabWidget->addTab(gearView, QStringLiteral("Models"));
tabWidget->addTab(materialView, QStringLiteral("Materials"));
tabWidget->addTab(metadataView, QStringLiteral("Metadata"));
tabWidget->addTab(gearView, i18nc("@title:tab", "Models"));
tabWidget->addTab(materialView, i18nc("@title:tab", "Materials"));
tabWidget->addTab(metadataView, i18nc("@title:tab", "Metadata"));
tabWidget->setDocumentMode(true); // Don't draw the borders
tabWidget->tabBar()->setExpanding(true);
dummyWidget->addWidget(tabWidget);
@ -68,18 +69,18 @@ MainWindow::MainWindow(GameData *in_data)
void MainWindow::setupAdditionalMenus(QMenuBar *menuBar)
{
auto toolsMenu = menuBar->addMenu(QStringLiteral("Tools"));
auto toolsMenu = menuBar->addMenu(i18nc("@title:menu", "Tools"));
auto cmpEditorMenu = toolsMenu->addAction(QStringLiteral("CMP Editor"));
auto cmpEditorMenu = toolsMenu->addAction(i18nc("@action:inmenu CMP is an abbreviation", "CMP Editor"));
cmpEditorMenu->setIcon(QIcon::fromTheme(QStringLiteral("document-edit")));
connect(cmpEditorMenu, &QAction::triggered, [this] {
auto cmpEditor = new CmpEditor(&data);
cmpEditor->show();
});
auto windowMenu = menuBar->addMenu(QStringLiteral("Window"));
auto windowMenu = menuBar->addMenu(i18nc("@title:menu", "Window"));
auto fmvMenu = windowMenu->addAction(QStringLiteral("Full Model viewer"));
auto fmvMenu = windowMenu->addAction(i18nc("@action:inmenu", "Full Model Viewer"));
fmvMenu->setCheckable(true);
fmvMenu->setIcon(QIcon::fromTheme(QStringLiteral("user-symbolic")));
connect(fmvMenu, &QAction::toggled, [this](bool toggled) {
@ -93,9 +94,9 @@ void MainWindow::setupAdditionalMenus(QMenuBar *menuBar)
fmvMenu->setChecked(fullModelViewer->isVisible());
});
auto settingsMenu = menuBar->addMenu(QStringLiteral("Settings"));
auto settingsMenu = menuBar->addMenu(i18nc("@title:menu", "Settings"));
auto settingsAction = settingsMenu->addAction(QStringLiteral("Configure Armoury..."));
auto settingsAction = settingsMenu->addAction(i18nc("@action:inmenu", "Configure Armoury…"));
settingsAction->setIcon(QIcon::fromTheme(QStringLiteral("configure-symbolic")));
connect(settingsAction, &QAction::triggered, [this] {
auto settingsWindow = new SettingsWindow();

View file

@ -5,6 +5,7 @@
#include <KConfig>
#include <KConfigGroup>
#include <KLocalizedString>
#include <QDebug>
#include <QFileDialog>
#include <QLineEdit>
@ -83,7 +84,7 @@ SingleGearView::SingleGearView(GameData *data, FileCache &cache, QWidget *parent
});
controlLayout->addWidget(lodCombo);
addToFMVButton = new QPushButton(QStringLiteral("Add to FMV"));
addToFMVButton = new QPushButton(i18nc("@action:button FMV is an abbreviation for Full Model Viewer", "Add to FMV"));
addToFMVButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add-user")));
connect(addToFMVButton, &QPushButton::clicked, this, [this](bool) {
if (currentGear.has_value()) {
@ -91,7 +92,7 @@ SingleGearView::SingleGearView(GameData *data, FileCache &cache, QWidget *parent
}
});
editButton = new QPushButton(QStringLiteral("Edit"));
editButton = new QPushButton(i18nc("@action:button", "Edit"));
editButton->setIcon(QIcon::fromTheme(QStringLiteral("document-edit")));
connect(editButton, &QPushButton::clicked, this, [this](bool) {
// Export in default location
@ -134,7 +135,7 @@ SingleGearView::SingleGearView(GameData *data, FileCache &cache, QWidget *parent
});
topControlLayout->addWidget(editButton);
importButton = new QPushButton(QStringLiteral("Import..."));
importButton = new QPushButton(i18nc("@action:button", "Import…"));
importButton->setIcon(QIcon::fromTheme(QStringLiteral("document-import")));
connect(importButton, &QPushButton::clicked, this, [this](bool) {
if (currentGear.has_value()) {
@ -157,7 +158,7 @@ SingleGearView::SingleGearView(GameData *data, FileCache &cache, QWidget *parent
if (!QDir().exists(path))
QDir().mkpath(path);
const QString fileName = QFileDialog::getOpenFileName(this, tr("Import Model"), path, tr("glTF Binary File (*.glb)"));
const QString fileName = QFileDialog::getOpenFileName(this, i18nc("@title:window", "Import Model"), path, i18n("glTF Binary File (*.glb)"));
if (!fileName.isEmpty()) {
importModel(fileName);
}
@ -166,7 +167,7 @@ SingleGearView::SingleGearView(GameData *data, FileCache &cache, QWidget *parent
topControlLayout->addWidget(importButton);
auto testMenu = new QMenu();
auto gltfAction = testMenu->addAction(QStringLiteral("glTF"));
auto gltfAction = testMenu->addAction(i18nc("@action:inmenu", "glTF"));
connect(gltfAction, &QAction::triggered, this, [this](bool) {
if (currentGear.has_value()) {
// TODO: deduplicate
@ -194,7 +195,7 @@ SingleGearView::SingleGearView(GameData *data, FileCache &cache, QWidget *parent
gearView->exportModel(fileName);
}
});
auto mdlAction = testMenu->addAction(QStringLiteral("MDL"));
auto mdlAction = testMenu->addAction(i18nc("@action:inmenu", "MDL"));
connect(mdlAction, &QAction::triggered, this, [this, data](bool) {
if (currentGear.has_value()) {
// TODO: deduplicate
@ -202,8 +203,10 @@ SingleGearView::SingleGearView(GameData *data, FileCache &cache, QWidget *parent
return QString(mdlPath).section(QLatin1Char('/'), -1);
};
const QString fileName =
QFileDialog::getSaveFileName(this, tr("Export Model"), sanitizeMdlPath(gearView->getLoadedGearPath()), tr("MDL File (*.mdl)"));
const QString fileName = QFileDialog::getSaveFileName(this,
i18nc("@title:window", "Export Model"),
sanitizeMdlPath(gearView->getLoadedGearPath()),
i18n("MDL File (*.mdl)"));
auto buffer = physis_gamedata_extract_file(data, gearView->getLoadedGearPath().toStdString().c_str());
@ -214,7 +217,7 @@ SingleGearView::SingleGearView(GameData *data, FileCache &cache, QWidget *parent
}
});
exportButton = new QPushButton(QStringLiteral("Export"));
exportButton = new QPushButton(i18nc("@action:button", "Export"));
exportButton->setMenu(testMenu);
exportButton->setIcon(QIcon::fromTheme(QStringLiteral("document-export")));
@ -386,7 +389,7 @@ void SingleGearView::reloadGear()
lodCombo->clear();
for (int i = 0; i < gearView->lodCount(); i++) {
lodCombo->addItem(QStringLiteral("LOD %1").arg(i), i);
lodCombo->addItem(i18nc("@action:inmenu LOD stands for Level of Detail", "LOD %1").arg(i), i);
}
if (oldLod < gearView->lodCount()) {
lodCombo->setCurrentIndex(oldLod);