From b0d7a35eb2f579ba254b221e663cf5bd88f536ff Mon Sep 17 00:00:00 2001 From: Andreev Gregory Date: Fri, 6 Sep 2024 01:06:36 +0300 Subject: [PATCH] First efforts to internationalize site --- assets/HypertextPages/chat-members.nytl.html | 6 +- assets/HypertextPages/chat.nytl.html | 6 +- assets/HypertextPages/edit-profile.nytl.html | 12 +- assets/HypertextPages/list-rooms.nytl.html | 4 +- assets/HypertextPages/login.nytl.html | 20 ++- assets/HypertextPages/view-profile.nytl.html | 8 +- assets/lang/en-US.lang.json | 11 ++ assets/lang/ru-RU.lang.json | 11 ++ building/main.cpp | 3 + config/default.json | 0 example/config.json | 36 +--- .../http_structures/accept_language.cpp | 72 ++++++++ .../http_structures/accept_language.h | 13 ++ .../http_structures/cookies.cpp | 8 +- .../http_structures/grammar.h | 11 ++ .../misc_tests/accept_language_test.cpp | 35 ++++ .../new_york_transit_line/parser.cpp | 4 +- .../backend_logic/client_server_interact.h | 2 + .../iu9_ca_web_chat_lib/localizator.cpp | 154 ++++++++++++++++++ .../iu9_ca_web_chat_lib/localizator.h | 36 ++++ src/web_chat/iu9_ca_web_chat_lib/run.cpp | 33 +++- 21 files changed, 419 insertions(+), 66 deletions(-) create mode 100644 assets/lang/en-US.lang.json create mode 100644 assets/lang/ru-RU.lang.json delete mode 100644 config/default.json create mode 100644 src/http_server/engine_engine_number_9/http_structures/accept_language.cpp create mode 100644 src/http_server/engine_engine_number_9/http_structures/accept_language.h create mode 100644 src/http_server/engine_engine_number_9/http_structures/grammar.h create mode 100644 src/http_server/misc_tests/accept_language_test.cpp create mode 100644 src/web_chat/iu9_ca_web_chat_lib/localizator.cpp create mode 100644 src/web_chat/iu9_ca_web_chat_lib/localizator.h diff --git a/assets/HypertextPages/chat-members.nytl.html b/assets/HypertextPages/chat-members.nytl.html index ec3b7c1..1094ef3 100644 --- a/assets/HypertextPages/chat-members.nytl.html +++ b/assets/HypertextPages/chat-members.nytl.html @@ -34,11 +34,11 @@ Go to list of chats - + Go to my profile -

Members list of {% WRITE openedchat.name %} ({% WRITE openedchat.nickname %})

- +

Members list of {% W openedchat.name %} ({% W openedchat.nickname %})

+
Back to chat diff --git a/assets/HypertextPages/chat.nytl.html b/assets/HypertextPages/chat.nytl.html index fb5a2e1..582ece8 100644 --- a/assets/HypertextPages/chat.nytl.html +++ b/assets/HypertextPages/chat.nytl.html @@ -36,11 +36,11 @@ Go to list of chats - + Go to my profile -

{% WRITE openedchat.name %} ({% WRITE openedchat.nickname %})

- +

{% W openedchat.name %} ({% W openedchat.nickname %})

+
Settings of chat. List of members diff --git a/assets/HypertextPages/edit-profile.nytl.html b/assets/HypertextPages/edit-profile.nytl.html index 4887645..d34aea2 100644 --- a/assets/HypertextPages/edit-profile.nytl.html +++ b/assets/HypertextPages/edit-profile.nytl.html @@ -16,28 +16,28 @@ Go to list of chats - + Go to my profile {% FOR error IN errors %}
- {% WRITE error.text %} + {% W error.text %}
{% ENDFOR %}
-

{% WRITE alienprofile.name %}

-

Nickname: {% WRITE alienprofile.nickname %}

+

{% W alienprofile.name %}

+

Nickname: {% W alienprofile.nickname %}

