5

tl;dr: My plugin wants to translate strings from core or other plugins that use _n_noop(). How?

This question related to this plugin and is sort of a follow up to this question.

My plugin adds "{status} (n)" (e.g. "Drafts (10)") to the admin menus for any post type. It supports any post status added with register_post_status() because it grabs all statuses with the get_post_stati() function (not the irritatingly similar get_post_statuses()).

When someone registers a post status with register_post_status(), one includes a label_count value in the $args that is perfect for what I need. I'd always like to display the plural label count in the menu and use sprintf() to drop in the count value.

Here's a truncated excerpt of the current plugin code (that first sprintf() is the thing I'm looking to change):

<?php
// an array of all the statuses
$ps_statuses = get_post_stati( array( 'show_in_admin_status_list' => true ), 'objects' );

// a filter for the list of statuses for anything people want to do that's plugin specific
$ps_statuses = apply_filters( 'psmi_statuses', $ps_statuses );

// Get status counts of all post types
$ps_status_counts = wp_count_posts( $ps_type_id );

foreach( $ps_statuses as $status ) {

    $ps_status_id = $status->name;
    $ps_status_count = $ps_status_counts -> $ps_status_id;

    // If a status has any posts, show it
    if( $ps_status_count > 0 ) {
        // Get the plural post status label
        $ps_status_label = $status->label_count['plural'];
        $submenu[$menu][] = array(
            sprintf(
                $ps_status_label,
                $ps_status_count
            ),
            'read',
            sprintf(
                '%1$sedit.php?post_status=%2$s&post_type=%3$s',
                get_admin_url(),
                $ps_status_id,
                $ps_type_id
            )

        );
    }
}

This works fine, but it's untranslatable.

I can see that when WordPress registers the post stati in core (in /wp-includes/post.php), it uses the _n_noop() function to allow for plural translations:

register_post_status( 'draft', array(
    'label'       => _x( 'Draft', 'post' ),
    'protected'   => true,
    '_builtin'    => true, /* internal use only. */
    'label_count' => _n_noop( 'Draft <span class="count">(%s)</span>', 'Drafts <span class="count">(%s)</span>' ),
) );

However, I haven't been able to figure out how to get the translated string working. I think I need to use translate_nooped_plural(), but I haven't been able to get that to work (and really, I just want to use the plural string even if there's only one post in a status). Secondly, I'm really lost what text domain I should use because the statuses could be coming from core, a custom call or register_post_status(), or a plugin like edit flow.

8
  • Aren't you able to do translate_nooped_plural( _n_noop( 'Draft %s', 'Drafts %s' ), $count );? Commented Jan 22, 2013 at 14:39
  • The problem is that the _n_noop( 'Draft %s', 'Drafts %s' ) is already in core (or a plugin). I need to get it out and use it, but that doesn't seem to be working.
    – mrwweb
    Commented Jan 22, 2013 at 14:43
  • And with just some text domain it won't work either? Because that would make things a lot less complicated. Commented Jan 22, 2013 at 14:54
  • I see that translate_nooped_plural() takes a domain, but I don't understand how to use that when the string to be translated is coming from core and has no domain.
    – mrwweb
    Commented Jan 22, 2013 at 16:18
  • The script that uses the translate_nooped_plural() is in a core file? In that case, I doubt if this can be done. If the script that uses the translate_nooped_plural() is in one of your own file, it must be possible to use the text domain you use in that plugin/script, overwriting the the core string. Commented Jan 23, 2013 at 8:21

1 Answer 1

2
+50
// Get the plural post status label
$ps_status_label = $status->label_count;

$submenu[$menu][] = array(

  sprintf(
    translate_nooped_plural(
      $ps_status_label,
      $ps_status_count
    ),
    $ps_status_count
  ),

This should work as expected for the core translations. Now you need the textdomain, so lets search for the string you wish to translate

foreach ( $GLOBALS['l10n'] as $domain => $data ) {
    if ( in_array( $ps_status_label[0], array_keys( $data->entries ) ) )
        break;

    $domain = '';
}

$domain = ( ! empty( $domain ) ) ? $domain : 'default';

And now you can alter the first code snippet to

// Get the plural post status label
$ps_status_label = $status->label_count;

$submenu[$menu][] = array(

  sprintf(
    translate_nooped_plural(
      $ps_status_label,
      $ps_status_count,
      $domain
    ),
    $ps_status_count
  ),

You only need the plural form of the post status, just rise the count value in translate_nooped_plural()

sprintf(
  translate_nooped_plural(
    $ps_status_label,
    10,
    $domain
  ),
  $ps_status_count
),

This will always return the plural form because the count value is greater than 1. Be sure to use a value graeter than 3, because in some languages there are differences between the cases for one, two or more.

Just to clearify:

translate_nooped_plural(
  [array(
    [string for singular]
    [string for plural]
  ),
  [count] (1 = select singular string, greater than 1 select the plural string)
  [domain]
)
4
  • Thanks for the answer. It's a hack, but I like the plural trick. Sadly, it's my understanding that the text domain must be a string passed directly in the function (not as a variable) (see here) because the parsers don't execute PHP. Is that not the case for translate_nooped_plural()?
    – mrwweb
    Commented Jan 24, 2013 at 16:45
  • Eeeeh... no. The strings are already translated. You do not have to translate them again. The strings are translated by the author who register the post status. You can also leave the domain blank, it's optional. If you didnÄ't provide a domain, WP do the same as the foreach-loop will do: WP search in the global array ´l10n´ for the string and a translation. It will be much faster if you provide a domain, because WP can access the l10n array direct by it's key (key=domain)
    – Ralf912
    Commented Jan 24, 2013 at 22:23
  • Thanks for the clarification, @ralf912. Since I can't know the text domain, I guess I just have to go for it and deal with the mild-sounding performance hit.
    – mrwweb
    Commented Jan 24, 2013 at 22:26
  • String or variable is another topic. Marc Jaquith wrote a article about it. But he didn't say when to use a string and when a variable is good enough. If you got more than one textdomain in one file, the parsers will struggle. Because the textdomains are the same for a parser at __('My string', $my_domain) and __('Your string', $your_domain). But meanwhile, there are some parsers out there which can detect a varaibel and can handle this.
    – Ralf912
    Commented Jan 24, 2013 at 22:33

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.