Boost C++ Libraries: Ticket #7266: Gettext path formats. https://svn.boost.org/trac10/ticket/7266 <pre class="wiki">I'm extremely happy about Boost.Locale, but I've found a few things lacking. So at first I wrote a some wrappers to get around a few flaws with my usage of Boost.Locale. One of these flaws was how it's hardcoded to use the Gettext directory hierarchy. I'd rather store my stuff in 'lang/en_US.mo' rather than 'lang/en_US/LC_MESSAGES/my_app.mo'. The patch adds a 'path format' feature, which allows you to format the directory structure when finding Gettext catalogs, to achieve the effect above. All you really have to do is run: gen.add_path_format("{1}/{2}.mo"); // Use a smaller hierarchy. to achieve the result that I prefer, or gen.add_path_format("{1}/{2}/{3}/{4}.mo"); // Use a Gettext hierarchy. to achieve the result that Boost.Locale uses right now. Ripped straight from Doxygen comments: {1} A path to search for catalogs in. {2} The locale's name. {3} The locale's category. {4} The Gettext domain. </pre><p> I apologize for the cut and paste from it but I'm having trouble with trac. The full thread with patches can be found at: <a class="ext-link" href="http://lists.boost.org/Archives/boost/2012/08/195789.php"><span class="icon">​</span>http://lists.boost.org/Archives/boost/2012/08/195789.php</a> </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/7266 Trac 1.4.3 166291@… Thu, 22 Nov 2012 18:35:34 GMT attachment set https://svn.boost.org/trac10/ticket/7266 https://svn.boost.org/trac10/ticket/7266 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">formats.patch</span> </li> </ul> <p> Patch v2 </p> Ticket 166291@… Thu, 22 Nov 2012 18:38:24 GMT <link>https://svn.boost.org/trac10/ticket/7266#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7266#comment:1</guid> <description> <p> So I've created this patch. (formats.patch) that uses a slightly different API to the first patch, and tweaks create_messages_info to be future-proof, but besides that it's 100% compatible with existing applications (I think down to the ABI level), and implements path formats. </p> <p> I haven't added anything to the generator class as from experience I create the messages facet myself to do anything with Gettext, but if it's a good idea I'd be happy to add it. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Artyom Beilis</dc:creator> <pubDate>Tue, 27 Nov 2012 16:19:31 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7266#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7266#comment:2</guid> <description> <p> I'm sorry I cound't work on this </p> <p> Unfortunatly the new patch still does changes ABI </p> <p> It inlines functions that were not inlined. </p> <p> I'll try to get to it this week. </p> <p> If no please ping me again :-) </p> </description> <category>Ticket</category> </item> <item> <author>166291@…</author> <pubDate>Sun, 09 Dec 2012 19:29:42 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7266#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7266#comment:3</guid> <description> <p> Ah, thanks for the response (which I completely missed). I'll try and fix it. How do you check these things? All I'm really working with is a text editor. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Artyom Beilis</dc:creator> <pubDate>Sat, 22 Dec 2012 20:02:00 GMT</pubDate> <title>status, milestone changed https://svn.boost.org/trac10/ticket/7266#comment:4 https://svn.boost.org/trac10/ticket/7266#comment:4 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> <li><strong>milestone</strong> <span class="trac-field-old">To Be Determined</span> → <span class="trac-field-new">Boost 1.54.0</span> </li> </ul> <p> I created an alternative patch on your patch base, it did some more radical changes that allow to add more details in future without breaking ABI or API. </p> <p> I attach the patch to the ticket so I can apply it later and not forget. I can't do it ready for 1.53 as it is closed for changes except bug fixes. </p> <p> I'll apply it to 1.54 </p> Ticket Artyom Beilis Sat, 22 Dec 2012 20:02:54 GMT attachment set https://svn.boost.org/trac10/ticket/7266 https://svn.boost.org/trac10/ticket/7266 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">gettext_paths.patch</span> </li> </ul> <p> Better patch for future updates </p> Ticket 166291@… Sat, 22 Dec 2012 20:19:46 GMT <link>https://svn.boost.org/trac10/ticket/7266#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7266#comment:5</guid> <description> <p> Wow! That's amazing. I'm in awe. </p> </description> <category>Ticket</category> </item> <item> <author>166291@…</author> <pubDate>Sat, 22 Dec 2012 23:35:17 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7266#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7266#comment:6</guid> <description> <p> Would it be possible to somehow expose this and do <a class="new ticket" href="https://svn.boost.org/trac10/ticket/7727" title="#7727: Feature Requests: Gettext information retriever (new)">#7727</a> at the same time? </p> </description> <category>Ticket</category> </item> <item> <author>166291@…</author> <pubDate>Mon, 07 Jan 2013 06:37:55 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7266#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7266#comment:7</guid> <description> <p> Okay, I've thought about this a lot and concluded that path formats are the wrong way to go about this in the short term, and only end up with technical debt. It should be handled by a callback class that receives information about the wanted catalog (locale name. category, etc) and returns the bytes of the file, as this is technically about custom file system support. </p> <p> I haven't actually coded anything yet, but this is how I'll think it'd work, and more importantly, why it'd be better: </p> <pre class="wiki">// --- BOOST.LOCALE CODE //! Information about a single catalog we want to find. class catalog_info { string language; string country; string variant; string encoding; string locale_category; string domain; }; //! Searches for, and loads a catalog. class default_catalog_loader { public: void add_search_path(string const&amp; path); void add_path_format(string const&amp; path); vector&lt;byte&gt; callback(catalog_info&amp; info) { vector&lt;string&gt; paths; paths += language; paths += language + "_" + country + "@" + variant; paths += language + "@" + variant; paths += language + "_" + country; foreach(search_path in search_paths) { foreach(path_format in path_formats) { foreach(path in paths) { string formatted = format(insert uber long line from existing code); if(FILE_EXISTS(formatted)) { // LOAD_FILE is hypothetical and utopian, thus UTF-8 encoded. return LOAD_FILE(formatted)); } } } } return vector&lt;byte&gt;(); // Empty vector. } } // --- USER CODE std::locale init_locale(void) { default_catalog_loader loader; loader.add_search_path("/usr/share/locale/"); loader.add_path_format("{1}/{2}/{3}/{4}.mo"); generator gen; std::locale genLoc = gen("en_US.UTF-8"); blg::messages_info info; info.language = "en"; info.country = "US"; info.encoding = "UTF-8"; info.variant = "@euro"; info.callback = boost::bind(loader::callback, &amp;loader, _1, _2); std::locale gettextLoc(genLoc, blg::create_messages_facet&lt;char&gt;(info)); return gettextLoc; } </pre><p> That would do what the existing code does (kind of, I'm sure I've forgotten something). Plus it means people could do things like this: </p> <pre class="wiki">// --- USER CODE // Include generated headers using bin2hex or something interesting. #include "en_US.mo.h" #include "en@euro.mo.h" vector&lt;byte&gt; memory_callback(catalog_info&amp; info) { vector&lt;string&gt; paths; paths += language; paths += language + "_" + country + "@" + variant; paths += language + "@" + variant; paths += language + "_" + country; foreach(path in paths) { byte* file_bytes = GET_MEMORY_FILE(path + ".mo"); if(file_bytes) { return VECTOR_FROM_BYTES(file_bytes); } } return vector&lt;byte&gt;(); // Empty vector. } </pre><p> Which implements a simple memory-based file loader. Personally I'd use this for my projects, as I already use a callback. </p> <p> I have a few notes on this approach however: </p> <p> There is shared repetition when looking for paths in multiple callback code. I don't know how to remove this without calling the callback multiple times, which is against this design (EXCEPT when we're trying to load multiple catalogs for multiple domains). </p> <p> It'd be stupidly easy to have a get_loaded_catalogs method that implements <a class="new ticket" href="https://svn.boost.org/trac10/ticket/7727" title="#7727: Feature Requests: Gettext information retriever (new)">#7727</a> in the library side, but it'd be best if it had some 'user' callback data. In the first case, which path format and search path and formatted path, in the second case, a pointer to the memory file. </p> <p> messages_info's callback would need to be changed, breaking the ABI. However, having a create_messages_facet that ONLY takes a callback in this case would work. </p> <p> Another thing is whether callbacks be classes? While the second example is one function long, making it a class would remove the horrible bind for class members, it'd allow the loader to be an interface which would be extendable if done right, I imagine callback data for catalog_info could be an abstract class defined by the loader too. </p> <p> What it'd also allow to do is custom file FORMATS, by returning something that mo_messages could use as a string table. This means for example, I could write a parser that loads po files uncompiled, or somebody completely insane could use XML, which I imagine could help transition. </p> <p> What're your thoughts on this? </p> </description> <category>Ticket</category> </item> </channel> </rss>