i18n: (#858) Handling localization for libraries within static executables
[sdk] / ecere / src / sys / i18n.ec
index 74b3026..6bad435 100644 (file)
@@ -1,19 +1,29 @@
+#ifndef ECERE_NOFILE
 import "File"
+#endif
 import "Map"
 
+#if defined(ECERE_BOOTSTRAP) || defined(ECERE_STATIC)
+#define dllexport
+#if !defined(ECERE_BOOTSTRAP)
+#define stdcall
+#endif
+#endif
+
 #ifndef ECERE_BOOTSTRAP
 #define FileOpen FileOpenBuffered
 #endif
 
-Map<String, Map<String, String>> moduleMaps { };
+static Map<String, Map<String, String>> moduleMaps { };
 
 #define SWAP_DWORD(dword) ((((unsigned int)(dword) & 0x000000ff) << 24) \
                          | (((unsigned int)(dword) & 0x0000ff00) <<  8) \
                          | (((unsigned int)(dword) & 0x00ff0000) >>  8) \
                          | (((unsigned int)(dword) & 0xff000000) >> 24))
 
-public dllexport void LoadTranslatedStrings(Module module, char * name)
+public dllexport void LoadTranslatedStrings(String moduleName, char * name)
 {
+#ifndef ECERE_NOFILE
    File f;
    char fileName[MAX_LOCATION];
 
@@ -22,6 +32,9 @@ public dllexport void LoadTranslatedStrings(Module module, char * name)
    char lang[256];
    char lcMessages[256];
    char * locale = null;
+   char genericLocale[256];
+
+   genericLocale[0] = 0;
 
    if(GetEnvironment("LANGUAGE", language, sizeof(language)))
       locale = language;
@@ -35,19 +48,36 @@ public dllexport void LoadTranslatedStrings(Module module, char * name)
    if(locale)
    {
       char * dot;
-      strcpy(language, locale);
+      if(language != locale)
+         strcpy(language, locale);
       dot = strstr(language, ".");
       if(dot) *dot = 0;
       locale = language;
    }
+   if(locale)
+   {
+      char * under;
+      strcpy(genericLocale, locale);
+      under = strchr(genericLocale, '_');
+      if(under)
+         *under = 0;
+   }
 
-   if(module.name)
-      sprintf(fileName, "<:%s>/locale/%s/LC_MESSAGES/%s.mo", module.name, locale, name);
+   if(moduleName)
+      sprintf(fileName, "<:%s>locale/%s.mo", moduleName, locale);
    else
-      sprintf(fileName, ":locale/%s/LC_MESSAGES/%s.mo", locale, name);
+      sprintf(fileName, ":locale/%s.mo", locale);
    f = FileOpen(fileName, read);
    if(!f)
    {
+      if(moduleName)
+         sprintf(fileName, "<:%s>locale/%s/LC_MESSAGES/%s.mo", moduleName, locale, name);
+      else
+         sprintf(fileName, ":locale/%s/LC_MESSAGES/%s.mo", locale, name);
+      f = FileOpen(fileName, read);
+   }
+   if(!f)
+   {
       sprintf(fileName, "locale/%s/LC_MESSAGES/%s.mo", locale, name);
       f = FileOpen(fileName, read);
    }
@@ -56,6 +86,35 @@ public dllexport void LoadTranslatedStrings(Module module, char * name)
       sprintf(fileName, "/usr/share/locale/%s/LC_MESSAGES/%s.mo", locale, name);
       f = FileOpen(fileName, read);
    }
+
+   if(!f && locale && strcmpi(locale, genericLocale))
+   {
+      // Attempt with generic language
+      if(moduleName)
+         sprintf(fileName, "<:%s>locale/%s.mo", moduleName, genericLocale);
+      else
+         sprintf(fileName, ":locale/%s.mo", name, genericLocale);
+      f = FileOpen(fileName, read);
+      if(!f)
+      {
+         if(moduleName)
+            sprintf(fileName, "<:%s>locale/%s/LC_MESSAGES/%s.mo", moduleName, genericLocale, name);
+         else
+            sprintf(fileName, ":locale/%s/LC_MESSAGES/%s.mo", genericLocale, name);
+         f = FileOpen(fileName, read);
+      }
+      if(!f)
+      {
+         sprintf(fileName, "locale/%s/LC_MESSAGES/%s.mo", genericLocale, name);
+         f = FileOpen(fileName, read);
+      }
+      if(!f)
+      {
+         sprintf(fileName, "/usr/share/locale/%s/LC_MESSAGES/%s.mo", genericLocale, name);
+         f = FileOpen(fileName, read);
+      }
+   }
+
    if(f)
    {
       uint magic = 0;
@@ -75,16 +134,16 @@ public dllexport void LoadTranslatedStrings(Module module, char * name)
          f.Read(&transStrings, sizeof(uint), 1);   if(swap) SWAP_DWORD(transStrings);
          f.Read(&hashingSize, sizeof(uint), 1);    if(swap) SWAP_DWORD(hashingSize);
          f.Read(&hashingOffset, sizeof(uint), 1);  if(swap) SWAP_DWORD(hashingOffset);
-         
+
          if(!moduleMaps)
             moduleMaps = { };
          {
             MapIterator<String, Map<String, String>> it { map = moduleMaps };
-            if(it.Index(module.name, false))
+            if(it.Index(name, false))
                delete it.data;
             // TOFIX: delete moduleMaps[module];
          }
-         moduleMaps[module.name] = textMap = { };
+         moduleMaps[name] = textMap = { };
          for(c = 0; c < numStrings; c++)
          {
             uint len = 0, offset = 0;
@@ -107,7 +166,14 @@ public dllexport void LoadTranslatedStrings(Module module, char * name)
             f.Read(translated, 1, len + 1);
 
             if(len)
-               textMap[original] = translated;
+            {
+               MapIterator<String, String> it { map = textMap };
+               // TOFIX: Memory leak if the add fails
+               if(it.Index(original, false))
+                  delete translated;
+               else
+                  textMap[original] = translated;
+            }
             else
                delete translated;
             delete original;
@@ -120,20 +186,22 @@ public dllexport void LoadTranslatedStrings(Module module, char * name)
       }
       delete f;
    }
+#endif
 }
 
-public dllexport void UnloadTranslatedStrings(Module module)
+public dllexport void UnloadTranslatedStrings(String name)
 {
    MapIterator<String, Map<String, String>> it { map = moduleMaps };
-   if(it.Index(module.name, false))
+   if(it.Index(name, false))
    {
       it.data.Free();
       moduleMaps.Delete(it.pointer);
    }
 }
 
-public dllexport char * GetTranslatedString(Module module, char * string)
+public dllexport char * GetTranslatedString(String name, char * string, char * stringAndContext)
 {
-   Map<String, String> textMap = moduleMaps ? moduleMaps[module.name] : null;
-   return textMap ? textMap[string] : string;
+   Map<String, String> textMap = moduleMaps ? moduleMaps[name] : null;
+   char * result = textMap ? textMap[stringAndContext ? stringAndContext : string] : string;
+   return (result && result[0]) ? result : string;
 }