4

I want to change some (20-30) of the defaults strings on Wordpress back-end (not to translate).

I know there is gettext filter but I think could lead to performance issues if we have a lot of strings.

Another method I tried was to create and use an admin-en_US.po file.

Which of the above methods are faster? Is there any better way? What do you suggest without affect performance?

3 Answers 3

4

Additionally to kaiser's answer, you can load customized .mo files that overrides the original file using load_textdomain_mofile filter. For example:

add_filter( 'load_textdomain_mofile', 'cyb_filter_load_textdomain_mofile', 10, 2 );
function cyb_filter_load_textdomain_mofile( $mofile, $domain ) {
    if ( $domain == 'some-textdomain-to-override' ) {
        $mofile = WP_LANG_DIR . '/overrides/' . basename( $mofile );
    }
    return $mofile;
}

It may be faster but you will be required to check for changes on every update in order to keep your .mo file syncrhonized with the original.

4

Yes, you can use the gettext filter. No, it's not the fastest filter, but that is only true when you add a callback to that filter in the wild:

Bad Example

This is bad as it makes a string comparison for every of the hundreds of translatable requests in the current request:

add_filter( 'gettext', function( $translated, $original, $domain ) {
    return 'foo' === $original ? 'bar' : $translated;
}, 10, 3 );

Good Example

You can speed things up by adding the filter right before you need it, then remove it:

Imagine the following bit of core, plugin or theme code (example):

do_action( 'before' );
_e( 'foo', 'textdomain' );

Now let's write a callback for the gettext filter:

add_action( 'before', 'wpse228163GettextReplacement', 10, 3 );

function wpse228163GettextReplacement( $translated, $original, $domain ) 
{
    // Instantly remove the filter so it only runs once
    remove_filter( current_filter(), __FUNCTION__ );

    return 'foo' === $original 
        ? 'bar' 
        : $translated;
}

ProTip: When you have multiple strings to replace, you can hook into the latest action or filter before your first string, then remove the callback in the next action or filter after your last string.

do_action( 'before' );
_e( 'foo', 'textdomain' );
do_action( 'after' );

Add & Remove it:

add_action( 'before', function() {
    // Add filter
    add_filter( 'gettext', 'wpse228163GettextReplacement', 10, 3 );

    // Remove filter when we are done
    add_action( 'after', function() {
        remove_filter( 'gettext', 'wpse228163GettextReplacement' );
    } );
} );
1
  • The good example which I was about to write :D That is not so bad after all many translation plugins and WordPress itself hook their functions on gettext to translate strings.
    – Sumit
    May 29, 2016 at 17:20
-2

After upvoting kaiser's answer I still feel the urge to point out that you are unlikely to write php code without DB access which will impact performance in a measurable way (unless you totally fuck it up).

Theoretically speaking, the filter option should be more performant, especially in memory consumption (this is due to the fact core handles translation in a non optimized way) but there is something to be said for keeping things that do not actually belong to code out of the code.

7
  • 2
    I really do not get that "without DB access" connection in your answer. Can you elaborate?
    – kaiser
    May 29, 2016 at 17:50
  • Sending requests to the DB is the performance bottleneck. Nothing you are likely to write which do not access the DB is likely to be as slow as sending a request. Since wordpress needs to send more then one request to be able to generate a page the impact of bad php code is negligible, especially since the code caching of php 5.6 and JIT compilation of PHP 7 any discussion about the performance of the language itself lacks almost any practical value.. May 29, 2016 at 18:12
  • Now memory is a different issue and the filter method is more likely to have a much better memory impact as the translation strings are saved in the common program cache and are not being reallocated for each process handling a request. May 29, 2016 at 18:16
  • Not sure if I agree on the "DB always slowest" assumption. DB servers can be damn fast when configured properly. Comparing that to large diffs on structures, I would not say that every DB request is slower. To take a different example: Remote requests. Anyway, as this is not the actual topic, I'd suggest to simply remove that part from the answer unless you have data to back those statements. Maybe convert the answer to a performance comparison of a full page request gettext filter vs some DB request? Would appreciate that :)
    – kaiser
    May 29, 2016 at 18:40
  • @kaiser, DB requests are not slow just because DBs are slow, but also because every I/O bound operation is much slower than memory access operation. In case of accessing the DB you need to get to the network layer and send a TCP/IP request to the DB. Even when the DB is on the same computer this invokes thousands lines of OS code and then you need to wait until the OS will decide that it is time to process that message. Same happens for the response. If the DB is on a different server like in many shared hosting then you actually need to get to the physical layer which is even slower. May 29, 2016 at 19:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.