Translating WP with __() and sprintf()

I’m trying to translate WP theme. I have this code:

$translation = __( get_color(), 'textdomain' );

It works, I get color dynamically from get_color() function, and it translates well. But when I use “Theme Check” plugin I get error for this code.

Read More

I need to use this instead:

$translation = sprintf( __( '%s', 'textdomain' ), get_color() );

But in that case my placeholder %s doesn’t translates, and I get original color name (not translated).

What I’m doing wrong? Thank you.

Related posts

5 comments

  1. I’m surprised no one mentioned the “translators” comment, that tells the translator what each variable in the sprintf is. Examples:

    sprintf(
        /* translators: %s: Name of a city */
        esc_html__( 'Your city is %s.', 'my-plugin' ),
        esc_html( $city )
    );
    
    sprintf(
         /* translators: 1: Name of a city 2: ZIP code */
        esc_html__( 'Your city is %1$s, and your zip code is %2$s.', 'my-plugin' ),
        esc_html( $city ),
        esc_html( $zipcode )
    );
    

    We escape the translation with esc_html__ to protect from XSS coming from community translated strings, and we escape the dynamic output with esc_html protect from XSS in the variable $city.

    See: https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#variables

  2. A.,

    In your code:

    $translation = sprintf( __( '%s', 'textdomain' ), get_color() );
    

    the __() functions checks for a translation of the string ‘%s’ – of which you probably have no translation – and then replaces ‘%s’ with the result of get_color(). So the value for get_color() never passes the translation function.

    I am not sure what the right solution is here, maybe just forget about Theme Check in this case.

  3. Many translation tools that extract translatable strings will look for string literals, like this:

    $translation = __( 'red', 'textdomain' );
    

    It’s a safe bet* that the Theme Check plugin is alerting you to the fact that your dynamic string will not be extracted by such tools. This is because the code won’t be executed during extraction, hence the expression get_color() will not be evaluated into a translatable string.

    If you don’t care about compatibility with string extraction tools, then just leave your code as per your first example (The second example is wrong as already pointed out).

    If you do want your code to work with translation tools, then I suggest you create a dummy PHP file containing all possible colour values. (assuming that list is finite). Your file would look something like this:

    <?php
    __('red', 'textdomain' );
    __('blue', 'textdomain' );
    // and so on..
    

    Then, if you want to stop the actual translation call producing “Theme Check” errors you’ll have to refactor it into something that won’t get picked up. Something like this would get missed by most extractors:

    $translation = call_user_func( '__', get_color(), 'textdomain' );
    

    * Worth noting that the author of Theme Check is a core WordPress contributor and quite vocal about doing WordPress i18n correctly.

  4. The answer is already given at the first 2 replies. Follow that but don’t forget to add an escaping function there as well.

    this is how you translate texts with one value or function:

    sprintf(
        esc_html__( 'Your translatable text goes here and value is %s.', 'textdomain' ),
        $value_or_function
    );
    

    And in the following way, you can add multiple values/ functions to yout translatable texts.

    sprintf(
        esc_html__( 'this is how you can add multiple values. value1: %1$s, and value2: %2$s.', 'textdomain' ),
        $value_or_function1,
        $value_or_function2
    );
    

    Here is a brief about this sprintf function:

    The arg1, arg2, ++ parameters will be inserted at percent (%) signs in the main string. This function works “step-by-step”. At the first % sign, arg1 is inserted, at the second % sign, arg2 is inserted, etc.

    Syntax: sprintf(format,arg1,arg2,arg++)

    Possible format values:

    %% - Returns a percent sign
    %b - Binary number
    %c - The character according to the ASCII value
    %d - Signed decimal number (negative, zero or positive)
    %e - Scientific notation using a lowercase (e.g. 1.2e+2)
    %E - Scientific notation using a uppercase (e.g. 1.2E+2)
    %u - Unsigned decimal number (equal to or greater than zero)
    %f - Floating-point number (local settings aware)
    %F - Floating-point number (not local settings aware)
    %g - shorter of %e and %f
    %G - shorter of %E and %f
    %o - Octal number
    %s - String
    %x - Hexadecimal number (lowercase letters)
    %X - Hexadecimal number (uppercase letters)
    

    But generally we use %s and assume that the argument value will be a string.

Comments are closed.