Translating WP with __() and sprintf()
Asked Answered
P

5

5

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.

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.

Palpitant answered 30/4, 2016 at 15:11 Comment(3)
Did you find the cause?Brewis
If you ask me, just ignore the theme check plugin in this case and be happy with the working and good solution.Unpen
@D.A. is Lille's answer correct? Might you accept it?Yasmin
D
13
echo sprintf(__("text %s", 'your__text_domain'), $data);
Darlleen answered 10/2, 2018 at 11:18 Comment(4)
sprintf() is a PHP function: php.net/manual/en/function.sprintf.phpSignification
This is already stated in the OP's question. Why do you think you have answered the question ?!Brewis
echo sprintf makes no sense ;) use printfObie
I agree. echo sprintf() is an "antipattern". There is absolutely no reason that anyone should ever write echo sprintf() -- it should be printf() without echo every time.Yasmin
D
10

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

Dolliedolloff answered 31/3, 2020 at 19:10 Comment(0)
L
3

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.

Lymn answered 30/4, 2016 at 18:50 Comment(0)
W
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.

Waylon answered 22/12, 2017 at 10:21 Comment(0)
B
3

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.

Blintz answered 14/6, 2022 at 4:43 Comment(1)
This is the best answer here, thanks! The only improvement would be to add to escape the value tooConnotative

© 2022 - 2024 — McMap. All rights reserved.