~aleteoryx/muditaos

ref: a2ba217b0696581e5a8a663c7e992f5679975e3f muditaos/module-utils/i18/i18.hpp -rw-r--r-- 4.5 KiB
a2ba217b — pawpMudita EGD-4077 Re-enable support for temporary contacts in Phonebook main window 5 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*
 *  @file i18.hpp
 *  @author Mateusz Piesta (mateusz.piesta@mudita.com)
 *  @date 29 mar 2019
 *  @brief I18 implementation
 *  @copyright Copyright (C) 2019 mudita.com
 *  @details
 */

#ifndef UNTITLED_I18_HPP
#define UNTITLED_I18_HPP

#include "json/json11.hpp"
#include <string>
#include "vfs.hpp"
#include "log/log.hpp"

#include "thread.hpp"

namespace utils
{

    enum class Lang
    {
        En,
        Pl,
        De,
        Sp
    };

    class LangLoader
    {

        const char *langEN_path = "assets/lang/lang_en.json";
        const char *langPL_path = "assets/lang/lang_pl.json";
        const char *langDE_path = "assets/lang/lang_de.json";
        const char *langSP_path = "assets/lang/lang_sp.json";

      public:
        LangLoader()
        {}
        virtual ~LangLoader()
        {}

        json11::Json Create(Lang lang)
        {
            std::string err;
            const char *path = nullptr;

            switch (lang) {
            case Lang::Pl:
                path = langPL_path;
                break;
            case Lang::En:
                path = langEN_path;
                break;
            case Lang::De:
                path = langDE_path;
                break;
            case Lang::Sp:
                path = langSP_path;
                break;

            default:
                return json11::Json();
            }

            auto fd = vfs.fopen(path, "r");
            if (fd == NULL) {
                LOG_FATAL("Error during opening file %s", path);
                return json11::Json();
            }

            uint32_t fsize = vfs.filelength(fd);

            char *stream = static_cast<char *>(malloc(fsize + 1)); // +1 for NULL terminator
            if (stream == NULL) {
                LOG_FATAL("Memory allocation failure");
                vfs.fclose(fd);
                return json11::Json();
            }

            memset(stream, 0, fsize + 1);

            vfs.fread(stream, 1, fsize, fd);

            json11::Json js = json11::Json::parse(stream, err);

            free(stream);
            vfs.fclose(fd);

            // Error
            if (err.length() != 0) {
                LOG_FATAL("%s", err.c_str());
                return json11::Json();
            }
            else {
                return js;
            }
        }
    };

    class i18
    {

        json11::Json langPack;
        json11::Json langBack; // backup language if item not found
        LangLoader loader;
        static const Lang lang_default = Lang::En;
        Lang current                   = lang_default;
        bool debugRequests             = true;

      public:
        // Default constructor, left empty on purpose
        i18()
        {}

        // Explicit initialization point, default constructor is omitted. This is because LangLoader uses file system
        // which is not available at program's startup.
        virtual ~i18()
        {}

        const std::string &get(const std::string &str)
        {
            auto retwithfallback = [this](const std::string &ret, const std::string &str) -> const std::string & {
                if (debugRequests && ret == "") {
                    return str;
                }
                else {
                    return ret;
                }
            };
            auto &ret = langPack[str].string_value();
            // if language pack returnet nothing then try default language
            if (ret == "" && current != lang_default) {
                auto &ret = langBack[str].string_value();
                return retwithfallback(ret, str);
            }
            return retwithfallback(ret, str);
        }

        void Switch(Lang lang)
        {
            static bool initialized = false;
            if (!initialized) {
                langBack    = loader.Create(lang_default);
                langPack    = langBack;
                initialized = true;
            }
            if (lang == current)
                return;
            current = lang;
            if (lang == lang_default) {
                langPack = langBack;
            }
            else {
                json11::Json pack = loader.Create(lang);
                // Suspend whole system during switching lang packs
                vTaskSuspendAll();
                langPack = pack;
                xTaskResumeAll();
            }
        }
    };

    // Global instance of i18 class
    extern i18 localize;
    auto translateI18 = [](const std::string &text) { return utils::localize.get(text); };
} // namespace utils

#endif // UNTITLED_I18_HPP