[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Localizing using printf and ternary operator

Posted on 2006-04-03
21
Medium Priority
?
673 Views
Last Modified: 2013-12-12
Hello all,

I'm having trouble to make this work using this example. I'm trying to locale the template I'm working on to support various language.
At 1 point the only way to support Asian language i.e Korean, Japanese is using the format below:

Published %1$s %2$s %3$s.

%1$s : if ($count_users > 1) ('by %s','domain') not ''
%2$s : if function_exists('time_since') ('%s ago','domain) not get_the_time(__('F jS, Y','domain')),
%3$s : ('in %s','domain') if function_exists('the_nice_category') the_nice_category(', ') not get_the_category_list(', ')


This is my current 'not working' codes. I was hoping to follow the format above which I fail to do so.
Is there any way to include string format (%s) in argument?

$count_users = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->usermeta WHERE `meta_key` = '" . $table_prefix . "user_level' AND `meta_value` > 1");

printf( __('Published %1$s %2$s %3$s.','domain'),

($count_users > 1) ? __('by','domain') . ' <a href="' . get_author_link(0, $authordata->ID, $authordata->user_nicename) .'">' . get_the_author() . '</a>' : (''),            

function_exists('time_since') ? time_since(abs(strtotime($post->post_date_gmt . " GMT"))) . __(' ago','domain') : get_the_time(__('F jS, Y','domain')),

function_exists('the_nice_category') ? the_nice_category(', ') : get_the_category_list(', ')

);

Thank you in advance.
0
Comment
Question by:daniaz
  • 12
  • 9
21 Comments
 
LVL 40

Expert Comment

by:Richard Quadling
ID: 16371696
Traditional if/then/else

if ($one == 1)
 {
 echo "$one equals 1";
 }
else
 {
 echo "$one does not equal 1";
 }

if $one is 1 then then output will be

1 equals 1

If $one is 2 then the output will be

2 does not equal 1

This can also be expressed as ...

echo ($one == 1) ? "$one equals 1" : "$one does not equal 1";

The output is the same.

Something to watch out for.

Personally, I always put () around ternary code. Just to make it clear.

echo (($one == 1) ? "$one equals 1" : "$one does not equal 1");



So how does this help you. I'm not too sure what your code is trying to do.


printf("Published %1\$s %2\$s %3\$s.", ...);

I think you need to put a \ in to use argument swapping in the printf functions.
0
 

Author Comment

by:daniaz
ID: 16377686
Hi,

There's no need for \

My above code actually already working (but not what I'm hoping for) and the real output is:
Published by Authorname April 5th, 2006 in Categoryname.
from
printf( __('Published %1$s %2$s %3$s.','domain'),

I've already done the traditional ifelse but it is possible to support various language when it comes to localize that sentence.

before:
if (function_exists('time_since')) {
printf(__('%s ago.','domain'), time_since(abs(strtotime($post->post_date_gmt . " GMT")), time()));
} else {
the_time(__('F jS, Y.','k2_domain'));
}
 
after:
function_exists('the_nice_category') ? the_nice_category(', ') : get_the_category_list(', ')

My intention was to use string(%s) inside argument (refer to my first post):
function_exists('the_nice_category') ? ('%s ago','domain'), the_nice_category(', ') : get_the_category_list(', ')

I think this is hard to understand, before this I have no problem using the traditional way of ifelse but someone using Asian language bumps in and told me it's possible to locale that sentence and gave me that format example (refer to my first post).

Thanks
0
 

Author Comment

by:daniaz
ID: 16378599
Just notice wrong example above cannot edit :(

before:
if (function_exists('time_since')) {
printf(__('%s ago.','domain'), time_since(abs(strtotime($post->post_date_gmt . " GMT")), time()));
} else {
the_time(__('F jS, Y.','k2_domain'));
}
 
after:

function_exists('time_since') ? time_since(abs(strtotime($post->post_date_gmt . " GMT"))) . __(' ago','domain') : get_the_time(__('F jS, Y','domain')),
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 40

Expert Comment

by:Richard Quadling
ID: 16379002
I think I'm missing something. I don't understand the issue.

Can you supply a complete script?

The __ is confusing me. I'm not sure what they are doing? I've not seen this before except as the leading characters on __construct, __destruct, __call, __set, __get, etc.

Is the format string constant? Is it ALWAYS 'Published %1$s %2$s %3$s.' ?

If so, why do you need argument swapping? (I think the format is NOT static, but just confirming).





BTW. The \$s bit. The example is using in the manual (http://www.php.net/manual/en/function.sprintf.php) uses "" so $s needs to become \$s. Sorry about that! Doh!

I'll raise a doc bug on this.
0
 

Author Comment

by:daniaz
ID: 16379507
Yeah it's a bit confusing to write this in words, my apology. This a WordPress theme I'm currently working on. The new code was suppose to support localization.

"The __ is confusing me."
That's a keyword (function name) use for translation. If u use poEdit you'll know. It can be _e or anything depends on how it is set.

This is the original code without locale:

<span class="chronodata">Published <?php /* If there is more than one author, show author's name */ $count_users = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->usermeta WHERE `meta_key` = '" . $table_prefix . "user_level' AND `meta_value` > 1"); if ($count_users > 1) { ?> by <?php the_author_posts_link(); } ?>
<?php /* If 'Dunstan's Time Since' plugin is installed use it; else use default. */ if (function_exists('time_since')) { echo time_since(abs(strtotime($post->post_date_gmt . " GMT")), time()); gt; ?> ago<?php } else { the_time('F jS, Y') ?><?php } ?>
in <?php /* If 'Nice Categories' plugin is installed, use it; if not, use default */ if (function_exists('the_nice_category')) { the_nice_category(', '); } else { the_category(', '); }?></span>

So basically the standard output would be (depends on activated plugin):
Published by Authorname April 5th, 2006 in Categoryname.

Previously I use printf with elseif combination, it support most of the translation language out there but then come this Korean guy about the problem if I break it into phrases. He suggest the printf( __('Published %1$s %2$s %3$s.','domain'), .

An example how I use this in the template (working code):
<p><?php printf(__('You are currently browsing the %1$s weblog archives for the year %2$s.','k2_domain'), '<a href="'.get_settings('siteurl').'">'.get_bloginfo('name').'</a>', get_the_time('Y')) ?></p>
                  
This is the code when I use the traditional ifelse.

<span class="chronodata">
<?php /* If there is more than one author, show author's name */ $count_users = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->usermeta WHERE `meta_key` = '" . $table_prefix . "user_level' AND `meta_value` > 1"); if ($count_users > 1) {

      printf(__('Published by %s','domain'), '<a href="' . get_author_link(0, $authordata->ID, $authordata->user_nicename) .'">' . get_the_author() . '</a>');
      } else {
      echo __('Published ','domain');
      }
?>

<?php /* If 'Dunstan's Time Since' plugin is installed use it; else use default. */
if (function_exists('time_since')) {
      printf(__('%s ago','domain'), time_since(abs(strtotime($post->post_date_gmt . " GMT")), time()));
      } else {
      the_time(__('F jS, Y','domain'));
      }
?>
                   
<?php /* If 'Nice Categories' plugin is installed, use it; if not, use default */
if (function_exists('the_nice_category')) {

      $category = the_nice_category(', ');
      } else {
      $category = get_the_category_list(', '); }

      printf(__('in %s.','domain'), $category );

?>

</span>


Take note that I'm a PHP newbie. I hope that I learn from this experience :)

Thanks.
0
 
LVL 40

Expert Comment

by:Richard Quadling
ID: 16379784
The __ function name is NOT a PHP function. So it must be a user defined function. Having said that the code looks like it should work.

The __ function is the issue. I am not sure how this works.

That happens if you ...

echo __('You are currently browsing the %1$s weblog archives for the year %2$s.','k2_domain');

This SHOULD output a printf format string. You will need to make sure that whatever includes you have are working as __ is not a PHP function.

If you can, I would STRONGLY recommend using a proper name for the function simply to remove the ambiguity.

Another issue is that you are swapping in and out of PHP. You are sometimes doing this inside an if statement. Makes if VERY difficult to read.

A much better way is to build the string to send to the browser bit at a time and then output the whole lot in 1 go.

e.g.
<?php
// Your includes...

$s_output = ''; // Empty output.

...

$s_output .= "Some output\n";
...
$s_output .= "Some more output\n";
...

echo $s_output; // Send the output to the client.
?>

You can then add debug echo statements and these will occur BEFORE the actual output.
0
 

Author Comment

by:daniaz
ID: 16380262
Well the __ is definately user defined and also if i'm not mistaken global WordPress define (for localization)

This the project that I'm working on with 2 other.

The entire file is at getk2.com/svn/theloop.php

thanks :)
0
 
LVL 40

Expert Comment

by:Richard Quadling
ID: 16380689
The code looks fine. I cannot see where you are using ...

test ? True : False;

anywhere in this code. This is what the PHP Manual says on the Ternary Operator ...

----------------------------------------------------------
Ternary Operator
Another conditional operator is the "?:" (or ternary) operator.

Example 6.3. Assigning a default value
copy to clipboard
<?php
// Example usage for: Ternary Operator
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];

// The above is identical to this if/else statement
if (empty($_POST['action'])) {
    $action = 'default';
} else {
    $action = $_POST['action'];
}

?>
The expression (expr1) ? (expr2) : (expr3) evaluates to expr2 if expr1 evaluates to TRUE, and expr3 if expr1 evaluates to FALSE.

Note:
Please note that the ternary operator is a statement, and that it doesn't evaluate to a variable, but to the result of a statement. This is important to know if you want to return a variable by reference. The statement return $var == 42 ? $a : $b; in a return-by-reference function will therefore not work and a warning is issued in later PHP versions.
----------------------------------------------------------

Can you ...


// Prepare Loop
echo __('Archive for %s','k2_domain');


What is the output?

What is the output of the whole page anyway?

Can you then create the output you REALLY are exepecting and place this on the site also.

I suspect that the __ function is not working as expected.
0
 
LVL 40

Expert Comment

by:Richard Quadling
ID: 16380784
Right. The function __ is defined in wp-l10n.php. And it returns a string.

So this string needs to look like a printf format. That is what I need to know.

This will identify if the error is in the wp-l10n.php code, your code, or the translated string.
0
 
LVL 40

Expert Comment

by:Richard Quadling
ID: 16380838
By "translated string" I mean the "translated printf format".

0
 

Author Comment

by:daniaz
ID: 16380882
I've revert the code few days ago since it's bringing me lot's of problem.
I've already posted the use of ternary code in my FIRST post here before I revert the code to original code.

The code:
$count_users = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->usermeta WHERE `meta_key` = '" . $table_prefix . "user_level' AND `meta_value` > 1");

printf( __('Published %1$s %2$s %3$s.','domain'),

($count_users > 1) ? __('by','domain') . ' <a href="' . get_author_link(0, $authordata->ID, $authordata->user_nicename) .'">' . get_the_author() . '</a>' : (''),            

function_exists('time_since') ? time_since(abs(strtotime($post->post_date_gmt . " GMT"))) . __(' ago','domain') : get_the_time(__('F jS, Y','domain')),

function_exists('the_nice_category') ? the_nice_category(', ') : get_the_category_list(', ')

);

The output is still the same from the previous examples.

There's nothing wrong with the current code and the previous code I've submitted here. The whole theloop.php is fine. You can view the overall working code in the root of the domain - getk2.com.

What's inside the <span class="chronodata">...</span> is what i want to change.
From the ternary code above is it possible to do something like this inside the code above:

('by %s','domain'), ' <a href="' . get_author_link(0, $authordata->ID, $authordata->user_nicename) .'">' . get_the_author() . '</a>'

You can test it yourself, grab a copy of WordPress and a copy of the entire template code in getk2.com/svn/ using any subversion client.

Oh and just imagine that __ is echo. There's nothing wrong with that fyi. It's a gettext stuff use for internalization and localization.
0
 

Author Comment

by:daniaz
ID: 16380921
"echo __('Archive for %s','k2_domain');"

the output (depends on which statement it's in). It can be:
<?php printf( __('Archive for %s','k2_domain'), get_the_time( __('Y','k2_domain'))) ?>
Archive for 2006

Here's a bug ticket for that.
url: getk2.com/bugs/view.php?id=235



0
 
LVL 40

Expert Comment

by:Richard Quadling
ID: 16380993
No. I was expecting the output of

echo __('Archive for %s', 'k2_domain');

to be something like ...

Archive for %s

or whatever the translation should be.




0
 

Author Comment

by:daniaz
ID: 16381097
Exactly,

if you only do something like:
echo __('Archive for %s', 'k2_domain');

it will return a plain "Archive for %s" (without " ") since there's not argument for the string(%s).
0
 
LVL 40

Expert Comment

by:Richard Quadling
ID: 16381140
Can you somehow incorporate this code and supply the output please.

What I am trying to determine is where does the problem lie. The code LOOKS valid. I can see no reason why ternary operators are not working. I suspect that there is another issue which is being missed.

Hopefully the following code will report all the values being worked upon. Each of the tests in the ternaries will be evaluated and reported as true/false. If the functions does exist, then the lines where they are called will fail (only my debug calls these functions unchecked).



error_reporting(E_ALL);
echo "Start of debug<br />\n";

// Build the database request.
$s_count_users_SQL = <<< END_SQL
SELECT
      COUNT(*) AS usercount
FROM
      {$wpdb->usermeta}
WHERE
      `meta_key` = '{$table_prefix}user_level' AND
      `meta_value` > 1
END_SQL;

// What is the request.
echo "$s_count_users_SQL<br />\n";

// Get the number of users.
$i_count_users = $wpdb->get_var($s_count_users_SQL);

// What is the db results
echo "Number of users is $i_count_users<br />\n";


// Output the various parts indivually.
echo '($i_count_users > 1) returns ' . (($i_count_users > 1) ? 'True' : 'False') . "<br />\n";
echo "If True then __('by','domain') . ' <a href=\"' . get_author_link(0, \$authordata->ID, \$authordata->user_nicename) .'\">' . get_the_author() . '</a>' returns " . __('by','domain') . ' <a href="' . get_author_link(0, $authordata->ID, $authordata->user_nicename) .'">' . get_the_author() . '</a>' . "<br />\n";

echo "function_exists('time_since') returns " . (function_exists('time_since') ? 'True' : 'False') . "<br />\n";
echo "If True then time_since(abs(strtotime(\$post->post_date_gmt . ' GMT'))) . __(' ago','domain') returns " . time_since(abs(strtotime($post->post_date_gmt . " GMT"))) . __(' ago','domain') . "<br />\n";
echo "If False then get_the_time(__('F jS, Y','domain')) returns " . get_the_time(__('F jS, Y','domain')) . "<br />\n";


echo "function_exists('the_nice_category') returns " . (function_exists('the_nice_category') ? 'True' : 'False') . "<br />\n";
echo "If True then the_nice_category(', ') returns " . the_nice_category(', ') . "<br />\n";
echo "If False then get_the_category_list(', ') returns " . get_the_category_list(', ') . "<br />\n";

// Output the combined results.
printf(
      __('Published %1$s %2$s %3$s.','domain'),
      (($i_count_users > 1)
            ?
            __('by','domain') . ' <a href="' . get_author_link(0, $authordata->ID, $authordata->user_nicename) .'">' . get_the_author() . '</a>'
            :
            ''),
      (function_exists('time_since')
            ?
            time_since(abs(strtotime($post->post_date_gmt . ' GMT'))) . __(' ago','domain')
            :
            get_the_time(__('F jS, Y','domain'))),
      (function_exists('the_nice_category')
            ?
            the_nice_category(', ')
            :
            get_the_category_list(', '))
      );
echo "End of debug<br />\n";
0
 
LVL 40

Expert Comment

by:Richard Quadling
ID: 16381232
>Comment from daniaz
>Date: 04/05/2006 01:16PM GMT
>
>Exactly,
>
>if you only do something like:
>echo __('Archive for %s', 'k2_domain');
>
>it will return a plain "Archive for %s" (without " ") since there's not argument for the string(%s).

Surely the k2_domain is acting as a translator? Making the text different in some way?

0
 

Author Comment

by:daniaz
ID: 16388844
RQuadling, I think you misunderstood this whole situation. As I said before the code is working fine (every piece of code that I posted here). But it is not what I want (actually that korean guy want).

In order to please that korean guy, the formatted string should be:
Published %1$s %2$s %3$s.
where:
%1$s : if ($count_users > 1) ('by %s','domain') not ''
%2$s : if function_exists('time_since') ('%s ago','domain) not get_the_time(__('F jS, Y','domain')),
%3$s : ('in %s','domain') if function_exists('the_nice_category') the_nice_category(', ') not get_the_category_list(', ')

The real problem lies here:
by %s, %s ago, in %s

is there any way to use argument data inside argument data. Refer to my comment -> Date: 04/05/2006 05:54AM PDT

I'm thinking something like this (not working code):

$count_users = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->usermeta WHERE `meta_key` = '" . $table_prefix . "user_level' AND `meta_value` > 1");

printf( __('Published %1$s %2$s %3$s.','domain'),

($count_users > 1) ? __('by %s','domain'), ' <a href="' . get_author_link(0, $authordata->ID, $authordata->user_nicename) .'">' . get_the_author() . '</a>' : (''),            

function_exists('time_since') ? __('%s ago','domain'), time_since(abs(strtotime($post->post_date_gmt . " GMT"))) .  : get_the_time(__('F jS, Y','domain')),

__('in %s','domain'), function_exists('the_nice_category') ? the_nice_category(', ') : get_the_category_list(', ')

);

The problem is, u can't use something like this in there:
__('in %s','domain'), function_exists('the_nice_category') ?

If there's any way beside ternary operator or using ifelse.

Thanks for helping me on this mate :)

0
 
LVL 40

Expert Comment

by:Richard Quadling
ID: 16389553
The code is causing too much noise.

I can't work out what you are trying to get to.

Are you trying to build a sub-printf statement to supply as a parameter to the main printf?

Something like ...

<?php
$count_users = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->usermeta WHERE `meta_key` = '" . $table_prefix . "user_level' AND `meta_value` > 1");

printf
      (
      __('Published %1$s %2$s %3$s.','domain'), // Initial format for Published

      // This is to generate the first parameter.
      (
            ($count_users > 1)
                  ?
                        printf
                              (
                              __('by %s','domain'),
                              ' <a href="' . get_author_link(0, $authordata->ID, $authordata->user_nicename) .'">' . get_the_author() . '</a>'
                              )
                  :
                        ('')
      ),
      
      // This is for the second parameter
      (
            function_exists('time_since')
                  ?
                        printf
                              (
                              __('%s ago','domain'),
                              time_since(abs(strtotime($post->post_date_gmt . " GMT")))
                              )
                  :
                        get_the_time(__('F jS, Y','domain'))
      ),
      
      // This is for the third parameter
      printf
            (
            __('in %s','domain'),
            function_exists('the_nice_category') ? the_nice_category(', ') : get_the_category_list(', ')
            )
      );
?>

Hopefully the indenting will add to the code and explain the dependence between each line of code.
0
 
LVL 40

Accepted Solution

by:
Richard Quadling earned 2000 total points
ID: 16389561
<?php
$count_users = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->usermeta WHERE `meta_key` = '" . $table_prefix . "user_level' AND `meta_value` > 1");

printf
      (
      __('Published %1$s %2$s %3$s.','domain'), // Initial format for Published

      // This is to generate the first parameter.
      (
            ($count_users > 1)
                  ?
                        printf
                              (
                              __('by %s','domain'),
                              ' <a href="' . get_author_link(0, $authordata->ID, $authordata->user_nicename) .'">' . get_the_author() . '</a>'
                              )
                  :
                        ('')
      ),
      
      // This is for the second parameter
      (
            function_exists('time_since')
                  ?
                        printf
                              (
                              __('%s ago','domain'),
                              time_since(abs(strtotime($post->post_date_gmt . " GMT")))
                              )
                  :
                        get_the_time(__('F jS, Y','domain'))
      ),
      
      // This is for the third parameter
      (
      printf
            (
            __('in %s','domain'),
            function_exists('the_nice_category') ? the_nice_category(', ') : get_the_category_list(', ')
            )
      )
      
      // End of main printf statement
      );
?>
0
 

Author Comment

by:daniaz
ID: 16390093
Thanks man. That would do the trick. *bow*

Sorry about the 'noise'. The original code was indent (like u did), in order to get the example I have to copy paste from SVN diff (which is compress).

This is an updated code from the above. Instead of using printf(), it should be using sprintf() to return the formatted string.

<?php
$count_users = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->usermeta WHERE `meta_key` = '" . $table_prefix . "user_level' AND `meta_value` > 1");

printf
     (
    __('Published %1$s %2$s %3$s.','domain'), // Initial format for Published

     // This is to generate the first parameter.
     (
          ($count_users > 1)
               ?
                    sprintf
                         (
                         __('by %s','domain'),
                         ' <a href="' . get_author_link(0, $authordata->ID, $authordata->user_nicename) .'">' . get_the_author() . '</a>'
                         )
               :
                    ('')
     ),
     
     // This is for the second parameter
     (
          function_exists('time_since')
               ?
                    sprintf
                         (
                         __('%s ago','domain'),
                         time_since(abs(strtotime($post->post_date_gmt . " GMT")))
                         )
               :
                    get_the_time(__('F jS, Y','domain'))
     ),
     
     // This is for the third parameter
     (
     sprintf
          (
          __('in %s','domain'),
          function_exists('the_nice_category') ? the_nice_category(', ') : get_the_category_list(', ')
          )
     )
     
     // End of main printf statement
     );
?>

Thanks a lot :)
0
 
LVL 40

Expert Comment

by:Richard Quadling
ID: 16390112
Yes. I forgot about sprintf.

Good luck with the project and thanks for the points.
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is intended for those who are new to PHP error handling (https://www.experts-exchange.com/articles/11769/And-by-the-way-I-am-New-to-PHP.html).  It addresses one of the most common problems that plague beginning PHP develop…
Many old projects have bad code, but the budget doesn't exist to rewrite the codebase. You can update this code to be safer by introducing contemporary input validation, sanitation, and safer database queries.
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.
Suggested Courses
Course of the Month20 days, 1 hour left to enroll

873 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question