@agenCi How about you try to have a default language and a current language, both loaded in memory, so when “getStringForKey” doesn’t find a string, it gets it from the default language (which must have the string), otherwise you do what you need to do.
Regardless though, you should always handle errors gracefully, and a crash isn’t very graceful.
I’ll show [key], if no value is found. This way I can see easier missing entries. The advice from @R101 will make it harder to fix missing translations.
This happens when calling getStringForKey, but only happens on a bunch of devices, most of the time works fine, so I’m sure the key and string exist… Last, the string is 101 char long.
Any ideas? I don’t have a device to reproduce and do proper debugging so that’s all the information I have…
Could it be possible that the json file is not properly loaded for some reason?
If I am reading that crash correctly, it looks like you’re trying to either assign a nullptr to a std::string, or you’re trying to de-reference a nullptr into a std::string. You should really be validating any data, because you’re making a lot of assumptions about data that is being read from a file.
For instance:
string LanguageManager::getStringForKey(string key) {
if (!document.HasMember(key.c_str()) || document[key.c_str()].IsNull())
return "";
return document[key.c_str()].GetString();
}
std::vector<std::string> LanguageManager::getArrayForKey(string key) {
if (!document.HasMember(key.c_str()) || document[key.c_str()].IsNull() || !document[key.c_str()].IsArray())
return std::vector<std::string>();
std::vector<std::string> s;
const rapidjson::Value& v = document[key.c_str()];
for (rapidjson::SizeType i = 0; i < v.Size(); i++) {
s.push_back(v[i].GetString());
}
return s;
}
There could be more code there that isn’t quite protected, but it’s up to you to go through it and make sure you cover all possible points of failure.
Aside from that, if you define RAPIDJSON_HAS_STDSTRING=1 in your makefile (so it becomes a pre-processor define), then you won’t need to write lines like this:
document[key.c_str()]
but instead just use the std::string without getting the raw pointer:
Many thanks for the help, but I don’t think defensive programming is the solution here, I have control over the json files, so I know the translations will exist, both the key and value. Also, if I can’t load the translations the game should exit, so returning an empty string I think is not going to help…
What I really need to do is to get to the bottom of this, find the root cause of crash and try to fix it… could it be possible that the json file is not properly loaded? not having a device for debugging really sucks…
Would you guys think I should probably throw an exception if the json file does not load? Here:
How about forcing the error in your dev environment, and by that I mean introduce all the possible incorrect conditions you can think of to try to replicate that exact error. At least then you would have narrowed down the possible reasons or section of code that is causing it.
It turns out some defensive programming could’ve helped. The problem was that the json file was not being parsed properly because the XCode was not linking the Spanish translations properly, that is why it was failing in some devices (the ones in English were just fine), and also why it happened only on iOS (Android does not have all this linking non-sense).
Thanks very much everyone for the help! Problem solved!