c++gettextboost-locale

Boost.Locale translation - Preventing user modifications to dictionaries / embed dictionaries in executable


I use Boost.Locale with ICU backend (internally using GNU gettext) to do the translations. This translation uses dictionaries stored on disk. Search paths are provided through boost's generator class like so:

boost::locale:generator gen;
gen.add_messages_path("path");

By inspecting the boost's source code, this internally later passes the paths to localzation backend through localization_backend::set_option. In case of ICU localization backend implementation that I use, this finally makes the paths to be set in gnu_gettext::messages_info (paths field).

Now as for my question - my requirement is to make sure that the user will not change the texts e.g. by modifying the .mo dictionary file on disk. The reason I use Boost.Locale is its codepage translations support, multiple languages support etc. and I want to keep that, but I don't want the ability for the user to freely define the texts later used in the application. My initial thought was to use the dictionaries "in memory" in some way, e.g. by storing .mo file contents inside executable and pass already read data into the localization_backend somehow. However, after checking how it works internally (described above) it seems that the only supported option is to have the dictionaries read in "real time" as I do the translations, which may include any changes to those files done by the user. It's either that or maybe I'm missing something?

What are my options?


Solution

  • You can use the callback field on gnu_gettext::messages_info to provide a function that will be called instead of loading messages files from disk. From Custom Filesystem Support:

    namespace blg = boost::locale::gnu_gettext;
    blg::messages_info info;
    info.language = "he";
    info.country = "IL";
    info.encoding="UTF-8";
    info.paths.push_back(""); // You need some even empty path
    info.domains.push_back(blg::messages_info::domain("my_app"));
    info.callback = some_file_loader; // Provide a callback
    

    The callback signature is std::vector<char>(std::string const &file_name, std::string const &encoding). There's an example in the tests; this actually loads from disk, but you can adapt it to return hard-coded data instead.