CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/Data/Text/I18n.cpp
Views: 1401
1
#include <cstring>
2
3
#include "Common/Data/Text/I18n.h"
4
#include "Common/Data/Format/IniFile.h"
5
#include "Common/File/VFS/VFS.h"
6
#include "Common/Log.h"
7
8
#include "Common/StringUtils.h"
9
10
static const char * const g_categoryNames[(size_t)I18NCat::CATEGORY_COUNT] = {
11
"Audio",
12
"Controls",
13
"CwCheats",
14
"DesktopUI",
15
"Developer",
16
"Dialog",
17
"Error",
18
"Game",
19
"Graphics",
20
"InstallZip",
21
"KeyMapping",
22
"MainMenu",
23
"MainSettings",
24
"MappableControls",
25
"Networking",
26
"Pause",
27
"PostShaders",
28
"PSPCredits",
29
"MemStick",
30
"RemoteISO",
31
"Reporting",
32
"Savedata",
33
"Screen",
34
"Search",
35
"Store",
36
"SysInfo",
37
"System",
38
"TextureShaders",
39
"Themes",
40
"UI Elements",
41
"Upgrade",
42
"VR",
43
"Achievements",
44
"PSPSettings",
45
};
46
47
I18NRepo g_i18nrepo;
48
49
std::string I18NRepo::LanguageID() {
50
return languageID_;
51
}
52
53
I18NRepo::I18NRepo() {
54
Clear();
55
}
56
57
void I18NRepo::Clear() {
58
std::lock_guard<std::mutex> guard(catsLock_);
59
for (auto &iter : cats_) {
60
// Initialize with empty categories, so that early lookups don't crash.
61
iter = std::make_shared<I18NCategory>();
62
}
63
}
64
65
I18NCategory::I18NCategory(const Section &section) {
66
std::map<std::string, std::string> sectionMap = section.ToMap();
67
SetMap(sectionMap);
68
}
69
70
void I18NCategory::Clear() {
71
map_.clear();
72
missedKeyLog_.clear();
73
}
74
75
std::string_view I18NCategory::T(std::string_view key, std::string_view def) {
76
auto iter = map_.find(key);
77
if (iter != map_.end()) {
78
return iter->second.text.c_str();
79
} else {
80
std::lock_guard<std::mutex> guard(missedKeyLock_);
81
std::string missedKey(key);
82
if (!def.empty())
83
missedKeyLog_[missedKey] = def;
84
else
85
missedKeyLog_[missedKey] = std::string(key);
86
return !def.empty() ? def : key;
87
}
88
}
89
90
const char *I18NCategory::T_cstr(const char *key, const char *def) {
91
auto iter = map_.find(key);
92
if (iter != map_.end()) {
93
return iter->second.text.c_str();
94
} else {
95
std::lock_guard<std::mutex> guard(missedKeyLock_);
96
std::string missedKey(key);
97
if (def)
98
missedKeyLog_[missedKey] = def;
99
else
100
missedKeyLog_[missedKey] = std::string(key);
101
return def ? def : key;
102
}
103
}
104
105
void I18NCategory::SetMap(const std::map<std::string, std::string> &m) {
106
for (const auto &[key, value] : m) {
107
if (map_.find(key) == map_.end()) {
108
std::string text = ReplaceAll(value, "\\n", "\n");
109
_dbg_assert_(key.find('\n') == std::string::npos);
110
map_[key] = I18NEntry(text);
111
}
112
}
113
}
114
115
std::map<std::string, std::string> I18NCategory::Missed() const {
116
std::lock_guard<std::mutex> guard(missedKeyLock_);
117
return missedKeyLog_;
118
}
119
120
std::shared_ptr<I18NCategory> I18NRepo::GetCategory(I18NCat category) {
121
std::lock_guard<std::mutex> guard(catsLock_);
122
if (category != I18NCat::NONE)
123
return cats_[(size_t)category];
124
else
125
return nullptr;
126
}
127
128
Path I18NRepo::GetIniPath(const std::string &languageID) const {
129
return Path("lang") / (languageID + ".ini");
130
}
131
132
bool I18NRepo::IniExists(const std::string &languageID) const {
133
File::FileInfo info;
134
if (!g_VFS.GetFileInfo(GetIniPath(languageID).ToString().c_str(), &info))
135
return false;
136
if (!info.exists)
137
return false;
138
return true;
139
}
140
141
bool I18NRepo::LoadIni(const std::string &languageID, const Path &overridePath) {
142
IniFile ini;
143
Path iniPath;
144
145
// INFO_LOG(Log::System, "Loading lang ini %s", iniPath.c_str());
146
if (!overridePath.empty()) {
147
iniPath = overridePath / (languageID + ".ini");
148
} else {
149
iniPath = GetIniPath(languageID);
150
}
151
152
if (!ini.LoadFromVFS(g_VFS, iniPath.ToString()))
153
return false;
154
155
Clear();
156
157
const std::vector<std::unique_ptr<Section>> &sections = ini.Sections();
158
159
std::lock_guard<std::mutex> guard(catsLock_);
160
for (auto &section : sections) {
161
for (size_t i = 0; i < (size_t)I18NCat::CATEGORY_COUNT; i++) {
162
if (!strcmp(section->name().c_str(), g_categoryNames[i])) {
163
cats_[i].reset(new I18NCategory(*section.get()));
164
}
165
}
166
}
167
168
languageID_ = languageID;
169
return true;
170
}
171
172
void I18NRepo::LogMissingKeys() const {
173
std::lock_guard<std::mutex> guard(catsLock_);
174
for (size_t i = 0; i < (size_t)I18NCat::CATEGORY_COUNT; i++) {
175
auto &cat = cats_[i];
176
for (auto &key : cat->Missed()) {
177
INFO_LOG(Log::System, "Missing translation [%s]: %s (%s)", g_categoryNames[i], key.first.c_str(), key.second.c_str());
178
}
179
}
180
}
181
182
std::shared_ptr<I18NCategory> GetI18NCategory(I18NCat category) {
183
if (category == I18NCat::NONE) {
184
return std::shared_ptr<I18NCategory>();
185
}
186
std::shared_ptr<I18NCategory> cat = g_i18nrepo.GetCategory(category);
187
_dbg_assert_(cat);
188
return cat;
189
}
190
191