Dictionary with two (or more) languages and change it when code is running - c++

I have to display some sentences on a screen.
However, the language can change if the user want to, so I do not want but I can do that :
if(language==1)
{
printf("Hello sir");
}
else if(language==2)
{
printf("Hola senor");
}
OR
printf("%s",language == 1 ? "Hello sir" : "Hola senor");
I do not want that because I have a lot of iterations.
Can I use map or enum and change it during code is running, I was thinking about a things like that :
#define MESSAGE_HELLO "Hello sir" OR "Hola senor"
printf("%s",MESSAGE_HELLO);
Do you have an idea ? Can you help me please ?

You can use some internationalization library that might help you. But here I will focus on how one can solve such a problem. Naturally, you need to have a set of languages, a set of message keys and a relationship between message keys and the languages, which would hold the actual message. Let's see some solutions:
Language file
You can store english.txt, etc. which would look like this:
hello_world="Hello World"
goodbye="Good bye"
and some other language, hungarian.txt for example:
hello_world="Heló Világ"
goodbye="Viszontlátásra"
etc.
Now, you can create an array of Map<String, Map<String, String>>, loop the languages, for each language process the corresponding file and fill the map accordingly.
Database
You can store a languages table, a message_keys table and a messages table. The messages table would have a foreign key pointing to languages and another one to message_keys and the actual message would be stored there as well. You could have an API that you could use in order to request items or groups of messages in a certain language.
There are many possible solutions.

In the professional world, I have often used tables (arrays) of phrases. Each slot in the array represents the phrase in another language.
static const char str_hello[] =
{
/* English */ "hello",
/* Spanish */ "hola",
/* German */ "guten tag",
//...
};
This has worked well in embedded systems.

You probably can create two maps for the sentences you want to translate - one map for one language - and then create a pointer to one of the maps. Then use pointer and [] to take sentences you need. Also, the pointer can be changed so that it points to another map at any moment.

Finally, I found a solution that fits with my requirements.
I use a .json file with all sentences and the languages I use.
{
"my-encoding": "UTF-8",
"messages": [
{
"MESS_HELLO": {
"english": "Hello",
"spanish": "Hola"
}
},
{
"MESS_GOODBYE": {
"english": "Bye",
"spanish": "Adios"
}
},
.......
]
}
To use .json file in C++, I included json-c lib in my project.
After loading the json file, I put it in a
std::unordered_map<std::string, std::unordered_map<std::string, std::string>> m_myTable;
With an ID declared in cpp (same as MESS_HELLO or MESS_GOODBYE).
It looks like that :
//"MESS_HELLO" -> { "english" -> "Hello" ; "spanish" -> "Hola" }
//"MESS_GOODBYE" -> { "english" -> "Bye" ; "other_language" -> "mess_in_other_language" ; +++ }
With that type I can do :
Easily add a new message by changing .json file + declaring in code a new ID
Modify the text by only change .json file
Add a new language by adding to .json file + adding several lines in code, but not a big deal.
To display it, I do something like
const auto &text_it = m_myTable.find("MESS_HELLO")
const auto &language_it = text_it->second.find("english");
printf("%s",language_it->second); //print Hello
Of course, it's in functions and well implemented, but I can't tell more about that.

Related

SwiftUI Localization Issue

I have a project with two targets representing two different final products. Until now the localization was shared between the two targets, but now I have just one string to be localized differently according to the active target. In order to avoid duplicating the Localizable.string file ad tweak the file target membership, I decided to create two different Localizable-Ext.string files containing just the string to be translated differently for each target.
I'm using the SwiftUI Text initializer accepting a LocalizedStringKey parameter which automatically looks up the corresponding translation inside the file. This is what has to be done in most cases. I noticed that this initializer also accepts a tableName parameter corresponding to the .string filename where the match should be taken.
What I'm trying to achieve is to have a custom Text initializer which takes the string key, looks up for it inside the default Localizable.string file and, if no match is found, falls back to the right file extension (string table) and search for it there. Apparently this is tough to achieve since I cannot manage to get the key value from the LocalizedStringKey instance.
I think you need something like
extension Text {
public init<S>(looking text: S) where S : StringProtocol {
let text = String(text)
var translated = NSLocalizedString(text, comment: "")
// returns same if no translation, so ...
if translated == text {
// ... continue in other table
translated = NSLocalizedString(text, tableName: "Localizable-Ext",
bundle: .main, value: text, comment: "")
}
// already translated, so avoid search again
self.init(verbatim: translated)
}
}

