WordPress.org

Ready to get started?Download WordPress

Forums

Codestyling Localization
[resolved] MO-file generating error when there are 2+ textdomains (8 posts)

  1. Alexander Gieg
    Member
    Posted 1 year ago #

    Some big plugins have two or more textdomains. CSL seems to not like that, because when I click the generate mo-file button only the currently-selected textdomain in the drop-down to the left "goes" into that language's MO file, strings pertaining to the other textdomains being ignored.

    Is there a way to get all of a plugins' textdomains included in its MO file? I have looked around but haven't found an option to make this happen...

    http://wordpress.org/extend/plugins/codestyling-localization/

  2. codestyling
    Member
    Plugin Author

    Posted 1 year ago #

    There ist no way to do that, because it simply makes no sence. Having a mixture of different textdomains inside a plugin or theme doesn't work as you may expect. Thatswhy my plugin issues warnings and errors and separates the textdomains.

    Let's do a simple example. Starting with the simple plugin's code:

    <?php
    /*
    Plugin Name: Test the Textdomains
    */
    
    load_plugin_textdomain('first_textdomain', PLUGINDIR,  '');
    
    add_filter('the_content', 'append_paragraph');
    function append_paragraph($content) {
    	return $content.'<p>'.__('Hello', 'first_textdomain').' '.__('World.','second_textdomain').'</p>';
    }

    ... and following the normally *.po file content:

    #: test-the-textdomains.php:10
    msgid "Hello"
    msgstr "Say"
    
    #: test-the-textdomains.php:10
    msgid "World."
    msgstr "Yes."

    ...and lets assume, the *.mo file contains both.

    What would you expect as appended paragraph at each post content?
    This is the original (no translation loaded):

    <p>Hello World.</p>

    This is what you would expect:

    <p>Say Yes.</p>'

    and this is what you will get really:

    <p>Say World.</p>

    Because you load a language file in scope of "first_textdomain" and try to call for the translation of "second_textdomain", there is no loaded translation for and the original remains as is even if it would be inside the *.mo file loaded in scope of "first_textdomain".

    Thats the reason for the issued errors and excluding of mismatching textdomain strings, they can't be found even they would be inside the *.mo and only blow up the size of the file with no further value.

  3. codestyling
    Member
    Plugin Author

    Posted 1 year ago #

    To complete the subject, my plugin is able to support mixed textdomains, you can use it by loading both textdomains.
    As you may also notice, you will get the generate mo-file button for the "second_texdomain" too. By pressing it, my plugin generates a second file only containing those translations.

    Extend the plugin's code to:

    <?php
    /*
    Plugin Name: Test the Textdomains
    */
    
    load_plugin_textdomain('first_textdomain', PLUGINDIR,  '');
    load_plugin_textdomain('second_textdomain', PLUGINDIR,  '');
    
    add_filter('the_content', 'append_paragraph');
    function append_paragraph($content) {
    	return $content.'<p>'.__('Hello', 'first_textdomain').' '.__('World.','second_textdomain').'</p>';
    }

    you will get the translation as:
    <p>Say Yes.</p>

    Because my plugin is able to generate two files:

    first_textdomain-de_DE.mo
    second_textdomain-de_DE.mo

    and assumed you load both textdomains, than you get the expected results. This is an advance feature and can be used to split backend only strings from frontend only strings.

    This speeds up the page load on frontend, because normally the ammount of backend strings is in most cases dramatically higher than frontend strings (big plugins have approx. 700 strings but only approx. 30 used at frontend).
    Using this feature allows to load one of the textdomains only at backend and avoids at the above example string count the pollution of memory with 670 strings never used for frontend rendering.

  4. Alexander Gieg
    Member
    Posted 1 year ago #

    Ah! Now I understand the reason behind how the plugin work. However, I've seen cases of plugins that use their own textdomain plus the 'default' one (the developer probably forgot to add a textdomain to some strings), and these do work even though there's no second "load_plugin_textdomain()".

    In one specific case, what I observed happening was this: country names had no textdomain, and everything else was in the plugins' own textdomain. The output rendered country names in my language fine. But after I translated a few strings and generated the MO file with CSL, my translated strings went live, while country names all turned to English, since the 'default' text-domain wasn't included.

    The proper solution, sure, is to contact the developer for him to fix this in the code, but it takes a while for a new fixed version to be released, and I needed this live ASAP. So, the fastest solution I found was to load the PO file in Poedit, which doesn't care and simply includes everything in the MO, then use it to generate a "full" MO file.

    So, a middle ground solution might be this: a checkbox to enable inclusion of translated 'default' textdomain strings into the generated MO, which when ticked would show a red warning telling the translator to only enable it if otherwise existing translations do not appear and, that being the case, to contact the plugin author so he can fix his code. What do you think?

  5. codestyling
    Member
    Plugin Author

    Posted 1 year ago #

    You didn't understand it fully. The "standard" textdomain belongs to WordPress itself! If those strings are missing, your target blog has no WordPress language file for the core PHP files loaded.
    Even if you would produce the mo file by po edit with all the "default"s occuring contained, the texts won't be presented as the demo plugin above does show. "default" always lookup for WordPress language file and nothing else. Even if this texts are contained in your "xyz" textdomain, they won't be taken.

    Thats why this option is not included nor it makes sences and will not be included in future.

  6. Alexander Gieg
    Member
    Posted 1 year ago #

    But the point is that it worked. The plugin source has something like this at one point:

    _e('Sales in ', 'td') . _e('USA');

    Comes with a pt_BR.po that looks like this:

    #: file.php:100
    #@ td
    msgid "Sales in "
    msgstr "Vendas em "
    
    #: file.php:100
    #@ default
    msgid "USA"
    msgstr "Estados Unidos"

    Plus the corresponding pt_BR.mo. And, out of the box, shows 'Vendas em Estados Unidos'.

    Then, if I scan the source using CSL to generate a new PO, I find 'Sales in ' in the 'td' textdomain, and 'USA' in the 'default' one. And if I compile the scanned MO using CSL, without changing anything at all, the translation for 'USA' isn't included, and the output becomes 'Vendas em USA'.

    And then, if I load the above PO (the one scanned by CSL) in Poedit, and generate a new MO using it, and replace the CSL-generated MO with the Poedit-generated one, the result becomes 'Vendas em Estados Unidos' again, as it was with the pt-BR.mo provided with the plugin.

    Don't get me wrong. Your explanation makes sense, and I don't pretend to understand gettext better than you do. But the fact of the matter is that, when I experiment with Poedit, it works, even though it shouldn't.

  7. codestyling
    Member
    Plugin Author

    Posted 1 year ago #

    Your are kidding me, isn't it ?
    _e('Sales in ', 'td') . _e('USA');
    Running this code is useless, because what should the concatination of strings do? The function _e() echos the result immediately and returns nothing for concatination. Depending on where this is running, you will see either never the USA terms, because the code runs at a filter prior to the started output (and you can't set the HTTP header afterwards) or if it runs inside a templates code, you would get at least:

    Vendas em USA

    All other outputs you may get are depending on interaction of installed plugins like qTranslate, WPML or others, they may translate some terms under the hood. Having no plugins running and using the normal WordPress standard theme for your blog, you will never get USA translated.
    And furthermore USA is not a term of WordPress itself. The core doesn't use it.

  8. Alexander Gieg
    Member
    Posted 1 year ago #

    No, not kidding, just confused. :-) And my oversimplification above, being wrong and incomplete, certainly didn't help.

    But I finally discovered what was causing the weirdness after looking carefully at that plugin's code. Turns out the many strings without a textdomain, in the form __('Something');, are stored in a database table [EDIT: I mean, the original 'Something' is stored in the database, with the many __('Something'); being in the same file for other purposes], and somewhere else a loop loads lines from that table and present them with __($variable, 'td');, which works even though the PO file had the string stored as:

    #@ default
    msgid "Something"
    msgstr "Some other thing"

    I guess this means either MO files don't know anything about #@ restrictions, or maybe they do, and it's load_plugin_textdomain() who doesn't care about them, grabbing and inserting into the named textdomain everything found in the MO no matter what. Which goes to show that __($variable, 'td'); really is bad practice.

    Sorry for taking your time, and thanks for keeping in the conversation. It helped me learn a new thing I should take care to avoid once I start writing my own code!

Topic Closed

This topic has been closed to new replies.

About this Plugin

About this Topic