aboutsummaryrefslogtreecommitdiff
path: root/core/src/Utils/I18n.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/Utils/I18n.cpp')
-rw-r--r--core/src/Utils/I18n.cpp300
1 files changed, 0 insertions, 300 deletions
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;
-}