Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/Data/Text/I18n.h
5695 views
1
#pragma once
2
3
// I18N = I....18..dots.....N = INTERNATIONALIZATION
4
5
// Super simple I18N library.
6
// Just enough to be useful and usable.
7
// Spits out easy-to-edit utf-8 .INI files.
8
9
// As usual, everything is UTF-8. Nothing else allowed.
10
11
#include <map>
12
#include <mutex>
13
#include <string>
14
#include <string_view>
15
#include <vector>
16
#include <memory>
17
18
#include "Common/Common.h"
19
#include "Common/File/Path.h"
20
21
// Reasonably thread safe.
22
23
class I18NRepo;
24
class IniFile;
25
class Section;
26
27
// Don't forget to update the string array in the cpp file if you change this.
28
enum class I18NCat : uint8_t {
29
AUDIO = 0,
30
CONTROLS,
31
CWCHEATS,
32
DESKTOPUI,
33
DEVELOPER,
34
DIALOG,
35
ERRORS, // Can't name it ERROR, clashes with many defines.
36
GAME,
37
GRAPHICS,
38
INSTALLZIP,
39
KEYMAPPING,
40
MAINMENU,
41
MAINSETTINGS,
42
MAPPABLECONTROLS,
43
NETWORKING,
44
PAUSE,
45
POSTSHADERS,
46
PSPCREDITS,
47
MEMSTICK,
48
REMOTEISO,
49
REPORTING,
50
SAVEDATA,
51
SCREEN,
52
SEARCH,
53
STORE,
54
SYSINFO,
55
SYSTEM,
56
TEXTURESHADERS,
57
THEMES,
58
UI_ELEMENTS,
59
VR,
60
ACHIEVEMENTS,
61
PSPSETTINGS,
62
CATEGORY_COUNT,
63
NONE = CATEGORY_COUNT,
64
};
65
66
struct I18NEntry {
67
I18NEntry(std::string_view t) : text(t), readFlag(false) {}
68
I18NEntry() : readFlag(false) {}
69
std::string text;
70
bool readFlag;
71
};
72
73
class I18NCategory {
74
public:
75
I18NCategory() {}
76
explicit I18NCategory(const Section &section);
77
78
// Faster since the string lengths don't need to be recomputed.
79
std::string_view T(std::string_view key, std::string_view def = "");
80
81
// Try to avoid this. Still useful in snprintf.
82
const char *T_cstr(const char *key, const char *def = nullptr);
83
84
std::map<std::string, std::string, std::less<>> Missed() const;
85
86
const std::map<std::string, I18NEntry, std::less<>> &GetMap() { return map_; }
87
void ClearMissed() { missedKeyLog_.clear(); }
88
void Clear();
89
90
private:
91
I18NCategory(I18NRepo *repo, const char *name) {}
92
void SetMap(const std::map<std::string, std::string> &m);
93
94
// std::less<> is needed to be able to look up string_views in a string-keyed map.
95
std::map<std::string, I18NEntry, std::less<>> map_;
96
mutable std::mutex missedKeyLock_;
97
std::map<std::string, std::string, std::less<>> missedKeyLog_;
98
99
std::string name_;
100
// Noone else can create these.
101
friend class I18NRepo;
102
};
103
104
class I18NRepo {
105
public:
106
I18NRepo();
107
bool IniExists(const std::string &languageID) const;
108
bool LoadIni(const std::string &languageID, const Path &overridePath = Path()); // NOT the filename!
109
110
std::string LanguageID();
111
112
std::shared_ptr<I18NCategory> GetCategory(I18NCat category);
113
114
// Translate the string, by looking up "key" in the file, and falling back to either def or key, in that order, if the lookup fails.
115
// def can (and usually is) set to nullptr.
116
std::string_view T(I18NCat category, std::string_view key, std::string_view def = "") {
117
if (category == I18NCat::NONE)
118
return !def.empty() ? def : key;
119
return cats_[(size_t)category]->T(key, def);
120
}
121
const char *T_cstr(I18NCat category, const char *key, const char *def = nullptr) {
122
if (category == I18NCat::NONE)
123
return def ? def : key;
124
return cats_[(size_t)category]->T_cstr(key, def);
125
}
126
void LogMissingKeys() const;
127
128
private:
129
Path GetIniPath(const std::string &languageID) const;
130
void Clear();
131
132
mutable std::mutex catsLock_;
133
std::shared_ptr<I18NCategory> cats_[(size_t)I18NCat::CATEGORY_COUNT];
134
std::string languageID_;
135
};
136
137
extern I18NRepo g_i18nrepo;
138
139
// These are simply talking to the one global instance of I18NRepo.
140
141
std::shared_ptr<I18NCategory> GetI18NCategory(I18NCat cat);
142
143
inline std::string_view T(I18NCat category, std::string_view key, std::string_view def = "") {
144
return g_i18nrepo.T(category, key, def);
145
}
146
147
inline const char *T_cstr(I18NCat category, const char *key, const char *def = "") {
148
return g_i18nrepo.T_cstr(category, key, def);
149
}
150
151