/
I18n.h
128 lines (96 loc) · 3.35 KB
/
I18n.h
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
#pragma once
// I18N = I....18..dots.....N = INTERNATIONALIZATION
// Super simple I18N library.
// Just enough to be useful and usable.
// Spits out easy-to-edit utf-8 .INI files.
// As usual, everything is UTF-8. Nothing else allowed.
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include "Common/Common.h"
#include "Common/File/Path.h"
// Reasonably thread safe.
class I18NRepo;
class IniFile;
class Section;
struct I18NEntry {
I18NEntry(const std::string &t) : text(t), readFlag(false) {}
I18NEntry() : readFlag(false) {}
std::string text;
bool readFlag;
};
struct I18NCandidate {
I18NCandidate() : key(0), defVal(0) {}
I18NCandidate(const char *k, const char *d) : key(k), defVal(d) {}
const char *key;
const char *defVal;
};
class I18NCategory {
public:
// NOTE: Name must be a global constant string - it is not copied.
I18NCategory(const char *name) : name_(name) {}
const char *T(const char *key, const char *def = 0);
const char *T(const std::string &key) {
return T(key.c_str(), nullptr);
}
const std::map<std::string, std::string> Missed() const {
std::lock_guard<std::mutex> guard(missedKeyLock_);
return missedKeyLog_;
}
const std::map<std::string, I18NEntry> &GetMap() { return map_; }
void ClearMissed() { missedKeyLog_.clear(); }
const char *GetName() const { return name_.c_str(); }
private:
I18NCategory(I18NRepo *repo, const char *name) : name_(name) {}
void SetMap(const std::map<std::string, std::string> &m);
std::string name_;
std::map<std::string, I18NEntry> map_;
mutable std::mutex missedKeyLock_;
std::map<std::string, std::string> missedKeyLog_;
// Noone else can create these.
friend class I18NRepo;
DISALLOW_COPY_AND_ASSIGN(I18NCategory);
};
class I18NRepo {
public:
I18NRepo() {}
~I18NRepo();
bool IniExists(const std::string &languageID) const;
bool LoadIni(const std::string &languageID, const Path &overridePath = Path()); // NOT the filename!
void SaveIni(const std::string &languageID);
std::string LanguageID();
std::shared_ptr<I18NCategory> GetCategory(const char *categoryName);
bool HasCategory(const char *categoryName) const {
std::lock_guard<std::mutex> guard(catsLock_);
return cats_.find(categoryName) != cats_.end();
}
const char *T(const char *category, const char *key, const char *def = 0);
std::map<std::string, std::vector<std::string>> GetMissingKeys() const;
private:
Path GetIniPath(const std::string &languageID) const;
void Clear();
I18NCategory *LoadSection(const Section *section, const char *name);
void SaveSection(IniFile &ini, Section *section, std::shared_ptr<I18NCategory> cat);
mutable std::mutex catsLock_;
std::map<std::string, std::shared_ptr<I18NCategory>> cats_;
std::string languageID_;
DISALLOW_COPY_AND_ASSIGN(I18NRepo);
};
extern I18NRepo i18nrepo;
// These are simply talking to the one global instance of I18NRepo.
inline std::shared_ptr<I18NCategory> GetI18NCategory(const char *categoryName) {
if (!categoryName)
return nullptr;
return i18nrepo.GetCategory(categoryName);
}
inline bool I18NCategoryLoaded(const char *categoryName) {
return i18nrepo.HasCategory(categoryName);
}
inline const char *T(const char *category, const char *key, const char *def = 0) {
return i18nrepo.T(category, key, def);
}
inline std::map<std::string, std::vector<std::string>> GetI18NMissingKeys() {
return i18nrepo.GetMissingKeys();
}