i18n
Translation lookup
Loading...
Searching...
No Matches
I18n.hpp
Go to the documentation of this file.
1
11#pragma once
12
13#include <string>
14#include <map>
15#include <concepts>
16
17#if defined(__APPLE__)
18 #include <CoreFoundation/CoreFoundation.h>
19#elif defined(__unix__) || defined(__linux__)
20 #include <locale>
21#endif
22
23#include "ILocale.hpp"
24
35template <typename T>
36struct is_tuple : std::false_type {};
37
49template <typename... Args>
50struct is_tuple<std::tuple<Args...>> : std::true_type {};
51
60template <typename T>
62
69template <typename Base, typename Derived>
70concept DerivedFrom = std::derived_from<Base, Derived>;
71
81template<LocaleInterface T>
82class I18n {
83
84 public:
85
91 static I18n<T>& getInstance() {
92 static I18n<T> instance;
93
94 return instance;
95 }
96
100 I18n(const I18n&) = delete;
101
105 I18n& operator=(const I18n&) = delete;
106
119 template <DerivedFrom<T>... T_Child>
121 // Uses a pack expansion to call injectLocale<T_Locale>() for every type in the parameter pack.
122 (this->setSupportedLocale<T_Child>(), ...);
123 if (!_locale)
124 setDefault();
125 }
126
138 template <IsTuple T_Tuple>
140 // 1. Decompose the type T_Tuple into a pack of types.
141 std::apply([this](auto... locals) {
142 (this->setSupportedLocale<std::decay_t<decltype(locals)>>(), ...);
143 }, T_Tuple{}); // T_Tuple{} creates a temporary instance just to enable std::apply
144 if (!_locale)
145 setDefault();
146 }
147
156 void setDefault() {
157 if (_supportedLocales.empty())
158 return;
159
160 if (!_systemCode.empty() && setLocale(_systemCode))
161 return;
162 if (setLocale("en"))
163 return;
164
165 _locale = _supportedLocales.begin()->second.get();
166 }
167
174 bool setLocale(const std::string& code) {
175 auto it = _supportedLocales.find(code);
176
177 if (it != _supportedLocales.end()) {
178 _locale = it->second.get();
179 return true;
180 }
181 return false;
182 }
183
189 T* getLocale() const {
190 return _locale;
191 }
192
193 private:
194 std::string _systemCode;
195 T* _locale = nullptr;
196 std::unordered_map<std::string, std::unique_ptr<T>> _supportedLocales;
197
198 private:
202 I18n() {
203 setSystemCode();
204 }
205
214 void setSystemCode() {
215 #if defined(__APPLE__)
216 CFLocaleRef locale = CFLocaleCopyCurrent();
217 if (!locale) _systemCode = "en"; // fallback
218
219 CFStringRef identifier = (CFStringRef)CFLocaleGetValue(locale, kCFLocaleIdentifier);
220
221 char buffer[16] = {0};
222 if (CFStringGetCString(identifier, buffer, sizeof(buffer), kCFStringEncodingUTF8)) {
223 CFRelease(locale);
224 _systemCode = std::string(buffer, 2); // first 2 letters
225 }
226 CFRelease(locale);
227 #elif defined(__unix__) || defined(__linux__)
228 try {
229 std::locale loc(""); // system locale
230 std::string name = loc.name(); // e.g., "fr_FR.UTF-8"
231 if (!name.empty() && name != "C" && name != "POSIX")
232 _systemCode = name.substr(0, 2);
233 } catch (...) {}
234 #else
235 _systemCode = "en"; // fallback for other platforms
236
237#endif
238 }
239
248 template <DerivedFrom<T> T_Child>
249 void setSupportedLocale() {
250 auto newInstance = std::make_unique<T_Child>();
251 std::string key = newInstance->languageCode();
252 _supportedLocales[key] = std::move(newInstance);
253 }
254
255};
256
Internationalization manager for a specific locale type.
Definition I18n.hpp:40
void setSupportedLocales()
Register a list of supported locales using template parameter pack.
Definition I18n.hpp:120
T * getLocale() const
Get the currently selected locale instance.
Definition I18n.hpp:189
void setDefault()
Sets the default locale to use if no other locale is selected.
Definition I18n.hpp:109
I18n & operator=(const I18n &)=delete
delete Move constructor
bool setLocale(const std::string &code)
Select a specific locale by code.
Definition I18n.hpp:127
static I18n< T > & getInstance()
Get the I18n singleton instance.
Definition I18n.hpp:91
I18n(const I18n &)=delete
delete Copy constructor
DerivedFrom is accept supportedLocal class only.
Definition I18n.hpp:70
Using is_tuple specialisation this concept verify if it's a tuple.
Definition I18n.hpp:61
Detect whether a type is a std::tuple or not.
Definition TypeTraits.hpp:82