Files
shadow-over-bishkek001/src/Localization.cpp
T

144 lines
4.3 KiB
C++

#include "Localization.h"
#include "external/nlohmann/json.hpp"
#include "utils/Utils.h"
#include <iostream>
// Платформозависимые инклюды для детекции языка
#if defined(_WIN32)
#include <windows.h>
#elif defined(__EMSCRIPTEN__)
#include <emscripten.h>
#elif defined(__ANDROID__)
#include <SDL.h>
#endif
namespace FRG {
Language g_currentLanguage = Language::Russian;
std::string languageToCode(Language lang) {
switch (lang) {
case Language::English: return "en";
case Language::Russian:
default: return "ru";
}
}
Language languageFromCode(const std::string& code) {
if (code == "en") return Language::English;
return Language::Russian;
}
std::string localizedConfigPath(const std::string& basePath, Language lang) {
static const std::string marker = "/config/";
const size_t pos = basePath.find(marker);
if (pos == std::string::npos) return basePath;
return basePath.substr(0, pos) + "/config_" + languageToCode(lang) + "/" + basePath.substr(pos + marker.size());
}
std::string readLocalizedConfigFile(const std::string& basePath, const std::string& zipFile) {
const std::string localizedPath = localizedConfigPath(basePath, g_currentLanguage);
if (localizedPath != basePath) {
std::string content;
if (zipFile.empty()) {
content = readTextFile(localizedPath);
} else {
try {
const auto buf = readFileFromZIP(localizedPath, zipFile);
content.assign(buf.begin(), buf.end());
} catch (const std::exception&) {
content.clear();
}
}
if (!content.empty()) return content;
}
if (zipFile.empty()) return readTextFile(basePath);
try {
const auto buf = readFileFromZIP(basePath, zipFile);
return std::string(buf.begin(), buf.end());
} catch (const std::exception&) {
return "";
}
}
void loadLanguageSetting() {
const std::string content = readSavedTextFile("settings.json");
// Если файла настроек нет (content пустой), определяем язык системы и выходим
if (content.empty()) {
g_currentLanguage = detectSystemLanguage();
logger() << "[settings] No settings.json found. System language detected: "
<< languageToCode(g_currentLanguage) << std::endl;
return;
}
try {
const nlohmann::json root = nlohmann::json::parse(content);
if (root.contains("language")) {
g_currentLanguage = languageFromCode(root["language"].get<std::string>());
}
} catch (const std::exception& e) {
std::cerr << "[settings] Failed to parse settings.json: " << e.what() << std::endl;
}
}
Language detectSystemLanguage() {
#if defined(__EMSCRIPTEN__)
// Получаем первые два символа языка из браузера (0 - English, 1 - Russian, -1 - другой)
int res = EM_ASM_INT({
var lang = (navigator.language || navigator.userLanguage || 'en').toLowerCase();
if (lang.startsWith('ru')) return 1;
if (lang.startsWith('en')) return 0;
return -1;
});
if (res == 1) return Language::Russian;
if (res == 0) return Language::English;
#elif defined(_WIN32)
LANGID langId = GetUserDefaultUILanguage();
WORD primaryLang = PRIMARYLANGID(langId);
if (primaryLang == LANG_RUSSIAN) return Language::Russian;
if (primaryLang == LANG_ENGLISH) return Language::English;
#elif defined(__ANDROID__)
SDL_Locale* locales = SDL_GetPreferredLocales();
if (locales) {
Language detected = Language::English;
for (SDL_Locale* l = locales; l->language; ++l) {
std::string langCode = l->language;
if (langCode == "ru") {
detected = Language::Russian;
break;
}
if (langCode == "en") {
detected = Language::English;
break;
}
}
SDL_free(locales);
return detected;
}
#else
// Linux / SteamOS
const char* langEnv = std::getenv("LC_ALL");
if (!langEnv || *langEnv == '\0') {
langEnv = std::getenv("LANG");
}
if (langEnv && *langEnv != '\0') {
std::string langStr(langEnv);
// Ищем префиксы "ru" или "en" в начале строки (например, ru_RU.UTF-8)
if (langStr.rfind("ru", 0) == 0) return Language::Russian;
if (langStr.rfind("en", 0) == 0) return Language::English;
}
#endif
// Дефолтный фоллбек, если язык системы не поддерживается игрой (например, немецкий)
return Language::English;
}
} // namespace FRG