How to unit test class with no logic?

I find it easy to write unit tests for algorithms. For example, sort(List), it is easy to write tests like:
list = [2, 1, 4];
assert(sort(list) == [1, 2, 4]);
But I find it really hard to test methods that have no logic, no if statements, just a set of calls.
There are mainly 2 examples that I'd like an answer for how to unit test them:
Example 1:
Let's say I have a class that is responsible for writing some data to a file, but that data is written in a specific way by external functions (writeHeaderToFile, writeSerializedData and writeEndOfFile).
The data is not written straight as it is to the file, so if data is something like:
{
list: [
"item 1",
"item 2"
],
name: "aaa"
}
That doesn't mean that the file will be neither the plain version of that data (without white spaces) nor it will be a simple serialized version or encrypted version into file. The actual file binary will be something unknown to me. All I know is that I can use those 3 methods to write in the right way.
This file also contains some other information that doesn't come directly from those 3 methods, like a specific type of header (that again, I have no idea how it will be represented in the file binary).
That is the class:
class FileCreator {
populateFileWithData(File file, Data data) {
doBlockWithLock(file, {
Header header;
header.format = SomeFormat;
header.version = SomeVersion;
writeHeaderToFile(file, header);
writeSerializedData(file, data);
writeEndOfFile(file);
});
}
// Private
void doBlockWithLock(File file, Lambda block) {
file.holdWritingLock();
block();
file.releaseWritingLock();
}
}
Example 2:
class Controller {
var screenOne = new ScreenOne();
var screenTwo = new ScreenTwo();
var screenThree = new ScreenThree();
void reloadButtonWasClicked() {
screenOne.reload();
screenTwo.reload();
screenThree.reload();
}
}
For this one I could do something like this:
var mockScreenOne = Mock<ScreenOne>().reload.expectOneCall();
var mockScreenTwo = Mock<ScreenTwo>().reload.expectOneCall();
var mockScreenThree = Mock<ScreenThree>().reload.expectOneCall();
Controller controller = new Controller();
controller.screenOne = mockScreenOne;
controller.screenTwo = mockScreenTwo;
controller.screenThree = mockScreenThree;
controller.reloadButtonWasClicked();
mockScreenOne.verify();
mockScreenTwo.verify();
mockScreenThree.verify();
But I don't find much value in it since I'm just asserting that I'm doing the same thing I'm doing in the implementation. Seems like code repetition to me.
What would be the proper way of testing my 2 examples?
In the first example, if you wrote the messages in question and satisfied with your test coverage, there's no reason to reproduce that testing logic on FileCreator. You just need to test the FileCreator populateFileWithData method to make sure the file is written and maybe that the locking mechanism works.
You are right, your last test is rather trivial. I'd be tempted to omit writing it. But it depends. Is it likely that someone might come along and comment out one of those panel constructors? Do you have other tests that would identify such a problem?

Retrieve element from array in Coldfusion

