7 #if defined(ECERE_BOOTSTRAP) || defined(ECERE_STATIC)
9 #if !defined(ECERE_BOOTSTRAP)
14 #ifndef ECERE_BOOTSTRAP
15 #define FileOpen FileOpenBuffered
18 static Map<const String, Map<const String, const String>> moduleMaps { };
20 #define SWAP_DWORD(dword) ((((unsigned int)(dword) & 0x000000ff) << 24) \
21 | (((unsigned int)(dword) & 0x0000ff00) << 8) \
22 | (((unsigned int)(dword) & 0x00ff0000) >> 8) \
23 | (((unsigned int)(dword) & 0xff000000) >> 24))
25 public dllexport void LoadTranslatedStrings(const String moduleName, const char * name)
27 #if !defined(ECERE_NOFILE) && !defined(__EMSCRIPTEN__)
29 char fileName[MAX_LOCATION];
36 char genericLocale[256];
40 if(GetEnvironment("ECERE_LANGUAGE", language, sizeof(language)))
42 else if(GetEnvironment("LANGUAGE", language, sizeof(language)))
44 else if(GetEnvironment("LC_ALL", lcAll, sizeof(lcAll)))
46 else if(GetEnvironment("LC_MESSAGES", lcMessages, sizeof(lcMessages)))
48 else if(GetEnvironment("LANG", lang, sizeof(lang)))
55 if(language != locale)
56 strcpy(language, locale);
57 dot = strstr(language, ".");
60 // TODO: Try multiple languages defined in LANGUAGE
61 colon = strstr(language, ":");
64 if(!strcmpi(locale, "zh"))
65 strcpy(locale, "zh_CN");
71 strcpy(genericLocale, locale);
72 under = strchr(genericLocale, '_');
75 if(!strcmpi(genericLocale, "zh"))
76 strcpy(genericLocale, "zh_CN");
80 sprintf(fileName, "<:%s>locale/%s.mo", moduleName, locale);
82 sprintf(fileName, ":locale/%s.mo", locale);
83 f = FileOpen(fileName, read);
87 sprintf(fileName, "<:%s>locale/%s/LC_MESSAGES/%s.mo", moduleName, locale, name);
89 sprintf(fileName, ":locale/%s/LC_MESSAGES/%s.mo", locale, name);
90 f = FileOpen(fileName, read);
94 sprintf(fileName, "locale/%s/LC_MESSAGES/%s.mo", locale, name);
95 f = FileOpen(fileName, read);
99 sprintf(fileName, "/usr/share/locale/%s/LC_MESSAGES/%s.mo", locale, name);
100 f = FileOpen(fileName, read);
103 if(!f && locale && strcmpi(locale, genericLocale))
105 // Attempt with generic language
107 sprintf(fileName, "<:%s>locale/%s.mo", moduleName, genericLocale);
109 sprintf(fileName, ":locale/%s.mo", genericLocale);
110 f = FileOpen(fileName, read);
114 sprintf(fileName, "<:%s>locale/%s/LC_MESSAGES/%s.mo", moduleName, genericLocale, name);
116 sprintf(fileName, ":locale/%s/LC_MESSAGES/%s.mo", genericLocale, name);
117 f = FileOpen(fileName, read);
121 sprintf(fileName, "locale/%s/LC_MESSAGES/%s.mo", genericLocale, name);
122 f = FileOpen(fileName, read);
126 sprintf(fileName, "/usr/share/locale/%s/LC_MESSAGES/%s.mo", genericLocale, name);
127 f = FileOpen(fileName, read);
134 f.Read(&magic, sizeof(uint), 1);
135 if(magic == 0x950412de || magic == 0xde120495)
137 Map<const String, const String> textMap;
138 bool swap = magic != 0x950412de;
141 uint origStrings = 0, transStrings = 0;
142 uint hashingSize = 0, hashingOffset = 0;
144 f.Read(&revision, sizeof(uint), 1); if(swap) revision = SWAP_DWORD(revision);
145 f.Read(&numStrings, sizeof(uint), 1); if(swap) numStrings = SWAP_DWORD(numStrings);
146 f.Read(&origStrings, sizeof(uint), 1); if(swap) origStrings = SWAP_DWORD(origStrings);
147 f.Read(&transStrings, sizeof(uint), 1); if(swap) transStrings = SWAP_DWORD(transStrings);
148 f.Read(&hashingSize, sizeof(uint), 1); if(swap) hashingSize = SWAP_DWORD(hashingSize);
149 f.Read(&hashingOffset, sizeof(uint), 1); if(swap) hashingOffset = SWAP_DWORD(hashingOffset);
154 MapIterator<const String, Map<const String, const String>> it { map = moduleMaps };
155 if(it.Index(name, false))
157 // TOFIX: delete moduleMaps[module];
159 moduleMaps[name] = textMap = { };
160 for(c = 0; c < numStrings; c++)
162 uint len = 0, offset = 0;
163 char * original = null, * translated = null;
165 f.Seek(origStrings + c*2*sizeof(uint), start);
166 f.Read(&len, sizeof(uint), 1); if(swap) len = SWAP_DWORD(len);
167 f.Read(&offset, sizeof(uint), 1); if(swap) offset = SWAP_DWORD(offset);
168 f.Seek(offset, start);
170 original = new byte[len + 1];
171 f.Read(original, 1, len + 1);
173 f.Seek(transStrings + c*2*sizeof(uint), start);
174 f.Read(&len, sizeof(uint), 1); if(swap) len = SWAP_DWORD(len);
175 f.Read(&offset, sizeof(uint), 1); if(swap) offset = SWAP_DWORD(offset);
176 f.Seek(offset, start);
178 translated = new byte[len + 1];
179 f.Read(translated, 1, len + 1);
183 MapIterator<String, String> it { map = textMap };
184 // TOFIX: Memory leak if the add fails
185 if(it.Index(original, false))
188 textMap[original] = translated;
198 printf("Invalid format while loading %s\n", fileName);
205 public dllexport void UnloadTranslatedStrings(const String name)
207 MapIterator<const String, Map<const String, const String>> it { map = moduleMaps };
208 if(it.Index(name, false))
211 moduleMaps.Delete(it.pointer);
215 public dllexport const char * GetTranslatedString(const String name, const char * string, const char * stringAndContext)
217 Map<const String, const String> textMap = moduleMaps ? moduleMaps[name] : null;
218 const char * result = textMap ? textMap[stringAndContext ? stringAndContext : string] : string;
219 return (result && result[0]) ? result : string;