Mangling strings for fun and profit

As a WordPress lead developer, every time I see someone recommending editing a core WordPress file, a little bit of me dies.

You should always avoid editing the core files and put your modifications into a plugin so as to ensure you have a smooth upgrade experience to a future WordPress version.

Therefore inspired by the following forum post here is how to change one of the translatable strings in WordPress without hacking a core file using the filters available in the translation functions:

<?php
/*
 Plugin Name: PJW Translation Mangler
 Plugin URI: http://blog.ftwr.co.uk/#
 Description: Example of how to mangle translated strings.
 Author: Peter Westwood
 Version: 0.01
 Author URI: http://blog.ftwr.co.uk/
 */

class PJW_Translation_Mangler {
 /**
 * Filter the translation string before it is displayed.
 *
 * @param $translation The current translation
 * @param $text The text being translated
 * @param $context The context for the translation
 * @param $domain The domain for the translation
 * @return string The translated / filtered text.
 */
 function filter_gettext($translation, $text, $domain) {
  $translations = &get_translations_for_domain( $domain );
  if ( $text == 'View all posts filed under %s' ) {
   return $translations->translate( 'See all articles filed under %s' );
  }
  return $translation;
 }
}
add_filter('gettext', array('PJW_Translation_Mangler', 'filter_gettext'), 10, 4);
?>

The filter used in this example gettext is one of a set of filters in the translation functions in wp-includes/l10n.php which also include gettext_with_context, ngettext, and ngettext_with_context.

15 Responses to “Mangling strings for fun and profit”

  1. scribu says:

    Pretty cool. Is there a reason why you put that single function in a class?

    • westi says:

      Force of habit, more than anything.

      I like to do it that way so as to keep everything namespaced and not take top level function names.

      I only use top level function names, in plugins, as wrappers when providing template tags.

  2. Donncha says:

    Hadn’t thought of using that gettext filter. There’s a filter in wp-super-cache that allows you to filter the contents of the page that is about to be cached. I wrote a small function that deletes the moderation message for comments as a small exercise because the string isn’t filterable, or so I thought!

    This way is much neater. Thanks!

  3. mkjones says:

    Really great tip :)

    Is it possible to use this function to re-name admin menu items when activating a theme?

    For example, if I wanted to change “Posts” to “News”?

    Or the “Appearance” tab back to “Themes” maybe?

    I’d love to be able to do total admin menu overhauls using theme functions rather than plugins.

    • westi says:

      Yes you should be able to do that too very easily with multiple replacements in the one function.

      • mkjones says:

        Currently I do something like:


        global $menu, $submenu, $wp_taxonomies;

        // Unset Post & Page menus so we can change them
        unset($menu[5]);
        unset($menu[10]);
        unset($menu[20]);

        // Change menu order to reflect new positions
        //New Pages
        $menu[5] = array(__('Pages'), 'edit_pages', 'edit-pages.php', '', 'wp-menu-open menu-top', 'menu-pages', 'div');
        $submenu['edit-pages.php'][5] = array(__('Edit'), 'edit_pages', 'edit-pages.php');
        $submenu['edit-pages.php'][10] = array(_c('Add New|page'), 'edit_pages', 'page-new.php');

        //New Posts (News)
        $menu[10] = array(__('News'), 'edit_posts', 'edit.php', '', 'menu-top', 'menu-posts', 'div');
        $submenu['edit.php'][5] = array(__('Edit'), 'edit_posts', 'edit.php');
        .... etc

        Which allows me to move menu items (Media between Pages and Posts always annoys me) and rename them, in this case Posts to News.

        Is this possible using the translation function?

  4. […] Translation Strings: Mangling strings for fun and profit: Peter Westwood gives simple tips for improving the quality of translation strings in WordPress Themes. […]

  5. mercime says:

    Thank you very much Westi. I was referred to this solution by DJPaul at BuddyPress Forums when I wanted to find a simpler and easier to override text output from BP parent theme’s template function. From 45 lines of code to replace a single sentence in child theme’s functions.php to 10 lines of code in same functions.php – Awesome!

  6. Ryan McCue says:

    Your code is somewhat inefficient. The get_translations_for_domain() call should be inside the if block :P

    Also, I love the fact that you have more comments than code. :)

  7. Devin says:

    Is there any way to do this one a per post type basis? For instance, I’d like to filter ‘Scheduled for: %1$s‘ to ‘Event Date: %1$s‘ only on my events custom post type.

    • westi says:

      This should be possible. Hopefully at the time the string is output there is enough context in global variables for you to determine which page you are on and therefore mangle the string in the correct way.
      From what I recall there is a global which tells you which admin page you are currently on so that may be of use to you.

  8. Peter,

    You pointing me to this as a solution for changing the name of admin menu items. One big of the problems I see with using the gettext hook in almost all cases is that it is called hundreds of times per page load and if anything significant is done in it using it could slow down page load by a noticeable amount. For example, I just ran a test and it runs 577 times on the Dashboard page of the admin.

    The fact it’s run over 500 times is why I’d rather not use it for something so simple as changing the name of a menu option; it’s an expensive and blunt instrument for something that could easily use an inexpensive scalpel, assuming one were easily made available and didn’t require intricate knowledge of the admin menu array structures.

    In general, I’d rather look for a hook that is called only once or just a few executions.

    -Mike

    • westi says:

      If you find the overhead is to high for this the easiest thing to do is to switch to doing it with a translation file instead. i.e. Create a special translation of WordPress for this particular use case.

  9. […] implementation was based on a similar, but different, approach by WordPress core developer Peter Westwood on his blog. * Replaces a string in the internationalisation table with a custom value. * * @global object […]



d
go to dashboard
l
go to login
h
show/hide help
e
edit post/page
r
comment on post/page
m
go to moderate comments
esc
cancel
%d bloggers like this: