45static const unsigned char qm_magic[16] = {0x3c, 0xb8, 0x64, 0x18, 0xca, 0xef, 0x9c, 0x95, 0xcd, 0x21, 0x1c, 0xbf, 0x60, 0xa1, 0xbd, 0xdd};
67 std::string language = e;
68 language = language.substr(0, language.find(
"."));
69 language = language.substr(0, language.find(
"@"));
72 for (
char c: language)
73 if (!strchr(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-.@", c))
76 std::transform(language.begin(), language.end(), language.begin(), tolower);
79 i18n_log(
"Language from LANG/LC_ALL suspiciously long, defaulting to en");
135 std::string filename, contents;
136 const unsigned char *data;
139 unsigned char chunk_type;
144 std::string translation,
source, context;
146 i18n_log(
"i18n_set_language(" << directory <<
"," << base <<
")");
147 if (!directory || !base)
150 if (language.empty())
152 filename = std::string(directory) +
"/" + base +
"_" + language +
".qm";
153 i18n_log(
"Loading translations for language " << language);
155 boost::system::error_code ignored_ec;
156 if (boost::filesystem::exists(filename, ignored_ec)) {
158 i18n_log(
"Failed to load translations file: " << filename);
162 i18n_log(
"Translations file not found: " << filename);
163 filename = std::string(base) +
"_" + language +
".qm";
164 if (!find_embedded_file(filename, contents)) {
165 i18n_log(
"Embedded translations file not found: " << filename);
166 const char *underscore = strchr(language.c_str(),
'_');
168 std::string fallback_language = std::string(language, 0, underscore - language.c_str());
169 filename = std::string(directory) +
"/" + base +
"_" + fallback_language +
".qm";
170 i18n_log(
"Loading translations for language " << fallback_language);
171 if (boost::filesystem::exists(filename, ignored_ec)) {
173 i18n_log(
"Failed to load translations file: " << filename);
177 i18n_log(
"Translations file not found: " << filename);
178 filename = std::string(base) +
"_" + fallback_language +
".qm";
179 if (!find_embedded_file(filename, contents)) {
180 i18n_log(
"Embedded translations file not found: " << filename);
190 data = (
const unsigned char*)contents.c_str();
191 datalen = contents.size();
193 i18n_log(
"Translations file size: " << datalen);
220 if (datalen <
sizeof(qm_magic) || memcmp(data, qm_magic,
sizeof(qm_magic))) {
221 i18n_log(
"Bad translations file format: " << filename);
224 idx +=
sizeof(qm_magic);
226 while (idx < datalen) {
227 if (idx + 5 > datalen) {
228 i18n_log(
"Bad translations file format: " << filename);
231 chunk_type = data[idx++];
232 chunk_size = be32(data+idx);
235 i18n_log(
"Found " << chunk_type <<
" of " << chunk_size <<
" bytes");
236 if (chunk_size >= datalen || idx > datalen - chunk_size) {
237 i18n_log(
"Bad translations file format: " << filename);
241 switch (chunk_type) {
243 i18n_log(
"Found offsets at " << idx);
246 num_messages = chunk_size / 8;
249 i18n_log(
"Found messages at " << idx);
253 i18n_log(
"Found unsupported chunk type: " << chunk_type);
265 i18n_log(
"No messages chunk found");
269 for (
uint32_t m = 0; m < num_messages; ++m) {
270 be32(data+offsets_idx+m*8);
271 idx = be32(data+offsets_idx+m*8+4);
274 if (idx > datalen || idx + 1 > datalen) {
275 i18n_log(
"Bad translations file format: " << filename);
280 if (idx + 5 > datalen) {
281 i18n_log(
"Bad translations file format: " << filename);
284 chunk_type = data[idx++];
286 if (chunk_type == 0x01) {
287 i18n_entries[context + std::string(
"",1) +
source] = translation;
288 context = std::string();
290 translation = std::string();
294 chunk_size = be32(data+idx);
296 i18n_log(
"Found " << chunk_type <<
" of " << chunk_size <<
" bytes");
297 if (chunk_size >= datalen || idx > datalen - chunk_size) {
298 i18n_log(
"Bad translations file format: " << filename);
301 switch (chunk_type) {
303 translation = utf16(data+idx, chunk_size);
304 i18n_log(
"Found translation: " << translation);
307 source = utf8(data+idx, chunk_size);
311 context = utf8(data+idx, chunk_size);
312 i18n_log(
"Found context: " << context);