Browse Source

localization JSON file now supports simple key-value structure (#2359)

* localization JSON file now supports simple key-value structure

* docs updated, code refactoring

* minor fix

* AngelScript integration fixed
Arnis Lielturks 6 years ago
parent
commit
d4cf8a9f05

+ 16 - 1
Docs/Reference.dox

@@ -479,12 +479,17 @@ Before using the subsystem, the localization string collection(s) need to be loa
 
 \code
 Localization* l10n = GetSubsystem<Localization>();
+// 1st JSON file format
 l10n->LoadJSONFile("StringsEnRu.json");
 l10n->LoadJSONFile("StringsDe.json");
+
+// 2nd JSON file format
+l10n->LoadJSONFile("StringsLv.json", "lv");
 \endcode
 
-JSON files must be in UTF8 encoding without BOM. Sample files are in the bin/Data directory. The JSON files have the following format:
+JSON files must be in UTF8 encoding without BOM. Sample files are in the bin/Data directory. The JSON files must have one of the following formats:
 
+1. `LoadJSONFile("StringsEnRu.json")` method will automatically pick the language from the JSON file
 \code
 {
     "string id 1":{
@@ -500,6 +505,16 @@ JSON files must be in UTF8 encoding without BOM. Sample files are in the bin/Dat
 }
 \endcode
 
+2. You must pass 2nd argument to the `LoadJSONFile("StringsLv.json", "lv")` method to tell the parser which language will be loaded
+\code
+{
+    "string id 1": "value 1",
+    "string id 2": "value 2",
+    "string id 3": "value 3"
+}
+\endcode
+
+
 Any number of languages can be defined. Remember that language names and string identifiers are case sensitive. "En" and "en" are considered different languages.
 During the loading process languages are numbered in order of finding. Indexing starts from zero. The first found language is set to be initially active.
 

+ 1 - 0
Source/Samples/40_Localization/L10n.cpp

@@ -77,6 +77,7 @@ void L10n::InitLocalizationSystem()
     l10n->LoadJSONFile("StringsEnRu.json");
     // You can load multiple files
     l10n->LoadJSONFile("StringsDe.json");
+    l10n->LoadJSONFile("StringsLv.json", "lv");
     // Hook up to the change language
     SubscribeToEvent(E_CHANGELANGUAGE, URHO3D_HANDLER(L10n, HandleChangeLanguage));
 }

+ 3 - 2
Source/Urho3D/AngelScript/ResourceAPI.cpp

@@ -133,8 +133,9 @@ static void RegisterLocalization(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Localization", "void SetLanguage(const String&in)", asMETHODPR(Localization, SetLanguage, (const String&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Localization", "String Get(const String&in)", asMETHOD(Localization, Get), asCALL_THISCALL);
     engine->RegisterObjectMethod("Localization", "void Reset()", asMETHOD(Localization, Reset), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Localization", "void LoadJSON(const JSONValue&in)", asMETHOD(Localization, LoadJSON), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Localization", "void LoadJSONFile(const String&in)", asMETHOD(Localization, LoadJSONFile), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Localization", "void LoadMultipleLanguageJSON(const JSONValue&in)", asMETHOD(Localization, LoadMultipleLanguageJSON), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Localization", "void LoadSingleLanguageJSON(const JSONValue&in, const String&language = String(\"\") const)", asMETHOD(Localization, LoadSingleLanguageJSON), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Localization", "void LoadJSONFile(const String&in, const String language = String(\"\") const)", asMETHOD(Localization, LoadJSONFile), asCALL_THISCALL);
     engine->RegisterGlobalFunction("Localization@+ get_localization()", asFUNCTION(GetLocalization), asCALL_CDECL);
 }
 

+ 3 - 2
Source/Urho3D/LuaScript/pkgs/Resource/Localization.pkg

@@ -11,8 +11,9 @@ class Localization : public Object
     void SetLanguage(int index);
     String Get(const String id);
     void Reset();
-    void LoadJSON(const JSONValue& source);
-    void LoadJSONFile(const String name);
+    void LoadMultipleLanguageJSON(const JSONValue& source);
+    void LoadSingleLanguageJSON(const JSONValue& source, const String& language = String::EMPTY);
+    void LoadJSONFile(const String name, const String language = String::EMPTY);
 
     tolua_readonly tolua_property__get_set int numLanguages;
     tolua_readonly tolua_property__get_set int languageIndex;

+ 73 - 30
Source/Urho3D/Resource/Localization.cpp

@@ -152,52 +152,95 @@ void Localization::Reset()
     strings_.Clear();
 }
 
-void Localization::LoadJSON(const JSONValue& source)
+void Localization::LoadJSONFile(const String& name, const String language)
+{
+    auto* cache = GetSubsystem<ResourceCache>();
+    auto* jsonFile = cache->GetResource<JSONFile>(name);
+    if (jsonFile) {
+        if (language.Empty()) {
+            LoadMultipleLanguageJSON(jsonFile->GetRoot());
+        } else {
+            LoadSingleLanguageJSON(jsonFile->GetRoot(), language);
+        }
+    }
+}
+
+
+void Localization::LoadMultipleLanguageJSON(const JSONValue& source)
 {
     for (JSONObject::ConstIterator i = source.Begin(); i != source.End(); ++i)
     {
         String id = i->first_;
         if (id.Empty())
         {
-            URHO3D_LOGWARNING("Localization::LoadJSON(source): string ID is empty");
+            URHO3D_LOGWARNING("Localization::LoadMultipleLanguageJSON(source): string ID is empty");
             continue;
         }
-        const JSONValue& langs = i->second_;
-        for (JSONObject::ConstIterator j = langs.Begin(); j != langs.End(); ++j)
-        {
-            const String& lang = j->first_;
-            if (lang.Empty())
-            {
-                URHO3D_LOGWARNING("Localization::LoadJSON(source): language name is empty, string ID=\"" + id + "\"");
-                continue;
+        const JSONValue& value = i->second_;
+        if (value.IsObject()) {
+            for (JSONObject::ConstIterator j = value.Begin(); j != value.End(); ++j) {
+                const String &lang = j->first_;
+                if (lang.Empty()) {
+                    URHO3D_LOGWARNING(
+                            "Localization::LoadMultipleLanguageJSON(source): language name is empty, string ID=\"" + id + "\"");
+                    continue;
+                }
+                const String &string = j->second_.GetString();
+                if (string.Empty()) {
+                    URHO3D_LOGWARNING(
+                            "Localization::LoadMultipleLanguageJSON(source): translation is empty, string ID=\"" + id +
+                            "\", language=\"" + lang + "\"");
+                    continue;
+                }
+                if (strings_[StringHash(lang)][StringHash(id)] != String::EMPTY) {
+                    URHO3D_LOGWARNING(
+                            "Localization::LoadMultipleLanguageJSON(source): override translation, string ID=\"" + id +
+                            "\", language=\"" + lang + "\"");
+                }
+                strings_[StringHash(lang)][StringHash(id)] = string;
+                if (!languages_.Contains(lang))
+                    languages_.Push(lang);
+                if (languageIndex_ == -1)
+                    languageIndex_ = 0;
             }
-            const String& string = j->second_.GetString();
-            if (string.Empty())
-            {
+        } else {
+            URHO3D_LOGWARNING("Localization::LoadMultipleLanguageJSON(source): failed to load values, string ID=\"" + id + "\"");
+        }
+    }
+}
+
+void Localization::LoadSingleLanguageJSON(const JSONValue& source, const String& language)
+{
+    for (JSONObject::ConstIterator i = source.Begin(); i != source.End(); ++i)
+    {
+        String id = i->first_;
+        if (id.Empty())
+        {
+            URHO3D_LOGWARNING("Localization::LoadSingleLanguageJSON(source, language): string ID is empty");
+            continue;
+        }
+        const JSONValue& value = i->second_;
+        if (value.IsString()) {
+            if (value.GetString().Empty()) {
                 URHO3D_LOGWARNING(
-                    "Localization::LoadJSON(source): translation is empty, string ID=\"" + id + "\", language=\"" + lang + "\"");
+                        "Localization::LoadSingleLanguageJSON(source, language): translation is empty, string ID=\"" + id +
+                        "\", language=\"" + language + "\"");
                 continue;
             }
-            if (strings_[StringHash(lang)][StringHash(id)] != String::EMPTY)
-            {
+            if (strings_[StringHash(language)][StringHash(id)] != String::EMPTY) {
                 URHO3D_LOGWARNING(
-                    "Localization::LoadJSON(source): override translation, string ID=\"" + id + "\", language=\"" + lang + "\"");
+                        "Localization::LoadSingleLanguageJSON(source, language): override translation, string ID=\"" + id +
+                        "\", language=\"" + language + "\"");
             }
-            strings_[StringHash(lang)][StringHash(id)] = string;
-            if (!languages_.Contains(lang))
-                languages_.Push(lang);
-            if (languageIndex_ == -1)
-                languageIndex_ = 0;
+            strings_[StringHash(language)][StringHash(id)] = value.GetString();
+            if (!languages_.Contains(language))
+                languages_.Push(language);
+        } else {
+            URHO3D_LOGWARNING(
+                    "Localization::LoadSingleLanguageJSON(source, language): failed to load value, string ID=\"" + id +
+                    "\", language=\"" + language + "\"");
         }
     }
 }
 
-void Localization::LoadJSONFile(const String& name)
-{
-    auto* cache = GetSubsystem<ResourceCache>();
-    auto* jsonFile = cache->GetResource<JSONFile>(name);
-    if (jsonFile)
-        LoadJSON(jsonFile->GetRoot());
-}
-
 }

+ 5 - 3
Source/Urho3D/Resource/Localization.h

@@ -59,10 +59,12 @@ public:
     String Get(const String& id);
     /// Clear all loaded strings.
     void Reset();
-    /// Load strings from JSONValue.
-    void LoadJSON(const JSONValue& source);
     /// Load strings from JSONFile. The file should be UTF8 without BOM.
-    void LoadJSONFile(const String& name);
+    void LoadJSONFile(const String& name, const String language = String::EMPTY);
+    /// Load strings from JSONValue.
+    void LoadMultipleLanguageJSON(const JSONValue& source);
+    /// Load strings from JSONValue for specific language
+    void LoadSingleLanguageJSON(const JSONValue& source, const String& language = String::EMPTY);
 
 private:
     /// Language names.

+ 1 - 0
bin/Data/LuaScripts/40_Localization.lua

@@ -33,6 +33,7 @@ function InitLocalizationSystem()
     localization:LoadJSONFile("StringsEnRu.json")
     -- You can load multiple files
     localization:LoadJSONFile("StringsDe.json")
+    localization:LoadJSONFile("StringsLv.json", "lv")
     -- Hook up to the change language
     SubscribeToEvent("ChangeLanguage", "HandleChangeLanguage")
 end

+ 1 - 0
bin/Data/Scripts/40_Localization.as

@@ -35,6 +35,7 @@ void InitLocalizationSystem()
     localization.LoadJSONFile("StringsEnRu.json");
     // You can load multiple files
     localization.LoadJSONFile("StringsDe.json");
+    localization.LoadJSONFile("StringsLv.json", "lv");
     // Hook up to the change language
     SubscribeToEvent("ChangeLanguage", "HandleChangeLanguage");
 }

+ 6 - 0
bin/Data/StringsLv.json

@@ -0,0 +1,6 @@
+{
+	"lang": "Latviešu",
+	"quit": "Iziet",
+	"Press this button": "Nospied mani!",
+	"title": "Nosaukums!"
+}