- {% WRITE alienprofile.bio %} + {% W alienprofile.bio %}

Change user attributes

-
+
diff --git a/assets/HypertextPages/list-rooms.nytl.html b/assets/HypertextPages/list-rooms.nytl.html index c7e7c4a..9b801d4 100644 --- a/assets/HypertextPages/list-rooms.nytl.html +++ b/assets/HypertextPages/list-rooms.nytl.html @@ -1,6 +1,6 @@ {% ELDEF main JSON pres JSON userinfo JSON initial_chatListUpdResp %} - + @@ -51,7 +51,7 @@ x
-

{% WRITE alienprofile.name %}

-

Nickname: {% WRITE alienprofile.nickname %}

+

{% W alienprofile.name %}

+

Nickname: {% W alienprofile.nickname %}

- {% WRITE alienprofile.bio %} + {% W alienprofile.bio %}

diff --git a/assets/lang/en-US.lang.json b/assets/lang/en-US.lang.json new file mode 100644 index 0000000..21fe522 --- /dev/null +++ b/assets/lang/en-US.lang.json @@ -0,0 +1,11 @@ +{ + "lang": "en", + "loginP": { + "header": "Login", + "directive-nickname": "Enter your nickname:", + "placeholder-nickname": "Nickname", + "directive-password": "Enter password:", + "placeholder-password": "Password", + "act": "Login" + } +} diff --git a/assets/lang/ru-RU.lang.json b/assets/lang/ru-RU.lang.json new file mode 100644 index 0000000..2147a5f --- /dev/null +++ b/assets/lang/ru-RU.lang.json @@ -0,0 +1,11 @@ +{ + "lang": "ru", + "loginP": { + "header": "Вход", + "directive-nickname": "Введите свой никнейм:", + "placeholder-nickname": "", + "directive-password": "Введите пароль:", + "placeholder-password": "", + "act": "Войти" + } +} \ No newline at end of file diff --git a/building/main.cpp b/building/main.cpp index d071bfe..2e87dfe 100644 --- a/building/main.cpp +++ b/building/main.cpp @@ -78,6 +78,7 @@ struct CAWebChat { "http_structures/client_request_parse.cpp", "http_structures/response_gen.cpp", "http_structures/cookies.cpp", + "http_structures/accept_language.cpp", "connecting_assets/static_asset_manager.cpp", "running_mainloop.cpp", "form_data_structure/urlencoded_query.cpp", @@ -97,6 +98,7 @@ struct CAWebChat { "http_structures/client_request.h", "http_structures/cookies.h", "http_structures/response_gen.h", + "http_structures/accept_language.h", "running_mainloop.h", "form_data_structure/urlencoded_query.h", "socket_address.h", @@ -141,6 +143,7 @@ struct CAWebChat { CTargetDependenceOnExternalLibrary{"sqlite3", {true, true}} }; T.units = { + "localizator.cpp", "initialize.cpp", "run.cpp", "str_fields.cpp", diff --git a/config/default.json b/config/default.json deleted file mode 100644 index e69de29..0000000 diff --git a/example/config.json b/example/config.json index 7c8ba53..8735c40 100644 --- a/example/config.json +++ b/example/config.json @@ -1,33 +1,9 @@ { - "presentation": { - "lang": "ru", - "instance-identity": { - "top-title": "Вэб чат от ИУ9" - }, - "phr": { - "decl": { - "enter": "Вход", - "nickname": "Никнейм", - "password": "Пароль", - "page-login": "Вход", - "list-of-chat-rooms": "Список Чат-Коsмнат", - "name-of-room": "Название комнаты", - "create-room": "Создать комнату", - - "incorrect-nickname-or-password": "Неправильный никнейм или пароль", - - "incorrect-profile-data": "Неправильно заполнены поля профиля" - }, - "ask" : { - "select-chat-room": "Выберете чат комнату" - }, - "act": { - "enter": "Войти", - "create-room": "Создать комнату", - "confirm": "Подтвердить", - "create": "Создать" - } - } + "lang": { + "whitelist": ["*"], + "force-order": [ + "ru" + ] }, "assets": "./assets", "database": { @@ -41,7 +17,7 @@ "storage-size-limit": 100000000000 }, "server": { - "workers": 8, + "workers": 16, "http-listen": ["127.0.0.1:1025"], "admin-command-listen": ["[::1]:1026"] } diff --git a/src/http_server/engine_engine_number_9/http_structures/accept_language.cpp b/src/http_server/engine_engine_number_9/http_structures/accept_language.cpp new file mode 100644 index 0000000..20dd850 --- /dev/null +++ b/src/http_server/engine_engine_number_9/http_structures/accept_language.cpp @@ -0,0 +1,72 @@ +#include "accept_language.h" +#include +#include "grammar.h" +#include "../baza_inter.h" + +namespace een9 { + bool AcceptLanguageSpec(char ch) { + return ch == ',' || ch == ';' || ch == '='; + } + + /* todo: This is one of many places in een9, where bad alloc does not interrupt request, + * todo: completely changing response instead. (see cookies and login cookies lol) + * todo: I have to do something about it. Maybe add more exception types */ + std::vector parse_header_Accept_Language(const std::string &AcceptLanguage) { + size_t n = AcceptLanguage.size(); + struct LR { + std::string lr; + float q = 1; + }; + size_t i = 0; + auto skipOWS = [&]() { + while (i < n && isSPACE(AcceptLanguage[i])) + i++; + }; + auto isThis = [&](char ch) { + skipOWS(); + return i >= n ? false : AcceptLanguage[i] == ch; + }; + auto readTkn = [&]() -> std::string { + skipOWS(); + if (i >= n) + return ""; + size_t bg = i; + while (i < n && !AcceptLanguageSpec(AcceptLanguage[i]) && !isSPACE(AcceptLanguage[i])) + i++; + return AcceptLanguage.substr(bg, i - bg); + }; + std::vector lrs; +#define myMsg "Bad Accept-Language" + while (i < n) { + skipOWS(); + if (i >= n) + break; + if (!lrs.empty()) { + if (isThis(',')) + i++; + else + break; + } + lrs.emplace_back(); + lrs.back().lr = readTkn(); + LR lr{readTkn(), 0}; + if (isThis(';')) { + i++; + if (readTkn() != "q") + THROW(myMsg); + if (!isThis('=')) + THROW(myMsg); + i++; + lrs.back().q = std::stof(readTkn()); + } + } + std::sort(lrs.begin(), lrs.end(), [](const LR& A, const LR& B) { + return A.q > B.q; + }); + std::vector result; + result.reserve(lrs.size()); + for (const LR& lr: lrs) + result.push_back(lr.lr == "*" ? "" : lr.lr); + return result; + } +} diff --git a/src/http_server/engine_engine_number_9/http_structures/accept_language.h b/src/http_server/engine_engine_number_9/http_structures/accept_language.h new file mode 100644 index 0000000..b6c4342 --- /dev/null +++ b/src/http_server/engine_engine_number_9/http_structures/accept_language.h @@ -0,0 +1,13 @@ +#ifndef ENGINE_ENGINE_NUMBER_9_HTTP_STRUCTURES_ACCEPT_LANGUAGE_H +#define ENGINE_ENGINE_NUMBER_9_HTTP_STRUCTURES_ACCEPT_LANGUAGE_H + +#include +#include + +namespace een9 { + /* Returns language ranges, sorted by priority (reverse) + * throws std::exception if header is incorrect! But it is not guaranteed. Maybe it won't */ + std::vector parse_header_Accept_Language(const std::string& AcceptLanguage); +} + +#endif diff --git a/src/http_server/engine_engine_number_9/http_structures/cookies.cpp b/src/http_server/engine_engine_number_9/http_structures/cookies.cpp index b7bc294..7520612 100644 --- a/src/http_server/engine_engine_number_9/http_structures/cookies.cpp +++ b/src/http_server/engine_engine_number_9/http_structures/cookies.cpp @@ -1,14 +1,20 @@ #include "cookies.h" #include "../baza_inter.h" +#include "grammar.h" + namespace een9 { bool isSPACE(char ch) { return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; } + bool isALPHANUM(char ch) { + return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('0' <= ch && ch <= '9'); + } + bool isToken(const std::string &str) { for (char ch : str) { - if (!(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('0' <= ch && ch <= '9') + if (!(isALPHANUM(ch) || ch == '!' || ch == '#' || ch == '$' || ch == '%' || ch == '&' || ch == '\'' || ch == '*' || ch == '+' || ch == '-' || ch == '.' || ch == '^' || ch == '_' || ch == '`' || ch == '|' || ch == '~' )) diff --git a/src/http_server/engine_engine_number_9/http_structures/grammar.h b/src/http_server/engine_engine_number_9/http_structures/grammar.h new file mode 100644 index 0000000..b82c69a --- /dev/null +++ b/src/http_server/engine_engine_number_9/http_structures/grammar.h @@ -0,0 +1,11 @@ +#ifndef ENGINE_ENGINE_NUMBER_9_HTTP_STRUCTURES_GRAMMAR_H +#define ENGINE_ENGINE_NUMBER_9_HTTP_STRUCTURES_GRAMMAR_H + +#include + +namespace een9 { + bool isSPACE(char ch); + bool isALPHANUM(char ch); +} + +#endif diff --git a/src/http_server/misc_tests/accept_language_test.cpp b/src/http_server/misc_tests/accept_language_test.cpp new file mode 100644 index 0000000..4aa4e43 --- /dev/null +++ b/src/http_server/misc_tests/accept_language_test.cpp @@ -0,0 +1,35 @@ +#include +#include + +using namespace een9; + +void test(const std::string& al, const std::vector& rls) { + std::vector got = parse_header_Accept_Language(al); + if (got != rls) { + printf("Test failed: wrong answer\n"); + abort(); + } + printf("Test passed\n"); +} + +void btest(const std::string& al) { + try { + parse_header_Accept_Language(al); + } catch (std::exception& e) {} + printf("...\n"); +} + +int main() { + test("RU-RU, uk-EN; q = 12.22", {"uk-EN", "RU-RU"}); + test(" RU-RU ,uk-EN; q = 12.22 ", {"uk-EN", "RU-RU"}); + test(" AAA; q=0.1, BBB-bb ; q=3, *; q=3", {"BBB-bb", "", "AAA"}); + test(" AAA; q=0.1, BBB-bb ; q=2.5, *; q=4.5", {"", "BBB-bb", "AAA"}); + test("ABB, AAA; q=0.1,AAB, BBB-bb ; q=2.5, *; q=4.5", {"", "BBB-bb", "ABB", "AAB", "AAA"}); + test("", {}); + test(" ", {}); + btest(";;;;"); + btest(";;==;;"); + btest("-;"); + btest("-=="); + return 0; +} diff --git a/src/http_server/new_york_transit_line/parser.cpp b/src/http_server/new_york_transit_line/parser.cpp index c87335a..94e447f 100644 --- a/src/http_server/new_york_transit_line/parser.cpp +++ b/src/http_server/new_york_transit_line/parser.cpp @@ -453,11 +453,11 @@ namespace nytl { P.passed_arguments = {parse_expression(ctx, local_var_names)}; skip_magic_block_end(ctx, syntax); }; - if (op == "WRITE") { + if (op == "WRITE" || op == "W") { mediocre_operator("str2text"); goto ya_e_ya_h_i_ya_g_d_o;; } - if (op == "ROUGHINSERT") { + if (op == "ROUGHINSERT" || op == "RI") { mediocre_operator("str2code"); goto ya_e_ya_h_i_ya_g_d_o;; } diff --git a/src/web_chat/iu9_ca_web_chat_lib/backend_logic/client_server_interact.h b/src/web_chat/iu9_ca_web_chat_lib/backend_logic/client_server_interact.h index 70c173d..70fbeec 100644 --- a/src/web_chat/iu9_ca_web_chat_lib/backend_logic/client_server_interact.h +++ b/src/web_chat/iu9_ca_web_chat_lib/backend_logic/client_server_interact.h @@ -11,12 +11,14 @@ #include #include #include +#include "../localizator.h" namespace iu9cawebchat { struct WorkerGuestData { /* Because templaters use libjsonincpp, they can't be READ by two thread simultaneously */ std::unique_ptr templater; std::unique_ptr db; + std::unique_ptr locales; }; void initial_extraction_of_all_the_useful_info_from_cookies( diff --git a/src/web_chat/iu9_ca_web_chat_lib/localizator.cpp b/src/web_chat/iu9_ca_web_chat_lib/localizator.cpp new file mode 100644 index 0000000..880b15c --- /dev/null +++ b/src/web_chat/iu9_ca_web_chat_lib/localizator.cpp @@ -0,0 +1,154 @@ +#include "localizator.h" + +#include +#include +#include +#include +#include +#include + +namespace iu9cawebchat { + std::string languageRangeSimpler(const std::string& a) { + return a == "*" ? "" : a; + } + + // I won't use iterators. c plus plus IS a scripting language and I do not want to mess with iterators + std::vector languageRangeGetPrefixes(const std::string& lr) { + if (lr.empty()) + return {""}; + std::vector result = {"", ""}; + for (size_t i = 0; i < lr.size(); i++) { + if (lr[i] == '-') + result.push_back(result.back()); + result.back() += lr[i]; + + } + return result; + } + + bool isInWhitelist(const std::string& lr, const std::vector& whitelist) { + for (const std::string& prefix : languageRangeGetPrefixes(lr)) + for (const std::string& nicePrefix: whitelist) + if (prefix == nicePrefix) + return true; + return false; + } + + std::vector collect_lang_dir_content(const std::string& lang_dir, + const std::vector& whitelist) { + + std::vector result; + errno = 0; + DIR* D = opendir(lang_dir.c_str()); + struct Guard1{ DIR*& D; ~Guard1(){ closedir(D); } } g1{D}; + if (!D) + een9_THROW_on_errno("opendir (" + lang_dir + ")"); + while (true) { + errno = 0; + struct dirent* Dent = readdir(D); + if (Dent == NULL) { + if (errno == 0) + break; + een9_THROW_on_errno("dirent"); + } + std::string entry = Dent->d_name; + if (entry == "." || entry == "..") + continue; + std::string filename = lang_dir + "/" + entry; + struct stat info; + int ret = stat(filename.c_str(), &info); + een9_ASSERT_on_iret(ret, "stat(" + filename + ")"); + if (!S_ISREG(info.st_mode)) + continue; + const std::string postfix = ".lang.json"; + if (!een9::endsWith(entry, postfix)) + continue; + std::string lang_antirange = entry.substr(0, entry.size() - postfix.size()); + if (!isInWhitelist(lang_antirange, whitelist)) + continue; + std::string content; + een9::readFile(filename, content); + + result.emplace_back(); + result.back().languagerange = languageRangeSimpler(lang_antirange); + result.back().content = json::parse_str_flawless(content); + } + return result; + } + + + Localizator::Localizator(const LocalizatorSettings &settings) : settings(settings) { + /* First - length of the longest prefix that was found so far (in force_order) + * Second - index in force_order that was assigned to this thingy + */ + + files = collect_lang_dir_content(settings.lang_dir, settings.whitelist); + size_t n = files.size(); +#define redundantFileMsg "Redundant localization file" + for (size_t i = 0; i < n; i++) { + for (size_t j = i + 1; j < n; j++) { + std::string A = files[i].languagerange; + std::string B = files[j].languagerange; + for (std::string& pa: languageRangeGetPrefixes(A)) + if (pa == B) + een9_THROW(redundantFileMsg); + for (std::string& pb: languageRangeGetPrefixes(B)) + if (pb == A) + een9_THROW(redundantFileMsg); + } + } + std::map> pref_to_files; + for (size_t k = 0; k < n; k++) { + for (const std::string& prefix: languageRangeGetPrefixes(files[k].languagerange)) { + pref_to_files[prefix].push_back(k); + } + } + std::vector> assignment; + constexpr size_t inf_bad_order = 999999999; + assignment.assign(n, {0, inf_bad_order}); + if (settings.force_order.size() >= inf_bad_order - 2) + een9_THROW("o_O"); + for (ssize_t i = 0; i < settings.force_order.size(); i++) { + const std::string& ip = settings.force_order[i]; + if (pref_to_files.count(ip) != 1) + een9_THROW("force-order list contains entries that match no files (" + ip + ")"); + for (size_t k: pref_to_files.at(ip)) { + if (assignment[k].first <= ip.size()) { + assignment[k].first = ip.size(); + assignment[k].second = i; + } + } + } + for (auto& p: pref_to_files) { + const std::vector& candidates = p.second; + assert(!candidates.empty()); + size_t bestSoFar = candidates[0]; + size_t f = inf_bad_order; + for (size_t k: candidates) { + if (assignment[k].second <= f) { + f = assignment[k].second; + bestSoFar = k; + } + } + prefix_to_file[p.first] = bestSoFar; + } + if (prefix_to_file.count("") != 1) + een9_THROW("No locales were provided"); + // todo: remove DEBUG + // for (size_t k = 0; k < n; k++) { + // printf("%s has priority %lu\n", files[k].languagerange.c_str(), assignment[k].second); + // } + // printf("==============\n"); + // for (const auto& p : prefix_to_file) { + // printf("%s -> %s\n", p.first.c_str(), files[p.second].languagerange.c_str()); + // } + } + + const LanguageFile& Localizator::get_right_locale(const std::vector &preferred_langs) { + for (const std::string& lr: preferred_langs) { + if (prefix_to_file.count(lr) == 1) + return files[prefix_to_file.at(lr)]; + } + return files[prefix_to_file.at("")]; + } +} diff --git a/src/web_chat/iu9_ca_web_chat_lib/localizator.h b/src/web_chat/iu9_ca_web_chat_lib/localizator.h new file mode 100644 index 0000000..7627a59 --- /dev/null +++ b/src/web_chat/iu9_ca_web_chat_lib/localizator.h @@ -0,0 +1,36 @@ +#ifndef IU9_CA_WEB_CHAT_LIB_LOCALIZATOR_H +#define IU9_CA_WEB_CHAT_LIB_LOCALIZATOR_H + +#include + +namespace iu9cawebchat { + /* '*' -> ''; X -> X */ + std::string languageRangeSimpler(const std::string& a); + + struct LocalizatorSettings { + std::string lang_dir; + std::vector whitelist; + std::vector force_order; + }; + + /* There is no need to put http Content-Language response value into json file. When is is in the name */ + struct LanguageFile { + std::string languagerange; + json::JSON content; + }; + + /* Localizator uses libjsonincpp internally, and thus can't be read by two treads simultaneously */ + struct Localizator { + LocalizatorSettings settings; + std::vector files; + std::map prefix_to_file; + + /* Throws std::exception if something goes wrong */ + explicit Localizator(const LocalizatorSettings& settings); + + /* Returns a reference to object inside Localizator */ + const LanguageFile& get_right_locale(const std::vector& preferred_langs); + }; +} + +#endif diff --git a/src/web_chat/iu9_ca_web_chat_lib/run.cpp b/src/web_chat/iu9_ca_web_chat_lib/run.cpp index 2fe2b29..7162740 100644 --- a/src/web_chat/iu9_ca_web_chat_lib/run.cpp +++ b/src/web_chat/iu9_ca_web_chat_lib/run.cpp @@ -5,6 +5,7 @@ #include #include "find_db.h" #include +#include #include #include "str_fields.h" #include "backend_logic/client_server_interact.h" @@ -32,11 +33,23 @@ namespace iu9cawebchat { } }; + LocalizatorSettings make_localizator_settings(const std::string& assets_dir, const json::JSON& config) { + std::vector whitelist; + for (const json::JSON& entry: config["lang"]["whitelist"].asArray()) + whitelist.push_back(languageRangeSimpler(entry.asString())); + std::vector force_order; + for (const json::JSON& entry: config["lang"]["force-order"].asArray()) + force_order.push_back(languageRangeSimpler(entry.asString())); + return LocalizatorSettings{assets_dir + "/lang", whitelist, force_order}; + } + void run_website(const json::JSON& config) { een9_ASSERT(config["assets"].isString(), "config[\"assets\"] is not string"); const std::string& assets_dir = config["assets"].asString(); een9_ASSERT(een9::isDirectory(assets_dir), "\"" + assets_dir + "\" is not a directory"); + LocalizatorSettings localizator_settings = make_localizator_settings(assets_dir, config); + een9::StaticAssetManagerSlaveModule samI; samI.update({ een9::StaticAssetManagerRule{assets_dir + "/css", "/assets/css", {{".css", "text/css"}} }, @@ -47,7 +60,6 @@ namespace iu9cawebchat { } }, }); - const json::JSON& config_presentation = config["presentation"]; int64_t slave_number = config["server"]["workers"].asInteger().get_int(); een9_ASSERT(slave_number > 0 && slave_number <= 200, "E"); @@ -61,15 +73,24 @@ namespace iu9cawebchat { nytl::TemplaterSettings{nytl::TemplaterDetourRules{assets_dir + "/HypertextPages"}}); worker_guest_data[i].templater->update(); worker_guest_data[i].db = std::make_unique(sqlite_db_path); + worker_guest_data[i].locales = std::make_unique(localizator_settings); } een9::MainloopParameters params; - params.guest_core = [&samI, &worker_guest_data, config_presentation] + params.guest_core = [&samI, &worker_guest_data] (const een9::SlaveTask& task, const een9::ClientRequest& req, een9::worker_id_t worker_id) -> std::string { een9_ASSERT_pl(0 <= worker_id && worker_id < worker_guest_data.size()); WorkerGuestData& wgd = worker_guest_data[worker_id]; een9::StaticAsset sa; ONE_SQLITE_TRANSACTION_GUARD conn_guard(*wgd.db); + std::string AcceptLanguage; + for (const std::pair& p: req.headers) { + if (p.first == "Accept-Language") + AcceptLanguage = p.second; + } + std::vector AcceptLanguageB = een9::parse_header_Accept_Language(AcceptLanguage); + const LanguageFile& locale = wgd.locales->get_right_locale(AcceptLanguageB); + const json::JSON& pres = locale.content; try { std::vector> cookies; std::vector login_cookies; @@ -78,17 +99,17 @@ namespace iu9cawebchat { initial_extraction_of_all_the_useful_info_from_cookies(*wgd.db, req, cookies, login_cookies, userinfo, logged_in_user); if (req.uri_path == "/" || req.uri_path == "/list-rooms") { - return when_page_list_rooms(wgd, config_presentation, req, userinfo); + return when_page_list_rooms(wgd, pres, req, userinfo); } if (req.uri_path == "/login") { - return when_page_login(wgd, config_presentation, req, login_cookies, userinfo); + return when_page_login(wgd, pres, req, login_cookies, userinfo); } // todo: split if (een9::beginsWith(req.uri_path, "/chat/") || een9::beginsWith(req.uri_path, "/chat-members/")) { - return when_page_chat(wgd, config_presentation, req, userinfo); + return when_page_chat(wgd, pres, req, userinfo); } if (een9::beginsWith(req.uri_path, "/user/")) { - return when_page_user(wgd, config_presentation, req, login_cookies, userinfo); + return when_page_user(wgd, pres, req, login_cookies, userinfo); } if (req.uri_path == "/api/chatPollEvents") { return when_internalapi_chatpollevents(wgd, req, logged_in_user);