i18n
Loading...
Searching...
No Matches
I18n.hpp
Go to the documentation of this file.
1
8#pragma once
9
10#include <string>
11#include <memory>
12#include <unordered_map>
13#include <tuple>
14#include <utility>
15#include <type_traits>
16
17#include "ILocale.hpp"
18#include "TypeTraits.hpp"
19
20#if defined(__APPLE__)
21 #include <CoreFoundation/CoreFoundation.h>
22#elif defined(__unix__) || defined(__linux__)
23 #include <locale>
24#endif
25
26
36template<typename T, typename = typename std::enable_if<is_derived_from<T, ILocale>::value>::type>
37class I18n {
38
39 public:
40
46 static I18n<T>& getInstance() {
47 static I18n<T> instance;
48
49 return instance;
50 }
51
55 I18n(const I18n&) = delete;
56
60 I18n& operator=(const I18n&) = delete;
61
71 template<typename... T_Child>
72 typename std::enable_if<all_derived<T, T_Child...>::value, void>::type
74 // C++11 pack expansion via initializer list trick
75 auto l = { (setSupportedLocale<T_Child>(), 0)... };
76 (void)l; //silence !
77 if (!_locale) setDefault();
78 }
79
80
89 template<typename T_Tuple>
90 typename std::enable_if<is_tuple<T_Tuple>::value, void>::type
92 registerTupleLocales_using_index<T_Tuple>(
93 typename make_index_sequence_impl<std::tuple_size<T_Tuple>::value>::type{}
94 );
95 if (!_locale) setDefault();
96 }
97
106 void setDefault() {
107 if (_supportedLocales.empty())
108 return;
109
110 if (!_systemCode.empty() && setLocale(_systemCode))
111 return;
112 if (setLocale("en"))
113 return;
114
115 _locale = _supportedLocales.begin()->second.get();
116 }
117
124 bool setLocale(const std::string& code) {
125 typename std::unordered_map<std::string, std::unique_ptr<T>>::iterator it = _supportedLocales.find(code);
126
127 if (it != _supportedLocales.end()) {
128 _locale = it->second.get();
129 return true;
130 }
131 return false;
132 }
133
139 T* getLocale() const {
140 return _locale;
141 }
142
143 private:
144 std::string _systemCode;
145 T* _locale = nullptr;
146 std::unordered_map<std::string, std::unique_ptr<T>> _supportedLocales;
147
148 private:
152 I18n() {
153 setSystemCode();
154 }
155
164 void setSystemCode() {
165 #if defined(__APPLE__)
166 // Use explicit casts and checks for C++11 compatibility
167 CFLocaleRef locale = CFLocaleCopyCurrent();
168 if (!locale) {
169 _systemCode = "en"; // fallback
170 return;
171 }
172
173 CFStringRef identifier = (CFStringRef)CFLocaleGetValue(locale, kCFLocaleIdentifier);
174
175 char buffer[16] = {0};
176 if (CFStringGetCString(identifier, buffer, sizeof(buffer), kCFStringEncodingUTF8)) {
177 _systemCode = std::string(buffer, 2); // first 2 letters
178 } else {
179 _systemCode = "en"; // second fallback
180 }
181 CFRelease(locale);
182 #elif defined(__unix__) || defined(__linux__)
183 try {
184 // C++11 locale handling
185 std::locale loc(""); // system locale
186 std::string name = loc.name(); // e.g., "fr_FR.UTF-8"
187 if (!name.empty() && name != "C" && name != "POSIX")
188 _systemCode = name.substr(0, 2);
189 } catch (...) {
190 _systemCode = "en"; // fallback on error
191 }
192 #else
193 _systemCode = "en"; // fallback for other platforms
194 #endif
195 }
196
205 template <typename T_Child, typename = typename std::enable_if<is_derived_from<T_Child, T>::value>::type>
206 void setSupportedLocale() {
207 // C++11 replacement for std::make_unique (C++14)
208 std::unique_ptr<T_Child> newInstance(new T_Child());
209 std::string key = newInstance->languageCode();
210 _supportedLocales[key] = std::move(newInstance);
211 }
212
213 template<typename Tuple, std::size_t... Is>
214 void registerTupleLocales_using_index(index_sequence<Is...>) {
215 // C++11 Pack Expansion via initializer list trick
216 auto l = { (setSupportedLocale<typename std::tuple_element<Is, Tuple>::type>(), 0)... };
217 (void)l;
218 }
219
220};
Internationalization manager for a specific locale type.
Definition I18n.hpp:37
T * getLocale() const
Get the currently selected locale instance.
Definition I18n.hpp:139
void setDefault()
Sets the default locale to use if no other locale is selected.
Definition I18n.hpp:106
I18n & operator=(const I18n &)=delete
delete Move constructor
std::enable_if< all_derived< T, T_Child... >::value, void >::type setSupportedLocales()
Register a list of supported locales using template parameter pack.
Definition I18n.hpp:73
bool setLocale(const std::string &code)
Select a specific locale by code.
Definition I18n.hpp:124
static I18n< T > & getInstance()
Get the I18n singleton instance.
Definition I18n.hpp:46
I18n(const I18n &)=delete
delete Copy constructor
std::enable_if< is_tuple< T_Tuple >::value, void >::type setSupportedLocales()
Register supported locales using a std::tuple of types. Each type must derive from T and be default-c...
Definition I18n.hpp:91
Trait to check if all types in a pack are derived from a base type.
Definition TypeTraits.hpp:37
Base Type to represent a sequence of compile time indice.
Definition TypeTraits.hpp:102
recursive template to generate the sequence
Definition TypeTraits.hpp:111