I get the following struct return from disqus.com API and I just don't know how to retrieve only the following "id" value in red using Coldfusion.
This is the full array returned.
{
"cursor":{
"prev":null,
"hasNext":false,
"next":"1213061503000000:1:0",
"hasPrev":false,
"total":null,
"id":"1213061503000000:1:0",
"more":false
},
"code":0,
"response":[
{
"category":"1",
"reactions":0,
"identifiers":[],
"forum":"bobross",
"title":"Donkeys live a long time",
"dislikes":0,
"isDeleted":false,
"author":"1",
"userScore":0,
"id":"2",
"isClosed":false,
"posts":0,
"link":null,
"likes":0,
"message":"\"Donkeys live a long time. None of you have ever seen a dead donkey.\"",
"ipAddress":"127.0.0.1",
"slug":"donkeys_live_a_long_time",
"createdAt":"2008-06-10T02:31:43"
},
{
"category":"1",
"reactions":0,
"identifiers":[
"my-identifier"
],
"forum":"bobross",
"title":"Happy Accidents",
"dislikes":0,
"isDeleted":false,
"author":"1",
"userScore":0,
"id":"1",
"isClosed":false,
"posts":76,
"link":null,
"likes":0,
"message":"\"If you've painted before you know that we don't make mistakes -- we have happy accidents.\"",
"ipAddress":"127.0.0.1",
"slug":"happy_accidents",
"createdAt":"2008-06-10T01:31:43"
}
]
}
Well: firstly, that's a JSON packet not an array, so you need to turn it into a CFML data structure by deserialising it, eg:
data = deserializeJson(jsonPacket);
Then you'll have a native CFML struct (not an array... the array is one of the values within the struct).
From there, you would access any given element the way one normally would with a CFML struct, using struct / array notation, or struct functions / etc.
To directly address the item you point out, it would be (given the code above has been run first):
data.response[1].id
However I suspect you don't really want to address just that one value? But without more detail as to what you're trying to do, it's difficult to answer other than exactly what you want.
If you wanted to get all the IDs, one could do this:
ids = [];
for (singleResponse in data.response){
arrayAppend(ids, singleResponse.id);
}
Or on ColdFusion 10 there's more options with how to iterate over arrays.
Again: clarify what you're trying to do, and we can help you do it.

C++: How to localize an already-written program

I want to localize a program I already written.. It's fairly big (almost 50k lines) and ideally I want a system that allows me (the programmer) to do the least amount of work possible, and without major changes to the program - if possible none at all.
I looked at gettext() and liked it a lot, but it's unclear to me how it would translate strings such as these:
const char *Colors[] = {
{ "Red" },
{ "Blue" },
{ "Yellow" },
....
};
which are VERY common in my program.. Here replacing "Red" with gettext("Red") would obviously not work.
So I thought I would do something like, OutputFunction(gettext(Colors[Id])), but then how can I get a list of strings to localize? I doubt any program is smart enough to be able to get "Red", "Blue", "Yellow" from that in a to-localize list statically.
Since it's basically a server there is no need for the ability to change the language without recompiling (I can compile it for every supported language without any major problem or annoyance), I thought about C++0x's constexpr, which would be perfect! It would work in arrays/etc and I would easily get a list of strings to localize at compile time.. Too bad that no compiler implemented it yet.
Changing all the strings to an ID is not an option since it would require a massive amount of work on my part and especially creating a new id for every new string would be annoying as hell. The same applies to converting all the arrays like the one above to something else.
So, any ideas? :/
For your specific example, I might try something like:
// presumably globals
const char *Colors_en[] = {
{ "Red" },
{ "Blue" },
{ "Yellow" },
....
};
const char *Colors[] = {0};
// in main()
gettextarray(Colors_en, Colors, sizeof(Colors_en) / sizeof(char*));
gettextarray calls gettext on each input and writes an output. I think it could be implemented just as a call to std::transform. And you could avoid the size parameter with a bit of template trickery.
Another option is to call gettext at the point where any of the color strings is about to be used (displayed, or appended to a string for display). That means changing more code, but doesn't require that main() translates every set of strings in the program prior to doing anything that might use them.
If you don't want to do the work in main, you could do it in the code which uses the strings, something like this:
if (Colors[0] == 0)
gettextarray(Colors_en, Colors, sizeof(Colors_en) / sizeof(char*));
Or if your app is multithreaded, consider pthread_once or the equivalent in the thread API you use.
After a lot of playing around with gettext() and xgettext I think I found a way myself (sorry onebyone but I didn't like your approach.. There must be hundreds of arrays like that and I would have to import all of them in main(), that's a lot of extern and a lot of extra work :/).
Anyways, this is how I think it can theoretically be done (I haven't tried yet to actually translate but I don't see why it wouldn't work)
Two #define's:
#define _ gettext
#define __(x) x
Then you use _ to actually translate and __ to simply mark strings as "to be translated":
const char *Colors[] = {
{ __("Red") },
{ __("Blue") },
{ __("Yellow") },
....
};
void PrintColor(int id) {
cout << _("The color is: ") << _(Colors[id]);
}
Then you run:
xgettext -k_ -k__ *.cpp
And you get the following .po file:
#: test.cpp:2
msgid "Red"
msgstr ""
#: test.cpp:3
msgid "Blue"
msgstr ""
#: test.cpp:4
msgid "Yellow"
msgstr ""
#: test.cpp:9
msgid "The color is: "
msgstr ""
So, you use __ (or any other name, doesn't really matter) as a "dummy function" to just let xgettext know that the string needs to be translated, and _ to actually call gettext().
If you call _ with a string then the string will be marked to-be-translated as well, if you call it with a variable, array, whatever then it appears to be simply ignored by xgettext.
Great! Now all I have to do is go through 5 trillion files and add underscores around, as if I was a monkey :/

What configuration file format allows the inclusions of otherfiles and the inheritance of settings?

I'm writing a Multiplayer C++ based game.
I need a flexible file format to store information about the game charactors.
The game charactors will often not share the same attributes, or use a basew
For example:
A format that would allow me to do something like this:
#include "standardsettings.config"
//include other files which this file
//then changes
FastSpaceship:
Speed: 10 //pixels/sec
Rotation: 5 //deg/sec
MotherShip : FastSpaceship //inherits all the settings of the Spaceship ship
ShieldRecharge: 4
WeaponA [ power:10,
range:20,
style:fireball]
SlowMotherShip : MotherShip //inherits all the settings of the monther ship
Speed: 4 // override speed
I've been searching for a pre-existing format that does all this, or is similar, but with no luck. I'm keen not to reinvent the wheel unless I have to, so i was wondering if anyone knows any good configuration file formats that support these features
JSON is about the simplest file format around, has mature libraries, and you can interpret it to do anything you want.
{
"FastSpaceship" : {
"Speed" : 10,
"Rotation" : 5
},
"MotherShip" : {
"Inherits" : "FastSpaceship",
"ShieldRecharge" : 4,
"WeaponA": {
"Power": 10,
"Range": 20,
"style": "fireball"
}
},
"SlowMotherShip": {
"Inherits": "MotherShip",
"Speed": 4
}
}
YAML? It's like JSON without the commas and quotes.
You might want to check out some sort of frame-based representation, since it seems that's exactly what you're talking about. That wikipedia page links to a few existing implementations that maybe you could use, or create your own.
After alot of searching i've found a pretty good solution using Lua
Lua I found out was originally designed as a configuration file language, but then evolved into a complete programming language.
Example
util.lua
-- helper function needed for inheritance
function inherit(t) -- return a deep copy (incudes all subtables) of the table t
local new = {} -- create a new table
local i, v = next(t, nil) -- i is an index of t, v = t[i]
while i do
if type(v)=="table" then v=inherit(v) end -- deep copy
new[i] = v
i, v = next(t, i) -- get next index
end
return new
end
globalsettings.lua
require "util"
SpaceShip = {
speed = 1,
rotation =1
}
myspaceship.lua
require "globalsettings" -- include file
FastSpaceship = inherits(SpaceShip)
FastSpaceship.Speed = 10
FastSpaceship.Rotation = 5
MotherShip = inherits(FastSpaceship)
MotherShip.ShieldRecharge = 4
ShieldRecharge.WeaponA = {
Power = 10,
Range = 20,
Style = "fireball"
SlowMotherShip = inherits(MotherShip)
SlowMotherShip.Speed = 4
Using the print function in Lua its also easy to test the settings if they are correct. Syntax isn't quite as nice as I would like it, but its so close to what I want, i'm not gonna mind writing out a bit more.
The using the code here http://windrealm.com/tutorials/reading-a-lua-configuration-file-from-c.php I can read the settings into my C++ program