144 lines
4.3 KiB
C++
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
|