languages support (WIP)

This commit is contained in:
MihailRis
2023-12-12 22:02:17 +03:00
parent 0837cf4f03
commit 7bf70bb26e
21 changed files with 456 additions and 38 deletions
+133
View File
@@ -0,0 +1,133 @@
#include "langs.h"
#include <iostream>
#include "../../coders/json.h"
#include "../../coders/commons.h"
#include "../../content/ContentPack.h"
#include "../../files/files.h"
#include "../../util/stringutil.h"
using std::string;
using std::wstring;
using std::vector;
using std::unique_ptr;
using std::unordered_map;
using std::filesystem::path;
namespace fs = std::filesystem;
unique_ptr<langs::Lang> langs::current;
vector<langs::LocaleInfo> langs::locales_info;
langs::Lang::Lang(string locale) : locale(locale) {
}
const wstring& langs::Lang::get(const wstring& key) const {
auto found = map.find(key);
if (found == map.end()) {
return key;
}
return found->second;
}
void langs::Lang::put(const wstring& key, const wstring& text) {
map[key] = text;
}
/* Language key-value txt files parser */
class Reader : public BasicParser {
void skipWhitespace() override {
BasicParser::skipWhitespace();
if (hasNext() && source[pos] == '#') {
skipLine();
if (hasNext() && is_whitespace(peek())) {
skipWhitespace();
}
}
}
public:
Reader(string file, string source) : BasicParser(file, source) {
}
void read(langs::Lang& lang, std::string prefix) {
skipWhitespace();
while (hasNext()) {
string key = parseString('=', true);
util::trim(key);
key = prefix + key;
string text = parseString('\n', false);
util::trim(text);
lang.put(util::str2wstr_utf8(key),
util::str2wstr_utf8(text));
skipWhitespace();
}
}
};
void langs::loadLocalesInfo(const path& resdir, string& fallback) {
path file = resdir/path(langs::TEXTS_FOLDER)/path("langs.json");
unique_ptr<json::JObject> root (files::read_json(file));
langs::locales_info.clear();
root->str("fallback", fallback);
auto langs = root->obj("langs");
if (langs) {
for (auto& entry : langs->map) {
auto langInfo = entry.second;
string name;
if (langInfo->type == json::valtype::object) {
name = langInfo->value.obj->getStr("name", "none");
} else {
continue;
}
std::cout << "locale " << entry.first << " (" << name << ") added" << std::endl;
langs::locales_info.push_back(LocaleInfo {entry.first, name});
}
}
}
void langs::load(const path& resdir,
const string& locale,
vector<const ContentPack*>& packs,
Lang& lang) {
path filename = path(TEXTS_FOLDER)/path(locale + LANG_FILE_EXT);
path core_file = resdir/filename;
if (fs::is_regular_file(core_file)) {
string text = files::read_string(core_file);
Reader reader(core_file.string(), text);
reader.read(lang, "");
}
for (auto pack : packs) {
path file = pack->getFolder()/filename;
if (fs::is_regular_file(file)) {
string text = files::read_string(file);
Reader reader(file.string(), text);
reader.read(lang, pack->getId()+":");
}
}
}
void langs::load(const path& resdir,
const string& locale,
const string& fallback,
vector<const ContentPack*>& packs) {
unique_ptr<Lang> lang (new Lang(locale));
load(resdir, fallback, packs, *lang.get());
load(resdir, locale, packs, *lang.get());
current.reset(lang.release());
}
void langs::setup(const path& resdir,
const string& locale,
vector<const ContentPack*>& packs) {
string fallback = langs::FALLBACK_DEFAULT;
langs::loadLocalesInfo(resdir, fallback);
langs::load(resdir, locale, fallback, packs);
}
const wstring& langs::get(const wstring& key) {
return current->get(key);
}
+65
View File
@@ -0,0 +1,65 @@
#ifndef FRONTEND_LOCALE_LANGS_H
#define FRONTEND_LOCALE_LANGS_H
#include <string>
#include <vector>
#include <memory>
#include <filesystem>
#include <unordered_map>
class ContentPack;
namespace langs {
const char LANG_FILE_EXT[] = ".txt";
const char TEXTS_FOLDER[] = "texts";
const char FALLBACK_DEFAULT[] = "en_US";
/*
Translation is mostly used for rendered text,
so Font.draw and Lang both use wstring for strings.
Translation key is wstring too, allowing to use it as value
if no any translation found, without conversion required
Key syntax: `modid:context.key` where modid is added at runtime for
content pack texts
*/
class Lang {
std::string locale;
std::unordered_map<std::wstring, std::wstring> map;
public:
Lang(std::string locale);
const std::wstring& get(const std::wstring& key) const;
void put(const std::wstring& key, const std::wstring& text);
};
struct LocaleInfo {
std::string locale;
std::string name;
};
extern std::unique_ptr<Lang> current;
extern std::vector<LocaleInfo> locales_info;
extern void loadLocalesInfo(
const std::filesystem::path& resdir,
std::string& fallback);
extern void load(const std::filesystem::path& resdir,
const std::string& locale,
std::vector<const ContentPack*>& packs,
Lang& lang);
extern void load(const std::filesystem::path& resdir,
const std::string& locale,
const std::string& fallback,
std::vector<const ContentPack*>& packs);
extern const std::wstring& get(const std::wstring& key);
extern void setup(const std::filesystem::path& resdir,
const std::string& locale,
std::vector<const ContentPack*>& packs);
}
#endif // FRONTEND_LOCALE_LANGS_H