aboutsummaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
Diffstat (limited to 'core/src')
-rw-r--r--core/src/Entrypoint/main.cpp11
-rw-r--r--core/src/Locale/zh_CN.h83
-rw-r--r--core/src/Model/Assets.cpp37
-rw-r--r--core/src/Model/Template/Template_Main.cpp24
-rw-r--r--core/src/Model/Workflow/Workflow_Main.cpp18
-rw-r--r--core/src/UI/Localization.cpp3
-rw-r--r--core/src/UI/Localization.hpp126
-rw-r--r--core/src/UI/UI_DatabaseView.cpp46
-rw-r--r--core/src/UI/UI_Items.cpp62
-rw-r--r--core/src/UI/UI_MainWindow.cpp65
-rw-r--r--core/src/UI/UI_Settings.cpp2
-rw-r--r--core/src/UI/UI_Templates.cpp20
-rw-r--r--core/src/UI/UI_Workflows.cpp28
-rw-r--r--core/src/UI/fwd.hpp3
-rw-r--r--core/src/Utils/I18n.cpp300
-rw-r--r--core/src/Utils/I18n.hpp91
-rw-r--r--core/src/Utils/Macros.hpp5
-rw-r--r--core/src/Utils/fwd.hpp9
18 files changed, 232 insertions, 701 deletions
diff --git a/core/src/Entrypoint/main.cpp b/core/src/Entrypoint/main.cpp
index d6f2cdf..3cd3862 100644
--- a/core/src/Entrypoint/main.cpp
+++ b/core/src/Entrypoint/main.cpp
@@ -1,6 +1,5 @@
#include "Entrypoint/Backend.hpp"
#include "Model/GlobalStates.hpp"
-#include "UI/Localization.hpp"
#include "UI/UI.hpp"
#include "Utils/I18n.hpp"
#include "Utils/ScopeGuard.hpp"
@@ -140,16 +139,6 @@ int main(int argc, char* argv[])
io.Fonts->AddFontFromFileTTF("fonts/FontAwesome5-Solid.otf", 14, &config, iconRanges);
}
- // Initialize localization utilities
- {
- I18n::OnLanguageChange.Connect([]() { LocaleStrings::Instance = std::make_unique<LocaleStrings>(); });
- // Do i18n initialization after linking reload signals, so that when SetLanguage() is called, the locale strings will be initialized (without us writing the code another time outside the slot)
- I18n::Init();
- I18n::SetLanguage("zh_CN");
- // All of our usage are cached in XxxTranslation objects, no need to keep key -> entry mappings anymore
- I18n::Unload();
- }
-
auto dataDirOption = parser.get<std::string>("--global-data-directory");
if (dataDirOption == "default") {
GlobalStates::Init();
diff --git a/core/src/Locale/zh_CN.h b/core/src/Locale/zh_CN.h
new file mode 100644
index 0000000..478c627
--- /dev/null
+++ b/core/src/Locale/zh_CN.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#define L10N_ERROR "错误"
+#define L10N_ADD "新建"
+#define L10N_EDIT "编辑"
+#define L10N_DELETE "删除"
+#define L10N_RENAME "重命名"
+#define L10N_DISCONNECT "断开连接"
+#define L10N_OPEN "打开"
+#define L10N_CLOSE "关闭"
+#define L10N_CONFIRM "确定"
+#define L10N_CANCEL "取消"
+#define L10N_NAME "名称"
+#define L10N_TYPE "类型"
+
+#define L10N_INVALID_PATH_ERROR "无效路径"
+#define L10N_EMPTY_NAME_ERROR "名称不能为空"
+#define L10N_DUPLICATE_NAME_ERROR "名称已被占用"
+
+#define L10N_MAIN_TAB_SETTINGS "设置"
+#define L10N_MAIN_WINDOW_TAB_PROJECT "项目"
+#define L10N_MAIN_WINDOW_TAB_DATABASE_VIEW "数据"
+#define L10N_MAIN_WINDOW_TAB_ITEMS "物品"
+#define L10N_MAIN_WINDOW_TAB_WORKFLOWS "工作流"
+#define L10N_MAIN_WINDOW_TAB_TEMPLATES "模板"
+
+#define L10N_PROJECT_NEW "新建项目..."
+#define L10N_PROJECT_NEW_DIALOG_TITLE "新建项目向导"
+#define L10N_PROJECT_NAME "项目名称"
+#define L10N_PROJECT_PATH "项目路径"
+#define L10N_PROJECT_NEW_PATH_DIALOG_TITLE "项目路径"
+#define L10N_PROJECT_OPEN "打开项目..."
+#define L10N_PROJECT_OPEN_DIALOG_TITLE "打开项目"
+#define L10N_PROJECT_RECENTS "最近使用"
+#define L10N_PROJECT_RECENTS_CLEAR "清空"
+#define L10N_PROJECT_RECENTS_NONE_PRESENT "(暂无最近使用的项目)"
+#define L10N_PROJECT_RECENTS_OPEN_TOOLTIP "打开该项目"
+#define L10N_PROJECT_RECENTS_DELETE_TOOLTIP "将该项目从最近使用列表中删除,项目本身将不受影响。"
+#define L10N_PROJECT_INVALID_PROJECT_FORMAT "无效的项目文件"
+
+#define L10N_PROJECT_OPEN_IN_FILESYSTEM "在文件系统中打开"
+
+#define L10N_DATABASE_SALES_VIEW_TAB_NAME "销售"
+#define L10N_DATABASE_SALES_VIEW_EDIT_DIALOG_TITLE "编辑销售记录"
+#define L10N_DATABASE_PURCHASES_VIEW_TAB_NAME "采购"
+#define L10N_DATABASE_PURCHASES_VIEW_EDIT_DIALOG_TITLE "编辑采购记录"
+#define L10N_DATABASE_COLUMN_ITEMS "项目"
+#define L10N_DATABASE_COLUMN_CUSTOMER "客户"
+#define L10N_DATABASE_COLUMN_FACTORY "工厂"
+/// 销售订单的交货期限
+#define L10N_DATABASE_COLUMN_DEADLINE "交货期限"
+/// 采购订单的下单时间
+#define L10N_DATABASE_COLUMN_ORDER_TIME "下单时间"
+/// 所有订单的“完成”时间。对于销售来说是实际交货时间,对于采购来说是收货时间。
+#define L10N_DATABASE_COLUMN_COMPLETION_TIME "交货时间"
+/// 运输批次的发货时间,适用于采购和销售批次。
+#define L10N_DATABASE_COLUMN_SHIPMENT_TIME "发货时间"
+/// 运输批次的收获时间,适用于采购和销售批次。
+#define L10N_DATABASE_COLUMN_ARRIVAL_TIME "实际到达时间"
+#define L10N_DATABASE_MESSAGE_NO_ORDER_SELECTED "选择任意一个订单以查看与其相关的批次"
+#define L10N_DATABASE_MESSAGE_NOT_DELIVERED "N/A"
+
+#define L10N_ITEM_ADD_DIALOG_TITLE "新建物品项"
+#define L10N_ITEM_EDIT_DIALOG_TITLE "编辑物品项"
+#define L10N_ITEM_DELETE_DIALOG_TITLE "删除物品项"
+#define L10N_ITEM_DELETE_DIALOG_MESSAGE "确定删除该物品项吗?"
+#define L10N_ITEM_CATEGORY_PRODUCT "产品"
+#define L10N_ITEM_CATEGORY_FACTORY "工厂"
+#define L10N_ITEM_CATEGORY_CUSTOMER "客户"
+#define L10N_ITEM_COLUMN_NAME "名称"
+#define L10N_ITEM_COLUMN_DESCRIPTION "描述"
+#define L10N_ITEM_COLUMN_EMAIL "邮箱"
+#define L10N_ITEM_COLUMN_STOCK "库存"
+#define L10N_ITEM_COLUMN_PRICE "价格"
+
+#define L10N_ASSET_OPEN "打开资源..."
+#define L10N_ASSET_OPEN_DIALOG_TITLE "打开资源"
+#define L10N_ASSET_MANAGE "管理资源..."
+#define L10N_ASSET_MANAGE_DIALOG_TITLE "管理资源"
+#define L10N_ADD_ASSET_DIALOG_TITLE "新建资源向导"
+#define L10N_DELETE_ASSET_DIALOG_TITLE "确认删除资源"
+#define L10N_RENAME_ASSET_DIALOG_TITLE "重命名资源"
+#define L10N_TEMPLATE_INVALID_TYPE_ERROR "无效的模板类型"
diff --git a/core/src/Model/Assets.cpp b/core/src/Model/Assets.cpp
index ac3335a..64e1f22 100644
--- a/core/src/Model/Assets.cpp
+++ b/core/src/Model/Assets.cpp
@@ -1,11 +1,12 @@
#include "Assets.hpp"
-#include "UI/Localization.hpp"
#include "UI/UI.hpp"
+#include "Utils/I18n.hpp"
#include <imgui.h>
#include <imgui_stdlib.h>
#include <tsl/array_map.h>
+#include <IconsFontAwesome.h>
#include <fstream>
#include <string>
#include <utility>
@@ -34,10 +35,10 @@ public:
switch (NewNameError) {
case NameSelectionError::None: break;
case NameSelectionError::Duplicated:
- ImGui::ErrorMessage("Duplicate template name");
+ ImGui::ErrorMessage(I18N_TEXT("Duplicate name", L10N_DUPLICATE_NAME_ERROR));
break;
case NameSelectionError::Empty:
- ImGui::ErrorMessage("Template name cannot be empty");
+ ImGui::ErrorMessage(I18N_TEXT("Name cannot be empty", L10N_EMPTY_NAME_ERROR));
break;
}
}
@@ -189,28 +190,26 @@ void AssetList::DisplayDetailsList(ListState& state)
void AssetList::DisplayControls(ListState& state)
{
auto& ps = mPrivate->PopupPrivateState;
- auto ls = LocaleStrings::Instance.get();
-
bool openedDummy = true;
- if (ImGui::Button(ls->Add.Get())) {
- ImGui::OpenPopup(ls->AddDialogTitle.Get());
+ if (ImGui::Button(ICON_FA_PLUS " " I18N_TEXT("Add", L10N_ADD))) {
+ ImGui::OpenPopup(I18N_TEXT("Add asset wizard", L10N_ADD_ASSET_DIALOG_TITLE));
}
- if (ImGui::BeginPopupModal(ls->AddDialogTitle.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
+ if (ImGui::BeginPopupModal(I18N_TEXT("Add asset wizard", L10N_ADD_ASSET_DIALOG_TITLE), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
DisplayAssetCreator(state);
ImGui::EndPopup();
}
ImGui::SameLine();
- if (ImGui::Button(ls->Rename.Get(), state.SelectedAsset == nullptr)) {
- ImGui::OpenPopup(ls->RenameDialogTitle.Get());
+ if (ImGui::Button(ICON_FA_I_CURSOR " " I18N_TEXT("Rename", L10N_RENAME), state.SelectedAsset == nullptr)) {
+ ImGui::OpenPopup(I18N_TEXT("Rename asset wizard", L10N_RENAME_ASSET_DIALOG_TITLE));
}
- if (ImGui::BeginPopupModal(ls->RenameDialogTitle.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
- if (ImGui::InputText("New name", &ps.NewName)) {
+ if (ImGui::BeginPopupModal(I18N_TEXT("Rename asset wizard", L10N_RENAME_ASSET_DIALOG_TITLE), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
+ if (ImGui::InputText(I18N_TEXT("Name", L10N_NAME), &ps.NewName)) {
ps.Validate(*this);
}
- if (ImGui::Button(ls->Confirm.Get(), ps.HasErrors())) {
+ if (ImGui::Button(I18N_TEXT("Confirm", L10N_CONFIRM), ps.HasErrors())) {
ImGui::CloseCurrentPopup();
auto movedAsset = Rename(state.SelectedAsset->Name, ps.NewName);
@@ -220,7 +219,7 @@ void AssetList::DisplayControls(ListState& state)
ps = {};
}
ImGui::SameLine();
- if (ImGui::Button(ls->Cancel.Get())) {
+ if (ImGui::Button(I18N_TEXT("Cancel", L10N_CANCEL))) {
ImGui::CloseCurrentPopup();
}
@@ -230,11 +229,11 @@ void AssetList::DisplayControls(ListState& state)
}
ImGui::SameLine();
- if (ImGui::Button(ls->Delete.Get(), state.SelectedAsset == nullptr)) {
- ImGui::OpenPopup(ls->DeleteDialogTitle.Get());
+ if (ImGui::Button(ICON_FA_TRASH " " I18N_TEXT("Delete", L10N_DELETE), state.SelectedAsset == nullptr)) {
+ ImGui::OpenPopup(I18N_TEXT("Delete asset", L10N_DELETE_ASSET_DIALOG_TITLE));
}
- if (ImGui::BeginPopupModal(ls->DeleteDialogTitle.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
- if (ImGui::Button(ls->Confirm.Get())) {
+ if (ImGui::BeginPopupModal(I18N_TEXT("Delete asset", L10N_DELETE_ASSET_DIALOG_TITLE), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
+ if (ImGui::Button(I18N_TEXT("Confirm", L10N_CONFIRM))) {
ImGui::CloseCurrentPopup();
auto& assetName = state.SelectedAsset->Name;
@@ -243,7 +242,7 @@ void AssetList::DisplayControls(ListState& state)
state.SelectedAsset = nullptr;
}
ImGui::SameLine();
- if (ImGui::Button(ls->Cancel.Get())) {
+ if (ImGui::Button(I18N_TEXT("Cancel", L10N_CANCEL))) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
diff --git a/core/src/Model/Template/Template_Main.cpp b/core/src/Model/Template/Template_Main.cpp
index 7d1b755..7dd5f87 100644
--- a/core/src/Model/Template/Template_Main.cpp
+++ b/core/src/Model/Template/Template_Main.cpp
@@ -2,7 +2,7 @@
#include "Model/GlobalStates.hpp"
#include "Model/Project.hpp"
-#include "UI/Localization.hpp"
+#include "Utils/I18n.hpp"
#include "UI/UI.hpp"
#include "Utils/UUID.hpp"
@@ -91,8 +91,6 @@ Template* TemplateAssetList::LoadImpl(const SavedAsset& asset) const
void TemplateAssetList::DisplayAssetCreator(ListState& state)
{
- auto ls = LocaleStrings::Instance.get();
-
auto ValidateNewName = [&]() -> void {
if (mACNewName.empty()) {
mACNewNameError = NameSelectionError::Empty;
@@ -111,17 +109,17 @@ void TemplateAssetList::DisplayAssetCreator(ListState& state)
switch (mACNewNameError) {
case NameSelectionError::None: break;
case NameSelectionError::Duplicated:
- ImGui::ErrorMessage(ls->DuplicateNameError.Get());
+ ImGui::ErrorMessage(I18N_TEXT("Duplicate name", L10N_DUPLICATE_NAME_ERROR));
break;
case NameSelectionError::Empty:
- ImGui::ErrorMessage(ls->EmptyNameError.Get());
+ ImGui::ErrorMessage(I18N_TEXT("Name cannot be empty", L10N_EMPTY_NAME_ERROR));
break;
}
};
auto ShowNewKindErrors = [&]() -> void {
if (mACNewKind == Template::InvalidKind) {
- ImGui::ErrorMessage(ls->InvalidTemplateTypeError.Get());
+ ImGui::ErrorMessage(I18N_TEXT("Invalid template type", L10N_TEMPLATE_INVALID_TYPE_ERROR));
}
};
@@ -136,11 +134,11 @@ void TemplateAssetList::DisplayAssetCreator(ListState& state)
ValidateNewName();
};
- if (ImGui::InputText(ls->Name.Get(), &mACNewName)) {
+ if (ImGui::InputText(I18N_TEXT("Name", L10N_NAME), &mACNewName)) {
ValidateNewName();
}
- if (ImGui::BeginCombo(ls->Type.Get(), Template::FormatKind(mACNewKind))) {
+ if (ImGui::BeginCombo(I18N_TEXT("Type", L10N_TYPE), Template::FormatKind(mACNewKind))) {
for (int i = 0; i < Template::KindCount; ++i) {
auto kind = static_cast<Template::Kind>(i);
if (ImGui::Selectable(Template::FormatKind(kind), mACNewKind == kind)) {
@@ -153,7 +151,7 @@ void TemplateAssetList::DisplayAssetCreator(ListState& state)
ShowNewNameErrors();
ShowNewKindErrors();
- if (ImGui::Button(ls->Confirm.Get(), !IsInputValid())) {
+ if (ImGui::Button(I18N_TEXT("OK", L10N_CONFIRM), !IsInputValid())) {
ImGui::CloseCurrentPopup();
Create(SavedAsset{
@@ -163,19 +161,17 @@ void TemplateAssetList::DisplayAssetCreator(ListState& state)
ResetState();
}
ImGui::SameLine();
- if (ImGui::Button(ls->Cancel.Get())) {
+ if (ImGui::Button(I18N_TEXT("Cancel", L10N_CANCEL))) {
ImGui::CloseCurrentPopup();
}
}
void TemplateAssetList::SetupDetailsTable(const char* tableId) const
{
- auto ls = LocaleStrings::Instance.get();
-
ImGui::BeginTable(tableId, 2, ImGuiTableFlags_Borders);
- ImGui::TableSetupColumn(ls->Name.Get());
- ImGui::TableSetupColumn(ls->Type.Get());
+ ImGui::TableSetupColumn(I18N_TEXT("Name", L10N_NAME));
+ ImGui::TableSetupColumn(I18N_TEXT("Type", L10N_TYPE));
ImGui::TableHeadersRow();
}
diff --git a/core/src/Model/Workflow/Workflow_Main.cpp b/core/src/Model/Workflow/Workflow_Main.cpp
index a01ab7b..adf944e 100644
--- a/core/src/Model/Workflow/Workflow_Main.cpp
+++ b/core/src/Model/Workflow/Workflow_Main.cpp
@@ -2,9 +2,9 @@
#include "Model/GlobalStates.hpp"
#include "Model/Project.hpp"
-#include "UI/Localization.hpp"
#include "UI/UI.hpp"
#include "Utils/UUID.hpp"
+#include "Utils/I18n.hpp"
#include <imgui.h>
#include <imgui_node_editor.h>
@@ -804,8 +804,6 @@ Workflow* WorkflowAssetList::LoadImpl(const SavedAsset& asset) const
void WorkflowAssetList::DisplayAssetCreator(ListState& state)
{
- auto ls = LocaleStrings::Instance.get();
-
auto ValidateNewName = [&]() -> void {
if (mACNewName.empty()) {
mACNewNameError = NameSelectionError::Empty;
@@ -824,10 +822,10 @@ void WorkflowAssetList::DisplayAssetCreator(ListState& state)
switch (mACNewNameError) {
case NameSelectionError::None: break;
case NameSelectionError::Duplicated:
- ImGui::ErrorMessage(ls->DuplicateNameError.Get());
+ ImGui::ErrorMessage(I18N_TEXT("Duplicate name", L10N_DUPLICATE_NAME_ERROR));
break;
case NameSelectionError::Empty:
- ImGui::ErrorMessage(ls->EmptyNameError.Get());
+ ImGui::ErrorMessage(I18N_TEXT("Name cannot be empty", L10N_EMPTY_NAME_ERROR));
break;
}
};
@@ -841,13 +839,13 @@ void WorkflowAssetList::DisplayAssetCreator(ListState& state)
ValidateNewName();
};
- if (ImGui::InputText(ls->Name.Get(), &mACNewName)) {
+ if (ImGui::InputText(I18N_TEXT("Name", L10N_NAME), &mACNewName)) {
ValidateNewName();
}
ShowNewNameErrors();
- if (ImGui::Button(ls->Confirm.Get(), !IsInputValid())) {
+ if (ImGui::Button(I18N_TEXT("OK", L10N_CONFIRM), !IsInputValid())) {
ImGui::CloseCurrentPopup();
Create(SavedAsset{
@@ -856,18 +854,16 @@ void WorkflowAssetList::DisplayAssetCreator(ListState& state)
ResetState();
}
ImGui::SameLine();
- if (ImGui::Button(ls->Cancel.Get())) {
+ if (ImGui::Button(I18N_TEXT("Cancel", L10N_CANCEL))) {
ImGui::CloseCurrentPopup();
}
}
void WorkflowAssetList::SetupDetailsTable(const char* tableId) const
{
- auto ls = LocaleStrings::Instance.get();
-
ImGui::BeginTable(tableId, 1, ImGuiTableFlags_Borders);
- ImGui::TableSetupColumn(ls->Name.Get());
+ ImGui::TableSetupColumn(I18N_TEXT("Name", L10N_NAME));
ImGui::TableHeadersRow();
}
diff --git a/core/src/UI/Localization.cpp b/core/src/UI/Localization.cpp
deleted file mode 100644
index 220df6f..0000000
--- a/core/src/UI/Localization.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "Localization.hpp"
-
-std::unique_ptr<LocaleStrings> LocaleStrings::Instance{};
diff --git a/core/src/UI/Localization.hpp b/core/src/UI/Localization.hpp
deleted file mode 100644
index 3474053..0000000
--- a/core/src/UI/Localization.hpp
+++ /dev/null
@@ -1,126 +0,0 @@
-#pragma once
-
-#include "Utils/I18n.hpp"
-
-#include <memory>
-#include <string_view>
-
-using namespace std::literals::string_view_literals;
-
-class LocaleStrings
-{
-public:
- static std::unique_ptr<LocaleStrings> Instance;
-
-public:
- /* Generic */
-
- BasicTranslation Error{ "Generic.Error"sv };
- BasicTranslation Add{ "Generic.Add"sv };
- BasicTranslation Edit{ "Generic.Edit"sv };
- BasicTranslation Delete{ "Generic.Delete"sv };
- BasicTranslation Rename{ "Generic.Rename"sv };
- BasicTranslation Disconnect{ "Generic.Disconnect"sv };
- BasicTranslation Open{ "Generic.Open"sv };
- BasicTranslation Close{ "Generic.Close"sv };
- BasicTranslation Confirm{ "Generic.Confirm"sv };
- BasicTranslation Cancel{ "Generic.Cancel"sv };
- BasicTranslation Name{ "Generic.Name"sv };
- BasicTranslation Type{ "Generic.Type"sv };
-
- BasicTranslation AddDialogTitle{ "Generic.Add.DialogTitle"sv };
- BasicTranslation DeleteDialogTitle{ "Generic.Delete.DialogTitle"sv };
- BasicTranslation RenameDialogTitle{ "Generic.Rename.DialogTitle"sv };
-
- BasicTranslation EmptyNameError{ "Generic.EmptyNameError"sv };
- BasicTranslation DuplicateNameError{ "Generic.DuplicateNameError"sv };
-
- /* Main window */
-
- BasicTranslation SettingsTab{ "MainWindow.Tab.Settings"sv };
- BasicTranslation ProjectTab{ "MainWindow.Tab.Project"sv };
- BasicTranslation DatabaseViewTab{ "MainWindow.Tab.DatabaseView"sv };
- BasicTranslation ItemsTab{ "MainWindow.Tab.Items"sv };
- BasicTranslation WorkflowsTab{ "MainWindow.Tab.Workflows"sv };
- BasicTranslation TemplatesTab{ "MainWindow.Tab.Templates"sv };
-
- /* Project tab */
-
- BasicTranslation NewProject{ "Project.New"sv };
- BasicTranslation NewProjectDialogTitle{ "Project.New.DialogTitle"sv };
- BasicTranslation NewProjectNameHint{ "Project.New.Name"sv };
- BasicTranslation NewProjectPathHint{ "Project.New.Path"sv };
- BasicTranslation NewProjectPathDialogTitle{ "Project.New.Path.DialogTitle"sv };
- BasicTranslation NewProjectEmptyNameError{ "Project.New.EmptyNameError"sv };
- BasicTranslation NewProjectInvalidPathError{ "Project.New.InvalidPathError"sv };
-
- BasicTranslation OpenProject{ "Project.Open"sv };
- BasicTranslation OpenProjectDialogTitle{ "Project.Open.DialogTitle"sv };
-
- BasicTranslation RecentProjects{ "Project.Recents"sv };
- BasicTranslation ClearRecentProjects{ "Project.Recents.Clear"sv };
- BasicTranslation NoRecentProjectsMessage{ "Project.Recents.NonePresent"sv };
- BasicTranslation OpenRecentProjectTooltip{ "Project.Recents.Open.Tooltip"sv };
- BasicTranslation DeleteRecentProjectTooltip{ "Project.Recents.Delete.Tooltip"sv };
-
- BasicTranslation InvalidProjectFormat{ "Project.InvalidProjectFormat"sv };
-
- BasicTranslation OpenActiveProjectInFileSystem{ "ActiveProject.OpenInFilesystem"sv };
- BasicTranslation ActiveProjectName{ "ActiveProject.Info.Name"sv };
- BasicTranslation ActiveProjectPath{ "ActiveProject.Info.Path"sv };
-
- /* Database view tab */
-
- BasicTranslation SalesViewTab{ "Database.SalesView.TabName"sv };
- BasicTranslation EditSaleEntryDialogTitle{ "Database.SalesView.Edit.DialogTitle"sv };
-
- BasicTranslation PurchasesViewTab{ "Database.PurchasesView.TabName"sv };
- BasicTranslation EditPurchaseEntryDialogTitle{ "Database.PurchasesView.Edit.DialogTitle"sv };
-
- BasicTranslation DatabaseItemsColumn{ "Database.Column.Items"sv };
- BasicTranslation DatabaseCustomerColumn{ "Database.Column.Customer"sv };
- BasicTranslation DatabaseFactoryColumn{ "Database.Column.Factory"sv };
- /// 销售订单的交货期限
- BasicTranslation DatabaseDeadlineColumn{ "Database.Column.Deadline"sv };
- /// 采购订单的下单时间
- BasicTranslation DatabaseOrderTimeColumn{ "Database.Column.OrderTime"sv };
- /// 所有订单的“完成”时间。对于销售来说是实际交货时间,对于采购来说是收货时间。
- BasicTranslation DatabaseCompletionTimeColumn{ "Database.Column.CompletionTime"sv };
- /// (运输)批次的发货时间,适用于采购和销售批次。
- BasicTranslation DatabaseShipmentTimeColumn{ "Database.Column.ShipmentTime"sv };
- /// (运输)批次的收获时间,适用于采购和销售批次。
- BasicTranslation DatabaseArrivalTimeColumn{ "Database.Column.ArrivalTime"sv };
-
- BasicTranslation SelectOrderToShowAssociatedDeliveries{ "Database.Message.NoOrderSelected"sv };
- BasicTranslation NotDelivered{ "Database.Message.NotDelivered"sv };
-
- /* Items tab */
-
- BasicTranslation AddItemDialogTitle{ "Item.Add.DialogTitle"sv };
- BasicTranslation EditItemDialogTitle{ "Item.Edit.DialogTitle"sv };
- BasicTranslation DeleteItemDialogTitle{ "Item.Delete.DialogTitle"sv };
- BasicTranslation DeleteItemDialogMessage{ "Item.Delete.DialogMessage"sv };
-
- BasicTranslation ProductCategoryName{ "Item.CategoryName.Product"sv };
- BasicTranslation FactoryCategoryName{ "Item.CategoryName.Factory"sv };
- BasicTranslation CustomerCategoryName{ "Item.CategoryName.Customer"sv };
-
- BasicTranslation ItemNameColumn{ "Item.Column.Name"sv };
- BasicTranslation ItemDescriptionColumn{ "Item.Column.Description"sv };
- BasicTranslation ItemEmailColumn{ "Item.Column.Email"sv };
- BasicTranslation ItemStockColumn{ "Item.Column.Stock"sv };
- BasicTranslation ItemPriceColumn{ "Item.Column.Price"sv };
-
- /* Assets */
-
- BasicTranslation OpenAsset{ "Asset.Open"sv };
- BasicTranslation OpenAssetDialogTitle{ "Asset.Open.DialogTitle"sv };
- BasicTranslation ManageAssets{ "Asset.Manage"sv };
- BasicTranslation ManageAssetsDialogTitle{ "Asset.Manage.DialogTitle"sv };
-
- /* Workflow tab */
-
- /* Templates tab */
-
- BasicTranslation InvalidTemplateTypeError{ "Template.InvalidTypeError"sv };
-};
diff --git a/core/src/UI/UI_DatabaseView.cpp b/core/src/UI/UI_DatabaseView.cpp
index bd0efa5..caf81d8 100644
--- a/core/src/UI/UI_DatabaseView.cpp
+++ b/core/src/UI/UI_DatabaseView.cpp
@@ -3,7 +3,7 @@
#include "Model/Filter.hpp"
#include "Model/GlobalStates.hpp"
#include "Model/Project.hpp"
-#include "UI/Localization.hpp"
+#include "Utils/I18n.hpp"
#include "Utils/ScopeGuard.hpp"
#include "Utils/Time.hpp"
@@ -210,7 +210,6 @@ public:
void Display()
{
bool dummy = true;
- auto ls = LocaleStrings::Instance.get();
if (ImGui::Button(ICON_FA_ARROW_LEFT, mCurrentPageNumber == 0)) {
SetPage(mCurrentPageNumber - 1);
@@ -226,7 +225,7 @@ public:
}
ImGui::SameLine();
- if (ImGui::Button(ls->Edit.Get(), mSelectRow == -1)) {
+ if (ImGui::Button(ICON_FA_EDIT " " I18N_TEXT("Edit", L10N_EDIT), mSelectRow == -1)) {
ImGui::OpenPopup(mEditDialogTitle);
}
if (ImGui::BeginPopupModal(mEditDialogTitle, &dummy, ImGuiWindowFlags_AlwaysAutoResize)) {
@@ -237,12 +236,12 @@ public:
}
ImGui::SameLine();
- if (ImGui::Button(ls->Add.Get())) {
+ if (ImGui::Button(ICON_FA_PLUS " " I18N_TEXT("Add", L10N_ADD))) {
// TODO
}
ImGui::SameLine();
- if (ImGui::Button(ls->Delete.Get(), mSelectRow == -1)) {
+ if (ImGui::Button(ICON_FA_TRASH " " I18N_TEXT("Delete", L10N_DELETE), mSelectRow == -1)) {
// TODO
}
@@ -252,7 +251,7 @@ public:
ImGui::NextColumn();
if (mSelectRow == -1) {
- ImGui::TextWrapped("%s", ls->SelectOrderToShowAssociatedDeliveries.Get());
+ ImGui::TextWrapped("%s", I18N_TEXT("Select an entry to show associated deliveries", L10N_DATABASE_MESSAGE_NO_ORDER_SELECTED));
} else {
DisplayDeliveriesTable();
}
@@ -284,15 +283,14 @@ private:
void DisplayMainTable()
{
- auto ls = LocaleStrings::Instance.get();
if (ImGui::BeginTable("DataTable", kColumnCount, ImGuiTableFlags_Borders | ImGuiTableFlags_ScrollX)) {
- if constexpr (kHasCustomer) ImGui::TableSetupColumn(ls->DatabaseCustomerColumn.Get());
- if constexpr (kHasDeadline) ImGui::TableSetupColumn(ls->DatabaseDeadlineColumn.Get());
- if constexpr (kHasFactory) ImGui::TableSetupColumn(ls->DatabaseFactoryColumn.Get());
- if constexpr (kHasOrderTime) ImGui::TableSetupColumn(ls->DatabaseOrderTimeColumn.Get());
- if constexpr (kHasCompletionTime) ImGui::TableSetupColumn(ls->DatabaseCompletionTimeColumn.Get());
- if constexpr (kHasItems) ImGui::TableSetupColumn(ls->DatabaseItemsColumn.Get());
+ if constexpr (kHasCustomer) ImGui::TableSetupColumn(I18N_TEXT("Customer", L10N_DATABASE_COLUMN_CUSTOMER));
+ if constexpr (kHasDeadline) ImGui::TableSetupColumn(I18N_TEXT("Deadline", L10N_DATABASE_COLUMN_DEADLINE));
+ if constexpr (kHasFactory) ImGui::TableSetupColumn(I18N_TEXT("Factory", L10N_DATABASE_COLUMN_FACTORY));
+ if constexpr (kHasOrderTime) ImGui::TableSetupColumn(I18N_TEXT("Order time", L10N_DATABASE_COLUMN_ORDER_TIME));
+ if constexpr (kHasCompletionTime) ImGui::TableSetupColumn(I18N_TEXT("Completion time", L10N_DATABASE_COLUMN_COMPLETION_TIME));
+ if constexpr (kHasItems) ImGui::TableSetupColumn(I18N_TEXT("Items", L10N_DATABASE_COLUMN_ITEMS));
ImGui::TableHeadersRow();
if (mActiveFilter) {
@@ -327,8 +325,6 @@ private:
void DisplayEntry(T& entry, int rowIdx, int entryIdx)
{
- auto ls = LocaleStrings::Instance.get();
-
ImGui::PushID(rowIdx);
ImGui::TableNextRow();
@@ -359,7 +355,7 @@ private:
if constexpr (kHasCompletionTime) {
ImGui::TableNextColumn();
if (entry.DeliveryTime.empty()) {
- ImGui::TextUnformatted(ls->NotDelivered.Get());
+ ImGui::TextUnformatted(I18N_TEXT("Not delivered", L10N_DATABASE_MESSAGE_NOT_DELIVERED));
} else {
ImGui::TextUnformatted(entry.DeliveryTime.c_str());
}
@@ -383,12 +379,11 @@ private:
void DisplayDeliveriesTable()
{
- auto ls = LocaleStrings::Instance.get();
if (ImGui::BeginTable("DeliveriesTable", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_ScrollX)) {
- ImGui::TableSetupColumn(ls->DatabaseShipmentTimeColumn.Get());
- ImGui::TableSetupColumn(ls->DatabaseArrivalTimeColumn.Get());
- ImGui::TableSetupColumn(ls->DatabaseItemsColumn.Get());
+ ImGui::TableSetupColumn(I18N_TEXT("Shipment time", L10N_DATABASE_COLUMN_SHIPMENT_TIME));
+ ImGui::TableSetupColumn(I18N_TEXT("Arrival time", L10N_DATABASE_COLUMN_ARRIVAL_TIME));
+ ImGui::TableSetupColumn(I18N_TEXT("Items", L10N_DATABASE_COLUMN_ITEMS));
ImGui::TableHeadersRow();
auto& entry = (*mCurrentPage)[mSelectRow];
@@ -601,8 +596,7 @@ class SalesTableView : public GenericTableView<SaleEntry>
public:
SalesTableView()
{
- auto ls = LocaleStrings::Instance.get();
- mEditDialogTitle = ls->EditSaleEntryDialogTitle.Get();
+ mEditDialogTitle = I18N_TEXT("Edit sales entry", L10N_DATABASE_SALES_VIEW_EDIT_DIALOG_TITLE);
}
#pragma clang diagnostic push
@@ -626,8 +620,7 @@ class PurchasesTableView : public GenericTableView<PurchaseEntry>
public:
PurchasesTableView()
{
- auto ls = LocaleStrings::Instance.get();
- mEditDialogTitle = ls->EditPurchaseEntryDialogTitle.Get();
+ mEditDialogTitle = I18N_TEXT("Edit purchase entry", L10N_DATABASE_PURCHASES_VIEW_EDIT_DIALOG_TITLE);
}
#pragma clang diagnostic push
@@ -649,7 +642,6 @@ public:
void UI::DatabaseViewTab()
{
- auto ls = LocaleStrings::Instance.get();
auto& gs = GlobalStates::GetInstance();
static Project* currentProject = nullptr;
@@ -663,11 +655,11 @@ void UI::DatabaseViewTab()
}
if (ImGui::BeginTabBar("DatabaseViewTabs")) {
- if (ImGui::BeginTabItem(ls->SalesViewTab.Get())) {
+ if (ImGui::BeginTabItem(I18N_TEXT("Sales", L10N_DATABASE_SALES_VIEW_TAB_NAME))) {
sales.Display();
ImGui::EndTabItem();
}
- if (ImGui::BeginTabItem(ls->PurchasesViewTab.Get())) {
+ if (ImGui::BeginTabItem(I18N_TEXT("Purchases", L10N_DATABASE_PURCHASES_VIEW_TAB_NAME))) {
purchases.Display();
ImGui::EndTabItem();
}
diff --git a/core/src/UI/UI_Items.cpp b/core/src/UI/UI_Items.cpp
index 6887f23..a557eb4 100644
--- a/core/src/UI/UI_Items.cpp
+++ b/core/src/UI/UI_Items.cpp
@@ -2,8 +2,9 @@
#include "Model/GlobalStates.hpp"
#include "Model/Project.hpp"
-#include "UI/Localization.hpp"
+#include "Utils/I18n.hpp"
+#include <IconsFontAwesome.h>
#include <imgui.h>
#include <imgui_stdlib.h>
@@ -30,7 +31,6 @@ ActionResult ItemEditor(ItemList<T>& list, T* item)
t.GetEmail();
};
- auto ls = LocaleStrings::Instance.get();
auto& gs = GlobalStates::GetInstance();
static bool duplicateName = false;
@@ -50,23 +50,23 @@ ActionResult ItemEditor(ItemList<T>& list, T* item)
description = {};
};
- if (ImGui::InputText(ls->ItemNameColumn.Get(), &name)) {
+ if (ImGui::InputText(I18N_TEXT("Name", L10N_ITEM_COLUMN_NAME), &name)) {
duplicateName = name != item->GetName() && list.Find(name) != nullptr;
}
- if constexpr (kHasDescription) ImGui::InputText(ls->ItemDescriptionColumn.Get(), &description);
- if constexpr (kHasEmail) ImGui::InputText(ls->ItemEmailColumn.Get(), &email);
+ if constexpr (kHasDescription) ImGui::InputText(I18N_TEXT("Description", L10N_ITEM_COLUMN_DESCRIPTION), &description);
+ if constexpr (kHasEmail) ImGui::InputText(I18N_TEXT("Email", L10N_ITEM_COLUMN_EMAIL), &email);
if (name.empty()) {
- ImGui::ErrorMessage("%s", ls->EmptyNameError.Get());
+ ImGui::ErrorMessage(I18N_TEXT("Name cannot be empty", L10N_EMPTY_NAME_ERROR));
}
if (duplicateName) {
- ImGui::ErrorMessage("%s", ls->DuplicateNameError.Get());
+ ImGui::ErrorMessage(I18N_TEXT("Duplicate name", L10N_DUPLICATE_NAME_ERROR));
}
// Return Value
auto rv = ActionResult::Pending;
- if (ImGui::Button(ls->Confirm.Get(), name.empty() || duplicateName)) {
+ if (ImGui::Button(I18N_TEXT("Confirm", L10N_CONFIRM), name.empty() || duplicateName)) {
if (item->GetName() != name) {
item->SetName(std::move(name));
}
@@ -85,7 +85,7 @@ ActionResult ItemEditor(ItemList<T>& list, T* item)
}
ImGui::SameLine();
- if (ImGui::Button(ls->Cancel.Get())) {
+ if (ImGui::Button(I18N_TEXT("Cancel", L10N_CANCEL))) {
ImGui::CloseCurrentPopup();
ClearStates();
rv = ActionResult::Canceled;
@@ -115,16 +115,15 @@ void ItemListEntries(ItemList<T>& list, int& selectedIdx)
};
constexpr int kColumns = 1 /* Name column */ + kHasDescription + kHasEmail + kHasStock + kHasPrice;
- auto ls = LocaleStrings::Instance.get();
auto& gs = GlobalStates::GetInstance();
if (ImGui::BeginTable("", kColumns, ImGuiTableFlags_Borders)) {
- ImGui::TableSetupColumn(ls->ItemNameColumn.Get());
- if constexpr (kHasDescription) ImGui::TableSetupColumn(ls->ItemDescriptionColumn.Get());
- if constexpr (kHasEmail) ImGui::TableSetupColumn(ls->ItemEmailColumn.Get());
- if constexpr (kHasStock) ImGui::TableSetupColumn(ls->ItemStockColumn.Get());
- if constexpr (kHasPrice) ImGui::TableSetupColumn(ls->ItemPriceColumn.Get());
+ ImGui::TableSetupColumn(I18N_TEXT("Name", L10N_ITEM_COLUMN_NAME));
+ if constexpr (kHasDescription) ImGui::TableSetupColumn(I18N_TEXT("Description", L10N_ITEM_COLUMN_DESCRIPTION));
+ if constexpr (kHasEmail) ImGui::TableSetupColumn(I18N_TEXT("Email", L10N_ITEM_COLUMN_EMAIL));
+ if constexpr (kHasStock) ImGui::TableSetupColumn(I18N_TEXT("Stock", L10N_ITEM_COLUMN_STOCK));
+ if constexpr (kHasPrice) ImGui::TableSetupColumn(I18N_TEXT("Price", L10N_ITEM_COLUMN_PRICE));
ImGui::TableHeadersRow();
size_t idx = 0;
@@ -170,19 +169,17 @@ void ItemListEntries(ItemList<T>& list, int& selectedIdx)
template <class T>
void ItemListEditor(ItemList<T>& list)
{
- auto ls = LocaleStrings::Instance.get();
-
bool opened = true;
static int selectedIdx = -1;
static T* editingItem = nullptr;
- if (ImGui::Button(ls->Add.Get())) {
+ if (ImGui::Button(ICON_FA_PLUS " " I18N_TEXT("Add", L10N_ADD))) {
ImGui::SetNextWindowCentered();
- ImGui::OpenPopup(ls->AddItemDialogTitle.Get());
+ ImGui::OpenPopup(I18N_TEXT("Add item", L10N_ITEM_ADD_DIALOG_TITLE));
editingItem = &list.Insert("");
}
- if (ImGui::BeginPopupModal(ls->AddItemDialogTitle.Get(), &opened, ImGuiWindowFlags_AlwaysAutoResize)) {
+ if (ImGui::BeginPopupModal(I18N_TEXT("Add item", L10N_ITEM_ADD_DIALOG_TITLE), &opened, ImGuiWindowFlags_AlwaysAutoResize)) {
switch (ItemEditor(list, editingItem)) {
case ActionResult::Confirmed:
editingItem = nullptr;
@@ -198,13 +195,13 @@ void ItemListEditor(ItemList<T>& list)
}
ImGui::SameLine();
- if (ImGui::Button(ls->Edit.Get(), selectedIdx == -1)) {
+ if (ImGui::Button(ICON_FA_EDIT " " I18N_TEXT("Edit", L10N_EDIT), selectedIdx == -1)) {
ImGui::SetNextWindowCentered();
- ImGui::OpenPopup(ls->EditItemDialogTitle.Get());
+ ImGui::OpenPopup(I18N_TEXT("Edit item", L10N_ITEM_EDIT_DIALOG_TITLE));
editingItem = list.Find(selectedIdx);
}
- if (ImGui::BeginPopupModal(ls->EditItemDialogTitle.Get(), &opened, ImGuiWindowFlags_AlwaysAutoResize)) {
+ if (ImGui::BeginPopupModal(I18N_TEXT("Edit item", L10N_ITEM_EDIT_DIALOG_TITLE), &opened, ImGuiWindowFlags_AlwaysAutoResize)) {
if (ItemEditor(list, editingItem) != ActionResult::Pending) {
editingItem = nullptr;
}
@@ -212,21 +209,21 @@ void ItemListEditor(ItemList<T>& list)
}
ImGui::SameLine();
- if (ImGui::Button(ls->Delete.Get(), selectedIdx == -1)) {
+ if (ImGui::Button(ICON_FA_TRASH " " I18N_TEXT("Delete", L10N_DELETE), selectedIdx == -1)) {
ImGui::SetNextWindowCentered();
- ImGui::OpenPopup(ls->DeleteItemDialogTitle.Get());
+ ImGui::OpenPopup(I18N_TEXT("Delete item", L10N_ITEM_DELETE_DIALOG_TITLE));
list.Remove(selectedIdx);
}
- if (ImGui::BeginPopupModal(ls->DeleteItemDialogTitle.Get(), &opened, ImGuiWindowFlags_AlwaysAutoResize)) {
- ImGui::TextUnformatted(ls->DeleteItemDialogMessage.Get());
+ if (ImGui::BeginPopupModal(I18N_TEXT("Delete item", L10N_ITEM_DELETE_DIALOG_TITLE), &opened, ImGuiWindowFlags_AlwaysAutoResize)) {
+ ImGui::TextUnformatted(I18N_TEXT("Are you sure you want to delete this item?", L10N_ITEM_DELETE_DIALOG_MESSAGE));
- if (ImGui::Button(ls->Confirm.Get())) {
+ if (ImGui::Button(I18N_TEXT("Confirm", L10N_CONFIRM))) {
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
- if (ImGui::Button(ls->Cancel.Get())) {
+ if (ImGui::Button(I18N_TEXT("Cancel", L10N_CANCEL))) {
ImGui::CloseCurrentPopup();
}
@@ -239,19 +236,18 @@ void ItemListEditor(ItemList<T>& list)
void UI::ItemsTab()
{
- auto ls = LocaleStrings::Instance.get();
auto& gs = GlobalStates::GetInstance();
if (ImGui::BeginTabBar("ItemViewTabs")) {
- if (ImGui::BeginTabItem(ls->ProductCategoryName.Get())) {
+ if (ImGui::BeginTabItem(I18N_TEXT("Products", L10N_ITEM_CATEGORY_PRODUCT))) {
ItemListEditor(gs.GetCurrentProject()->Products);
ImGui::EndTabItem();
}
- if (ImGui::BeginTabItem(ls->FactoryCategoryName.Get())) {
+ if (ImGui::BeginTabItem(I18N_TEXT("Factories", L10N_ITEM_CATEGORY_FACTORY))) {
ItemListEditor(gs.GetCurrentProject()->Factories);
ImGui::EndTabItem();
}
- if (ImGui::BeginTabItem(ls->CustomerCategoryName.Get())) {
+ if (ImGui::BeginTabItem(I18N_TEXT("Customers", L10N_ITEM_CATEGORY_CUSTOMER))) {
ItemListEditor(gs.GetCurrentProject()->Customers);
ImGui::EndTabItem();
}
diff --git a/core/src/UI/UI_MainWindow.cpp b/core/src/UI/UI_MainWindow.cpp
index 8131508..ce6e2e0 100644
--- a/core/src/UI/UI_MainWindow.cpp
+++ b/core/src/UI/UI_MainWindow.cpp
@@ -2,7 +2,7 @@
#include "Model/GlobalStates.hpp"
#include "Model/Project.hpp"
-#include "UI/Localization.hpp"
+#include "Utils/I18n.hpp"
#include <IconsFontAwesome.h>
#include <imgui.h>
@@ -16,25 +16,23 @@ namespace fs = std::filesystem;
namespace {
void ProjectTab_Normal()
{
- auto ls = LocaleStrings::Instance.get();
auto& gs = GlobalStates::GetInstance();
- if (ImGui::Button(ls->Close.Get())) {
+ if (ImGui::Button(ICON_FA_TIMES " " I18N_TEXT("Close", L10N_CLOSE))) {
gs.SetCurrentProject(nullptr);
return;
}
ImGui::SameLine();
- if (ImGui::Button(ls->OpenActiveProjectInFileSystem.Get())) {
+ if (ImGui::Button(ICON_FA_FOLDER " " I18N_TEXT("Open in filesystem", L10N_PROJECT_OPEN_IN_FILESYSTEM))) {
// TODO
}
- ImGui::Text("%s%s", ls->ActiveProjectName.Get(), gs.GetCurrentProject()->GetName().c_str());
- ImGui::Text("%s%s", ls->ActiveProjectPath.Get(), gs.GetCurrentProject()->GetPathString().c_str());
+ ImGui::Text("%s %s", I18N_TEXT("Project name", L10N_PROJECT_NAME), gs.GetCurrentProject()->GetName().c_str());
+ ImGui::Text("%s %s", I18N_TEXT("Project path", L10N_PROJECT_PATH), gs.GetCurrentProject()->GetPathString().c_str());
}
void ProjectTab_NoProject()
{
- auto ls = LocaleStrings::Instance.get();
auto& gs = GlobalStates::GetInstance();
bool openedDummy = true;
@@ -54,37 +52,37 @@ void ProjectTab_NoProject()
}
};
- if (ImGui::Button(ls->NewProject.Get())) {
+ if (ImGui::Button(I18N_TEXT("Create project....", L10N_PROJECT_NEW))) {
ImGui::SetNextWindowCentered();
- ImGui::OpenPopup(ls->NewProjectDialogTitle.Get());
+ ImGui::OpenPopup(I18N_TEXT("Create project wizard", L10N_PROJECT_NEW_DIALOG_TITLE));
}
// Make it so that the modal dialog has a close button
- if (ImGui::BeginPopupModal(ls->NewProjectDialogTitle.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
- ImGui::InputTextWithHint("##ProjectName", ls->NewProjectNameHint.Get(), &projectName);
+ if (ImGui::BeginPopupModal(I18N_TEXT("Create project wizard", L10N_PROJECT_NEW_DIALOG_TITLE), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
+ ImGui::InputTextWithHint("##ProjectName", I18N_TEXT("Project name", L10N_PROJECT_NAME), &projectName);
- if (ImGui::InputTextWithHint("##ProjectPath", ls->NewProjectPathHint.Get(), &dirName)) {
+ if (ImGui::InputTextWithHint("##ProjectPath", I18N_TEXT("Project path", L10N_PROJECT_PATH), &dirName)) {
// Changed, validate value
TrySelectPath(fs::path(dirName));
}
ImGui::SameLine();
if (ImGui::Button("...")) {
- auto selection = pfd::select_folder(ls->NewProjectPathDialogTitle.Get()).result();
+ auto selection = pfd::select_folder(I18N_TEXT("Project path", L10N_PROJECT_NEW_PATH_DIALOG_TITLE)).result();
if (!selection.empty()) {
TrySelectPath(fs::path(selection));
}
}
if (projectName.empty()) {
- ImGui::ErrorMessage("%s", ls->NewProjectEmptyNameError.Get());
+ ImGui::ErrorMessage("%s", I18N_TEXT("Name cannot be empty", L10N_EMPTY_NAME_ERROR));
}
if (!dirNameIsValid) {
- ImGui::ErrorMessage("%s", ls->NewProjectInvalidPathError.Get());
+ ImGui::ErrorMessage("%s", I18N_TEXT("Invalid path", L10N_INVALID_PATH_ERROR));
}
ImGui::Spacing();
- if (ImGui::Button(ls->Confirm.Get(), !dirNameIsValid || projectName.empty())) {
+ if (ImGui::Button(I18N_TEXT("Confirm", L10N_CONFIRM), !dirNameIsValid || projectName.empty())) {
ImGui::CloseCurrentPopup();
gs.SetCurrentProject(std::make_unique<Project>(std::move(dirPath), std::move(projectName)));
@@ -97,7 +95,7 @@ void ProjectTab_NoProject()
}
ImGui::SameLine();
- if (ImGui::Button(ls->Cancel.Get())) {
+ if (ImGui::Button(I18N_TEXT("Cancel", L10N_CANCEL))) {
ImGui::CloseCurrentPopup();
}
@@ -105,8 +103,8 @@ void ProjectTab_NoProject()
}
ImGui::SameLine();
- if (ImGui::Button(ls->OpenProject.Get())) {
- auto selection = pfd::open_file(ls->OpenProjectDialogTitle.Get()).result();
+ if (ImGui::Button(I18N_TEXT("Open project...", L10N_PROJECT_OPEN))) {
+ auto selection = pfd::open_file(I18N_TEXT("Open project", L10N_PROJECT_OPEN_DIALOG_TITLE)).result();
if (!selection.empty()) {
fs::path path(selection[0]);
@@ -124,10 +122,10 @@ void ProjectTab_NoProject()
// Recent projects
ImGui::Separator();
- ImGui::TextUnformatted(ls->RecentProjects.Get());
+ ImGui::TextUnformatted(I18N_TEXT("Recent projects", L10N_PROJECT_RECENTS));
ImGui::SameLine();
- if (ImGui::Button(ls->ClearRecentProjects.Get())) {
+ if (ImGui::Button(I18N_TEXT("Clear", L10N_PROJECT_RECENTS_CLEAR))) {
gs.ClearRecentProjects();
}
@@ -136,7 +134,7 @@ void ProjectTab_NoProject()
size_t toRemoveIdx = rp.size();
if (rp.empty()) {
- ImGui::TextUnformatted(ls->NoRecentProjectsMessage.Get());
+ ImGui::TextUnformatted(I18N_TEXT("No recent projects", L10N_PROJECT_RECENTS_NONE_PRESENT));
} else {
for (auto it = rp.rbegin(); it != rp.rend(); ++it) {
auto& [path, recent] = *it;
@@ -155,7 +153,7 @@ void ProjectTab_NoProject()
}
}
if (ImGui::IsItemHovered()) {
- ImGui::SetTooltip("%s", ls->OpenRecentProjectTooltip.Get());
+ ImGui::SetTooltip(I18N_TEXT("Open this project", L10N_PROJECT_RECENTS_OPEN_TOOLTIP));
}
ImGui::SameLine();
@@ -163,7 +161,7 @@ void ProjectTab_NoProject()
toRemoveIdx = idx;
}
if (ImGui::IsItemHovered()) {
- ImGui::SetTooltip("%s", ls->DeleteRecentProjectTooltip.Get());
+ ImGui::SetTooltip(I18N_TEXT("Delete this project from the Recent Projects list, the project itself will not be affected", L10N_PROJECT_RECENTS_DELETE_TOOLTIP));
}
ImGui::PopID();
@@ -176,10 +174,10 @@ void ProjectTab_NoProject()
if (openErrorDialog) {
ImGui::SetNextWindowCentered();
- ImGui::OpenPopup(ls->Error.Get());
+ ImGui::OpenPopup(I18N_TEXT("Error", L10N_ERROR));
}
- if (ImGui::BeginPopupModal(ls->Error.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
- ImGui::ErrorMessage("%s", ls->InvalidProjectFormat.Get());
+ if (ImGui::BeginPopupModal(I18N_TEXT("Error", L10N_ERROR), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
+ ImGui::ErrorMessage("%s", I18N_TEXT("Invalid project file", L10N_PROJECT_INVALID_PROJECT_FORMAT));
ImGui::EndPopup();
}
}
@@ -187,7 +185,6 @@ void ProjectTab_NoProject()
void UI::MainWindow()
{
- auto ls = LocaleStrings::Instance.get();
auto& gs = GlobalStates::GetInstance();
auto windowSize = ImGui::GetMainViewport()->Size;
@@ -195,12 +192,12 @@ void UI::MainWindow()
ImGui::SetNextWindowPos({ 0, 0 });
ImGui::Begin("##MainWindow", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
if (ImGui::BeginTabBar("MainWindowTabs")) {
- if (ImGui::BeginTabItem(ls->SettingsTab.Get())) {
+ if (ImGui::BeginTabItem(ICON_FA_COGS " " I18N_TEXT("Settings", L10N_MAIN_TAB_SETTINGS))) {
UI::SettingsTab();
ImGui::EndTabItem();
}
- if (ImGui::BeginTabItem(ls->ProjectTab.Get(), nullptr)) {
+ if (ImGui::BeginTabItem(ICON_FA_FILE " " I18N_TEXT("Project", L10N_MAIN_WINDOW_TAB_PROJECT), nullptr)) {
if (gs.HasCurrentProject()) {
ProjectTab_Normal();
} else {
@@ -213,22 +210,22 @@ void UI::MainWindow()
goto endTab;
}
- if (ImGui::BeginTabItem(ls->DatabaseViewTab.Get())) {
+ if (ImGui::BeginTabItem(ICON_FA_DATABASE " " I18N_TEXT("Data", L10N_MAIN_WINDOW_TAB_DATABASE_VIEW))) {
UI::DatabaseViewTab();
ImGui::EndTabItem();
}
- if (ImGui::BeginTabItem(ls->ItemsTab.Get())) {
+ if (ImGui::BeginTabItem(ICON_FA_BOX " " I18N_TEXT("Items", L10N_MAIN_WINDOW_TAB_ITEMS))) {
UI::ItemsTab();
ImGui::EndTabItem();
}
- if (ImGui::BeginTabItem(ls->WorkflowsTab.Get())) {
+ if (ImGui::BeginTabItem(ICON_FA_SCROLL " " I18N_TEXT("Workflows", L10N_MAIN_WINDOW_TAB_WORKFLOWS))) {
UI::WorkflowsTab();
ImGui::EndTabItem();
}
- if (ImGui::BeginTabItem(ls->TemplatesTab.Get())) {
+ if (ImGui::BeginTabItem(ICON_FA_TABLE " " I18N_TEXT("Templates", L10N_MAIN_WINDOW_TAB_TEMPLATES))) {
UI::TemplatesTab();
ImGui::EndTabItem();
}
diff --git a/core/src/UI/UI_Settings.cpp b/core/src/UI/UI_Settings.cpp
index da935c6..107b94c 100644
--- a/core/src/UI/UI_Settings.cpp
+++ b/core/src/UI/UI_Settings.cpp
@@ -1,7 +1,5 @@
#include "UI/UI.hpp"
-#include "UI/Localization.hpp"
-
#include <imgui.h>
void UI::SettingsTab()
diff --git a/core/src/UI/UI_Templates.cpp b/core/src/UI/UI_Templates.cpp
index b3a1e05..e08510a 100644
--- a/core/src/UI/UI_Templates.cpp
+++ b/core/src/UI/UI_Templates.cpp
@@ -4,8 +4,9 @@
#include "Model/Project.hpp"
#include "Model/Template/TableTemplate.hpp"
#include "Model/Template/Template.hpp"
-#include "UI/Localization.hpp"
+#include "Utils/I18n.hpp"
+#include <IconsFontAwesome.h>
#include <imgui.h>
#include <imgui_extra_math.h>
#include <imgui_stdlib.h>
@@ -134,7 +135,6 @@ std::unique_ptr<TemplateUI> TemplateUI::CreateByKind(Template::Kind kind)
void UI::TemplatesTab()
{
- auto ls = LocaleStrings::Instance.get();
auto& project = *GlobalStates::GetInstance().GetCurrentProject();
static std::unique_ptr<TemplateUI> openTemplate;
@@ -142,17 +142,17 @@ void UI::TemplatesTab()
bool openedDummy = true;
// Toolbar item: close
- if (ImGui::Button(ls->Close.Get(), openTemplate == nullptr)) {
+ if (ImGui::Button(ICON_FA_TIMES " " I18N_TEXT("Close", L10N_CLOSE), openTemplate == nullptr)) {
openTemplate = nullptr;
}
// Toolbar item: open...
ImGui::SameLine();
- if (ImGui::Button(ls->OpenAsset.Get())) {
- ImGui::OpenPopup(ls->OpenAssetDialogTitle.Get());
+ if (ImGui::Button(I18N_TEXT("Open asset...", L10N_ASSET_OPEN))) {
+ ImGui::OpenPopup(I18N_TEXT("Open asset", L10N_ASSET_OPEN_DIALOG_TITLE));
}
- if (ImGui::BeginPopupModal(ls->OpenAssetDialogTitle.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
- if (ImGui::Button(ls->Open.Get(), state.SelectedAsset == nullptr)) {
+ if (ImGui::BeginPopupModal(I18N_TEXT("Open asset", L10N_ASSET_OPEN_DIALOG_TITLE), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
+ if (ImGui::Button(I18N_TEXT("Open", L10N_OPEN), state.SelectedAsset == nullptr)) {
auto kind = static_cast<Template::Kind>(state.SelectedAsset->Payload);
openTemplate = TemplateUI::CreateByKind(kind);
}
@@ -165,10 +165,10 @@ void UI::TemplatesTab()
// Toolbar item: manage...
ImGui::SameLine();
- if (ImGui::Button(ls->ManageAssets.Get())) {
- ImGui::OpenPopup(ls->ManageAssetsDialogTitle.Get());
+ if (ImGui::Button(I18N_TEXT("Manage assets...", L10N_ASSET_MANAGE))) {
+ ImGui::OpenPopup(I18N_TEXT("Manage assets", L10N_ASSET_MANAGE_DIALOG_TITLE));
}
- if (ImGui::BeginPopupModal(ls->ManageAssetsDialogTitle.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
+ if (ImGui::BeginPopupModal(I18N_TEXT("Manage assets", L10N_ASSET_MANAGE_DIALOG_TITLE), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
project.Templates.DisplayControls(state);
project.Templates.DisplayDetailsList(state);
ImGui::EndPopup();
diff --git a/core/src/UI/UI_Workflows.cpp b/core/src/UI/UI_Workflows.cpp
index 3230cf9..4535f08 100644
--- a/core/src/UI/UI_Workflows.cpp
+++ b/core/src/UI/UI_Workflows.cpp
@@ -7,9 +7,10 @@
#include "Model/Workflow/Nodes/TextNodes.hpp"
#include "Model/Workflow/Nodes/UserInputNodes.hpp"
#include "Model/Workflow/Workflow.hpp"
-#include "UI/Localization.hpp"
+#include "Utils/I18n.hpp"
#include "Utils/Macros.hpp"
+#include <IconsFontAwesome.h>
#include <imgui.h>
#include <imgui_node_editor.h>
#include <imgui_stdlib.h>
@@ -162,8 +163,6 @@ public:
void Draw()
{
- auto ls = LocaleStrings::Instance.get();
-
ImNodes::SetCurrentEditor(mContext);
ImNodes::Begin("");
@@ -278,7 +277,7 @@ public:
auto& node = *mWorkflow->GetNodeByNodeId(mContextMenuNodeId);
node.DrawDebugInfo();
- if (ImGui::MenuItem(ls->Delete.Get())) {
+ if (ImGui::MenuItem(ICON_FA_TRASH " " I18N_TEXT("Delete", L10N_DELETE))) {
ImNodes::DeleteNode(mContextMenuNodeId);
}
@@ -293,7 +292,7 @@ public:
node->DrawInputPinDebugInfo(pinId);
}
- if (ImGui::MenuItem(ls->Disconnect.Get())) {
+ if (ImGui::MenuItem(ICON_FA_UNLINK " " I18N_TEXT("Disconnect", L10N_DISCONNECT))) {
if (isOutput) {
auto& pin = node->GetOutputPin(pinId);
if (pin.IsConnected()) {
@@ -318,7 +317,7 @@ public:
auto& conn = *mWorkflow->GetConnectionByLinkId(mContextMenuLinkId);
conn.DrawDebugInfo();
- if (ImGui::MenuItem(ls->Delete.Get())) {
+ if (ImGui::MenuItem(ICON_FA_TRASH " " I18N_TEXT("Delete", L10N_DELETE))) {
ImNodes::DeleteLink(mContextMenuLinkId);
}
@@ -362,7 +361,6 @@ public:
void UI::WorkflowsTab()
{
- auto ls = LocaleStrings::Instance.get();
auto& project = *GlobalStates::GetInstance().GetCurrentProject();
static std::unique_ptr<WorkflowUI> openWorkflow;
@@ -370,17 +368,17 @@ void UI::WorkflowsTab()
bool openedDummy = true;
// Toolbar item: close
- if (ImGui::Button(ls->Close.Get(), openWorkflow == nullptr)) {
+ if (ImGui::Button(ICON_FA_TIMES " " I18N_TEXT("Close", L10N_CLOSE), openWorkflow == nullptr)) {
openWorkflow = nullptr;
}
// Toolbar item: open...
ImGui::SameLine();
- if (ImGui::Button(ls->OpenAsset.Get())) {
- ImGui::OpenPopup(ls->OpenAssetDialogTitle.Get());
+ if (ImGui::Button((I18N_TEXT("Open asset...", L10N_ASSET_OPEN)))) {
+ ImGui::OpenPopup(I18N_TEXT("Open asset", L10N_ASSET_OPEN_DIALOG_TITLE));
}
- if (ImGui::BeginPopupModal(ls->OpenAssetDialogTitle.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
- if (ImGui::Button(ls->Open.Get(), state.SelectedAsset == nullptr)) {
+ if (ImGui::BeginPopupModal(I18N_TEXT("Open asset", L10N_ASSET_OPEN_DIALOG_TITLE), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
+ if (ImGui::Button(I18N_TEXT("Open", L10N_OPEN), state.SelectedAsset == nullptr)) {
auto workflow = project.Workflows.Load(*state.SelectedAsset);
openWorkflow = std::make_unique<WorkflowUI>(std::move(workflow));
}
@@ -393,10 +391,10 @@ void UI::WorkflowsTab()
// Toolbar item: manage...
ImGui::SameLine();
- if (ImGui::Button(ls->ManageAssets.Get())) {
- ImGui::OpenPopup(ls->ManageAssetsDialogTitle.Get());
+ if (ImGui::Button(I18N_TEXT("Manage assets...", L10N_ASSET_MANAGE))) {
+ ImGui::OpenPopup(I18N_TEXT("Manage assets", L10N_ASSET_MANAGE_DIALOG_TITLE));
}
- if (ImGui::BeginPopupModal(ls->ManageAssetsDialogTitle.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
+ if (ImGui::BeginPopupModal(I18N_TEXT("Manage assets", L10N_ASSET_MANAGE_DIALOG_TITLE), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
project.Workflows.DisplayControls(state);
project.Workflows.DisplayDetailsList(state);
ImGui::EndPopup();
diff --git a/core/src/UI/fwd.hpp b/core/src/UI/fwd.hpp
index 9b88370..756e567 100644
--- a/core/src/UI/fwd.hpp
+++ b/core/src/UI/fwd.hpp
@@ -1,8 +1,5 @@
#pragma once
-// Localization.hpp
-class LocaleStrings;
-
// UI.hpp
namespace ImGui {
enum class IconType;
diff --git a/core/src/Utils/I18n.cpp b/core/src/Utils/I18n.cpp
deleted file mode 100644
index e5131cc..0000000
--- a/core/src/Utils/I18n.cpp
+++ /dev/null
@@ -1,300 +0,0 @@
-#include "I18n.hpp"
-
-#include <json/reader.h>
-#include <json/value.h>
-#include <tsl/array_map.h>
-#include <filesystem>
-#include <fstream>
-#include <stdexcept>
-#include <string_view>
-#include <utility>
-
-namespace fs = std::filesystem;
-using namespace std::literals::string_view_literals;
-
-namespace {
-
-struct LanguageInfo
-{
- std::string CodeName;
- std::string LocaleName;
- fs::path File;
-};
-
-class I18nState
-{
-public:
- static I18nState& Get()
- {
- static I18nState instance;
- return instance;
- }
-
-public:
- tsl::array_map<char, LanguageInfo> LocaleInfos;
- tsl::array_map<char, std::string> CurrentEntries;
- LanguageInfo* CurrentLanguage = nullptr;
- bool Unloaded = false;
-
- void Unload()
- {
- Unloaded = true;
- CurrentEntries = {};
- }
-
- void EnsureLoaded()
- {
- if (Unloaded) {
- Unloaded = false;
- Reload();
- }
- }
-
- void Reload()
- {
- if (!CurrentLanguage) return;
-
- std::ifstream ifs(CurrentLanguage->File);
- Json::Value root;
- ifs >> root;
-
- for (auto name : root.getMemberNames()) {
- if (name == "$localized_name") {
- continue;
- }
-
- auto& value = root[name];
- if (value.isString()) {
- CurrentEntries.insert(name, value.asCString());
- }
- }
- }
-};
-
-std::string FindLocalizedName(const fs::path& localeFile)
-{
- std::ifstream ifs(localeFile);
- if (!ifs) {
- throw std::runtime_error("Failed to open locale file.");
- }
-
- Json::Value root;
- ifs >> root;
- if (auto& name = root["$localized_name"]; name.isString()) {
- return std::string(name.asCString());
- } else {
- throw std::runtime_error("Failed to find $localized_name in language file.");
- }
-}
-
-} // namespace
-
-void I18n::Init()
-{
- auto& state = I18nState::Get();
-
- auto dir = fs::current_path() / "locale";
- if (!fs::exists(dir)) {
- throw std::runtime_error("Failed to find locale directory.");
- }
-
- for (auto& elm : fs::directory_iterator{ dir }) {
- if (!elm.is_regular_file()) continue;
-
- auto& path = elm.path();
- auto codeName = path.stem().string();
-
- state.LocaleInfos.emplace(
- codeName,
- LanguageInfo{
- .CodeName = codeName,
- .LocaleName = FindLocalizedName(path),
- .File = path,
- });
- }
-}
-
-void I18n::Shutdown()
-{
- auto& state = I18nState::Get();
- state.LocaleInfos.clear();
- state.CurrentEntries.clear();
- state.CurrentLanguage = nullptr;
- state.Unloaded = false;
-}
-
-void I18n::Unload()
-{
- auto& state = I18nState::Get();
- state.Unload();
- OnUnload();
-}
-
-std::string_view I18n::GetLanguage()
-{
- auto& state = I18nState::Get();
- return state.CurrentLanguage->CodeName;
-}
-
-bool I18n::SetLanguage(std::string_view lang)
-{
- auto& state = I18nState::Get();
- if (state.CurrentLanguage &&
- state.CurrentLanguage->CodeName == lang)
- {
- return false;
- }
-
- if (auto iter = state.LocaleInfos.find(lang); iter != state.LocaleInfos.end()) {
- state.CurrentLanguage = &iter.value();
- state.Reload();
- }
-
- OnLanguageChange();
- return true;
-}
-
-std::optional<std::string_view> I18n::Lookup(std::string_view key)
-{
- auto& state = I18nState::Get();
- state.EnsureLoaded();
-
- auto iter = state.CurrentEntries.find(key);
- if (iter != state.CurrentEntries.end()) {
- return iter.value();
- } else {
- return std::nullopt;
- }
-}
-
-std::string_view I18n::LookupUnwrap(std::string_view key)
-{
- auto o = Lookup(key);
- if (!o) {
- std::string msg;
- msg.append("Unable to find locale for '");
- msg.append(key);
- msg.append("'.");
- throw std::runtime_error(std::move(msg));
- };
- return o.value();
-}
-
-std::string_view I18n::LookupLanguage(std::string_view lang)
-{
- auto& state = I18nState::Get();
- auto iter = state.LocaleInfos.find(lang);
- if (iter != state.LocaleInfos.end()) {
- return iter.value().LocaleName;
- } else {
- return ""sv;
- }
-}
-
-BasicTranslation::BasicTranslation(std::string_view key)
- : mContent{ I18n::LookupUnwrap(key) }
-{
-}
-
-const std::string& BasicTranslation::GetString() const
-{
- return mContent;
-}
-
-const char* BasicTranslation::Get() const
-{
- return mContent.c_str();
-}
-
-FormattedTranslation::FormattedTranslation(std::string_view key)
-{
- auto src = I18n::LookupUnwrap(key);
-
- mMinimumResultLen = 0;
-
- bool escape = false;
- bool matchingCloseBrace = false;
- std::string buf;
- for (char c : src) {
- switch (c) {
- case '\\': {
- // Disallow double (or more) escaping
- if (escape) {
- buf += '\\';
- escape = false;
- break;
- }
-
- escape = true;
- } break;
-
- case '{': {
- // Escaping an opening brace cause the whole "argument" (if any) gets parsed as a part of the previous literal
- if (escape) {
- buf += '{';
- escape = false;
- break;
- }
-
- // Generate literal
- mMinimumResultLen += buf.size();
- mParsedElements.push_back(Element{ std::move(buf) }); // Should also clear buf
-
- matchingCloseBrace = true;
- } break;
- case '}': {
- if (escape) {
- throw std::runtime_error("Cannot escape '}', put \\ before the '{' if intended to escape braces.");
- }
-
- // If there is no pairing '{', simply treat this as a normal character
- // (escaping for closing braces)
- if (!matchingCloseBrace) {
- buf += '}';
- break;
- }
-
- // Generate argument
- if (buf.empty()) {
- // No index given, default to use current argument's index
- auto currArgIdx = (int)mNumArguments;
- mParsedElements.push_back(Element{ currArgIdx });
- } else {
- // Use provided index
- int argIdx = std::stoi(buf);
- mParsedElements.push_back(Element{ argIdx });
- buf.clear();
- }
- } break;
-
- default: {
- if (escape) {
- throw std::runtime_error("Cannot escape normal character '" + std::to_string(c) + "'.");
- }
-
- buf += c;
- } break;
- }
- }
-}
-
-std::string FormattedTranslation::Format(std::span<Argument> args)
-{
- if (args.size() != mNumArguments) {
- throw std::runtime_error("Invalid number of arguments for FormattedTranslation::Format, expected " + std::to_string(mNumArguments) + " but found " + std::to_string(args.size()) + ".");
- }
-
- std::string result;
- result.reserve(mMinimumResultLen);
-
- for (auto& elm : mParsedElements) {
- if (auto literal = std::get_if<std::string>(&elm)) {
- result.append(*literal);
- }
- if (auto idx = std::get_if<int>(&elm)) {
- result.append(args[*idx]);
- }
- }
-
- return result;
-}
diff --git a/core/src/Utils/I18n.hpp b/core/src/Utils/I18n.hpp
index 6285d60..e9eaac9 100644
--- a/core/src/Utils/I18n.hpp
+++ b/core/src/Utils/I18n.hpp
@@ -1,87 +1,10 @@
#pragma once
-#include "Utils/Sigslot.hpp"
-#include "Utils/fwd.hpp"
+#include "Utils/Macros.hpp"
-#include <cstddef>
-#include <optional>
-#include <span>
-#include <string>
-#include <string_view>
-#include <variant>
-#include <vector>
-
-class I18n
-{
-public:
- static inline Signal<> OnLanguageChange{};
- static inline Signal<> OnUnload{};
-
- static void Init();
- static void Shutdown();
-
- /// Discard in-memory mapping from key to locale entries.
- /// When any of the entry accessors are invoked, unloaded entries will be reloaded.
- static void Unload();
-
- static std::string_view GetLanguage();
- static bool SetLanguage(std::string_view lang);
-
- /* Entry accessors */
- /// Find the localized entry with the given key, return \c std::nullopt if does not exist. Reloads locale entries if they are currently unloaded.
- static std::optional<std::string_view> Lookup(std::string_view key);
- /// Find the localized entry with the given key, throw an exception if does not exist. EnsureLoaded locale entries if they are currently unloaded.
- static std::string_view LookupUnwrap(std::string_view key);
-
- /// Query the localized name of a locale, e.g. "en_US" -> "English - United States".
- /// If the queried locale does not exist, an empty string will be returned (existing locales can never have an empty localized name).
- static std::string_view LookupLanguage(std::string_view lang);
-};
-
-struct StringArgument
-{
- std::string Value;
-};
-
-struct IntArgument
-{
- int Value;
-};
-
-struct FloatArgument
-{
- double Value;
-};
-
-class BasicTranslation
-{
-private:
- std::string mContent;
-
-public:
- BasicTranslation(std::string_view key);
- const std::string& GetString() const;
- const char* Get() const;
-};
-
-class FormattedTranslation
-{
-public:
- using Element = std::variant<std::string, int>;
- using Argument = std::string;
-
-private:
- std::vector<Element> mParsedElements;
- size_t mNumArguments;
- size_t mMinimumResultLen;
-
-public:
- FormattedTranslation(std::string_view key);
- std::string Format(std::span<Argument> args);
-};
-
-class NumericTranslation
-{
-public:
- // TODO
-};
+#if !defined(TARGET_LOCALE)
+# define I18N_TEXT(defaultText, name) defaultText
+#else
+# include TARGET_LOCALE_FILE
+# define I18N_TEXT(defaultText, name) name
+#endif
diff --git a/core/src/Utils/Macros.hpp b/core/src/Utils/Macros.hpp
index 68b93fb..6958ed1 100644
--- a/core/src/Utils/Macros.hpp
+++ b/core/src/Utils/Macros.hpp
@@ -1,7 +1,12 @@
#pragma once
+#define STRINGIFY_IMPL(text) #text
+#define STRINGIFY(text) STRINGIFY_IMPL(text)
+
#define CONCAT_IMPL(a, b) a##b
#define CONCAT(a, b) CONCAT_IMPL(a, b)
+#define CONCAT_3(a, b, c) CONCAT(a, CONCAT(b, c))
+#define CONCAT_4(a, b, c, d) CONCAT(CONCAT(a, b), CONCAT(c, d))
#define UNIQUE_NAME(prefix) CONCAT(prefix, __COUNTER__)
#define UNIQUE_NAME_LINE(prefix) CONCAT(prefix, __LINE__)
diff --git a/core/src/Utils/fwd.hpp b/core/src/Utils/fwd.hpp
index 74e642d..5d1fe45 100644
--- a/core/src/Utils/fwd.hpp
+++ b/core/src/Utils/fwd.hpp
@@ -4,15 +4,6 @@
class RgbaColor;
class HsvColor;
-// I18n.hpp
-class I18n;
-struct StringArgument;
-struct IntArgument;
-struct FloatArgument;
-class BasicTranslation;
-class FormattedTranslation;
-class NumericTranslation;
-
// Sigslot.hpp
class SignalStub;
template <class... TArgs>