Jump to content
  • Advertisement
Sign in to follow this  
Burnhard

Localisation (C++) question.

This topic is 3882 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Ok, I'm having this debate with a guy at work about how to handle string localisation in our software. For reasons I won't go into, we aren't using a resource file for our string localisation, we are using a series of text files. My idea is to parse in the text file and then put them in a std::map, accessing via a key, so the text file would look like this: [English] RED=Red BTERROR=Bluetooth Error Access would be like this: std::wstring myRedString = myLanguageMap ["RED"]; Ok, so far, so good. His idea, on the other hand, is to #define constants like this: #define IDS_STRING1 0 and then pass those into the map instead, like this: std::wstring myRedString = myLanguageMap [IDS_STRING1]; where the language file looks like this: [English] 0=Red His idea is that you will get a compile-time error if you try to use IDS_STRING2, because it isn't defined, whereas with my method you could write myLanguageMap ["REF"] by mistake and that would throw at runtime, rather than compile time. On the other hand, I prefer the verbosity and readabiliy of writing "RED" and also you don't have to maintain a set of constants alongside your language file. Double the work. Who is right?

Share this post


Link to post
Share on other sites
Advertisement
Whatever method you choose, don't use #define to define constants in C++. There are vastly superior methods to achieve this. In this particular case, enumerations happen to be auto-numbered and type-safe.

As for the actual choice, I would be tempted to propose an additional way of doing things, which is close to how C# handles this:
// A language representation, loaded from file
typedef std::map<std::string, std::wstring> data;

std::wstring read(const data &d, const std::string &k)
{
data::const_iterator it = d.find(k);
if (it == d.end()) return std::wstring();
return it->second;
}

// Auto-generated source file begins here ---

struct Strings
{
const std::wstring red;
const std::wstring bterror;

Strings(const data &d) :
red( read(d, "RED") ),
bterror( read(d, "BTERROR") )
{}
};

// Auto-generated source file ends here ---

std::wstring myRedString = myLanguageMap.red;


It is then a trivial task to generate the above given a list of all possible keys (which could be read from a sample description). This provides compile-time safety (but, as a consequence, is not extensible at runtime), enables intellisense, and avoids the difficulty of maintaining two sets of constants.

Share this post


Link to post
Share on other sites
I kind of like the simplicity of the approach of not using (resource) identifiers in any form (be they enums or other strings) and in the code make the string literal totally explicit.

cout << tr( "do you accept the pending connection (Y/n)") << endl;

tr() indicates a translation which uses std::map which is loaded on initialisation with the mappings that are made explicit in a file. The disadvantage is that it is not compile time checked but you have a marker in the "tr" - something on which to grep and cross reference with against the translation txt file.

I can understand others not liking this approach however without an indirection layer. I might be biased towards a too simple approach since I have to use the mess of mfc resource ids and string tables to do this stuff at the moment.

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
In this particular case, enumerations happen to be auto-numbered and type-safe.


I always thought the opposite was true. [PDF]

Quote:

C plus plus [C plus plus 03] currently provides only incremental improvements over C [C99] enums. Major safety and security problems remain, notably in the areas of type safety, unintended errors, code clarity, and code portability.

Share this post


Link to post
Share on other sites
Quote:
Original post by aaron_ds
I always thought the opposite was true. [PDF]


C++ enumerations are nowhere as safe as, say, OCaml sum types. However, they are type-safe as far as converting an integer to an enumeration goes (it cannot be done implicitely). In the current situation, there is no danger in mistakenly using an enumeration value as an integer, though there is a danger in using an integer as an enumeration value (when using integer constants instead of enumerations). The second danger is effectively solved by the requirement for explicit conversion.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!