php-i18n Digest 30 Jul 2002 07:52:05 -0000 Issue 116

Topics (messages 296 through 306):

Re: htmlentities() and charset
        296 by: Yasuo Ohgaki

php + gettext tutorial
        297 by: Jonas Mariλn
        298 by: Hans Lellelid

Re: How to structure a multilingual app
        299 by: Anatole Varin
        300 by: Hans Lellelid
        301 by: Hans Lellelid
        302 by: Anatole Varin
        303 by: Hans Lellelid
        304 by: a.h.s. boy
        305 by: Hans Lellelid

PHP, MySQL & Chinese (Big5)
        306 by: William

Administrivia:

To subscribe to the digest, e-mail:
        [EMAIL PROTECTED]

To unsubscribe from the digest, e-mail:
        [EMAIL PROTECTED]

To post to the list, e-mail:
        [EMAIL PROTECTED]


----------------------------------------------------------------------
--- Begin Message ---
A . H . S . Boy wrote:
> If I submit the Greek text, it goes into my MySQL database just fine. To 
> display it, I'm calling
> 
>    nl2br(htmlentities($body,ENT_COMPAT,'ISO-8859-7'));
> 
> and the result in my browser is
> 
> Υπάρχουν ιστορικά...
> 
> (Random Latin 1 accented characters, not Greek).
> 
> If, however, I change the htmlentities() call to htmlspecialchars(), 
> still with the character set specified, it renders properly in my 
> browser, in Greek.
> 
> Is this a bug in htmlentities? I'm using PHP 4.2.2, just released, so if 
> it's a bug, it hasn't been fixed yet.

Pointer must be pointing somewhere eles or like...

Search Bug DB and if it's not fixed, submit bug with
short & complete script.

--
Yasuo Ohgaki

--- End Message ---
--- Begin Message ---
Does anybody have a good entry level text, tutorial, howto, whatever on how to 
setup an internationalised php application with gettext?

A tutorial on how to compile php with gettext support etc would not be 
necessary. What I really need is a step-by-step description on how to use 
gettext in a large php script to provide for multilanguage strings...

thank you -- jonas




--- End Message ---
--- Begin Message ---
There's a great tutorial on O'reilly network site:

http://www.onlamp.com/pub/a/php/2002/06/13/php.html

I've just recently done some work on a bi-lingual site.  And another
gotcha I discovered a little too late is that you should use functions
like strftime() instead of date() to format dates in a locale-sensitive
way. 

HTH

Cheers,
Hans

On Wed, 2002-07-24 at 04:19, Jonas Mariλn wrote:
> Does anybody have a good entry level text, tutorial, howto, whatever on how to 
> setup an internationalised php application with gettext?
> 
> A tutorial on how to compile php with gettext support etc would not be 
> necessary. What I really need is a step-by-step description on how to use 
> gettext in a large php script to provide for multilanguage strings...
> 
> thank you -- jonas
> 
> 
> 
> 
> 
> -- 
> PHP Internationalization Mailing List (http://www.php.net/)
> To unsubscribe, visit: http://www.php.net/unsub.php
> 
> 



--- End Message ---
--- Begin Message ---
Good question. I'll tell you my hack, however I'd be really curious to hear
other people's opinions as well.

For text without links I do something similar to the phpMyAdmin way, however
I put my language into an array, just so that if I use language inside of
functions I don't have to declare each variable as a global, just the one
array. For example (using romanji for the Japanese for non-Japanese enabled
mail clients on this list):

$lang = array(
    "verify" => "kakunin",
    "name" => "namae",
    "no" => iie",
    "delete" => "sakujo,
    "close_window" => "tojiru"
);

Then, when I want to use it in a function I just use "global $lang" and I
can use the bits that I want (i.e. <?php print($lang[name]); ?>

For pieces that are a bit more complex, such as phrases that contain links
or bolding or other attributes that might not line up because of the
differences in expressing English and Japanese, I use functions:

function lang_show_result($start,$finish) {
 $txt = "Showing results $start-$finish.";
 return($txt);
}


> It's very nice to see some activity on here from this end of the mailing
> list as well.  I am on the verge of putting together a php/mysql
> multilingual website from scratch and it's good to know that some people
> are reading up on the list.  I was wondering what people's opinion on
> the overall structure of a multi language php application is.  There are
> a number of ways to implement the frontend.
> 
> 1.  Do something similar to the way phpMyAdmin works and have different
> files layed out with the different encoding types and variables listed
> for each message displayed to the users.
> 
> 2.  Use gettext or some other widely used standard.
> 
> ..... Etc..
> 
> Of course even these 2 solutions have their good and bad points.  The
> first is quick but harder to maintain.  The second of course is easier
> to maintain but more difficult to setup from the beginning.  What do
> others think or what are they using at this time?
> 
> Thanks,
> -jeff

- AV

--- End Message ---
--- Begin Message ---
For translating text that might have dynamic values, I build a wrapper
function for gettext() -- note that if you do this you'll probably need
to use a shell/perl script to replace the wrapper function name with
gettext() or _() before feeding it into thee xgettext tool.

So my wrapper function is invoked like this:

xlate("Search found {count} pages for {keywords}", $count, $query$);

It doesn't matter how you label your {tags}, but make sure you use
the same label in all translations.  

** This way you can re-order the tags in the translated text & PHP will
still insert the correct values.**

In the [bad French] POT file:

msgid "Search found {count} pages for {keywords}"
msgstr "En cherchant le database pour {keywords}, on a trouve {count}
results."

Notice that the the order changes for dynamic elements.


Here's the actual wrapper function I use:

function xlate($text) 
{   

  // 1) get array of {tags} in text
  // these will be replaced with passed params

     preg_match_all("/{([^}]+)}/", $text, $var_matches);

     $replace_tags = $var_matches[1];

  // $replace_tags is an array of all tags we need to replace
  // in original order.

   $num_args = func_num_args();
   $num_replace_tags = sizeof($replace_tags);

   if( ($num_args - 1) < $num_replace_tags) {
      trigger_error("More replace tags than arguments", E_USER_WARNING);
   }

    $replace_map = array();

    // build a hash of tags & values to replace them with.

    for($c = 0; $c < $num_replace_tags; $c++) {
      $replace_map[ $replace_tags[$c] ] = func_get_arg($c+1);
    }


   // 2) translate the text
                        
      $xlated = gettext($text);

   // 3) re-insert the values from the hash
        
      $xlated = preg_replace("/{([^\}]+)}/e", "\$replace_map[$1]" ,
$text);]
                                                                
                        
    return $xlated;

}


Cheers,
Hans

On Wed, 2002-07-24 at 10:11, Anatole Varin wrote:
> Good question. I'll tell you my hack, however I'd be really curious to hear
> other people's opinions as well.
> 
> For text without links I do something similar to the phpMyAdmin way, however
> I put my language into an array, just so that if I use language inside of
> functions I don't have to declare each variable as a global, just the one
> array. For example (using romanji for the Japanese for non-Japanese enabled
> mail clients on this list):
> 
> $lang = array(
>     "verify" => "kakunin",
>     "name" => "namae",
>     "no" => iie",
>     "delete" => "sakujo,
>     "close_window" => "tojiru"
> );
> 
> Then, when I want to use it in a function I just use "global $lang" and I
> can use the bits that I want (i.e. <?php print($lang[name]); ?>
> 
> For pieces that are a bit more complex, such as phrases that contain links
> or bolding or other attributes that might not line up because of the
> differences in expressing English and Japanese, I use functions:
> 
> function lang_show_result($start,$finish) {
>  $txt = "Showing results $start-$finish.";
>  return($txt);
> }
> 
> 
> > It's very nice to see some activity on here from this end of the mailing
> > list as well.  I am on the verge of putting together a php/mysql
> > multilingual website from scratch and it's good to know that some people
> > are reading up on the list.  I was wondering what people's opinion on
> > the overall structure of a multi language php application is.  There are
> > a number of ways to implement the frontend.
> > 
> > 1.  Do something similar to the way phpMyAdmin works and have different
> > files layed out with the different encoding types and variables listed
> > for each message displayed to the users.
> > 
> > 2.  Use gettext or some other widely used standard.
> > 
> > ..... Etc..
> > 
> > Of course even these 2 solutions have their good and bad points.  The
> > first is quick but harder to maintain.  The second of course is easier
> > to maintain but more difficult to setup from the beginning.  What do
> > others think or what are they using at this time?
> > 
> > Thanks,
> > -jeff
> 
> - AV
> 
> 
> -- 
> PHP Internationalization Mailing List (http://www.php.net/)
> To unsubscribe, visit: http://www.php.net/unsub.php
> 
> 



--- End Message ---
--- Begin Message ---
Errors in my php example / code:

invoke:
  xlate("Search found {count} pages for {keywords}", $count, $query);

in xlate():

  $xlated = preg_replace("/{([^\}]+)}/e", "\$replace_map[$1]" , $xlated);

Sorry :-)
Hans


On Wed, 2002-07-24 at 10:57, Hans Lellelid wrote:
> For translating text that might have dynamic values, I build a wrapper
> function for gettext() -- note that if you do this you'll probably need
> to use a shell/perl script to replace the wrapper function name with
> gettext() or _() before feeding it into thee xgettext tool.
> 
> So my wrapper function is invoked like this:
> 
> xlate("Search found {count} pages for {keywords}", $count, $query$);
> 
> It doesn't matter how you label your {tags}, but make sure you use
> the same label in all translations.  
> 
> ** This way you can re-order the tags in the translated text & PHP will
> still insert the correct values.**
> 
> In the [bad French] POT file:
> 
> msgid "Search found {count} pages for {keywords}"
> msgstr "En cherchant le database pour {keywords}, on a trouve {count}
> results."
> 
> Notice that the the order changes for dynamic elements.
> 
> 
> Here's the actual wrapper function I use:
> 
> function xlate($text) 
> {   
> 
>   // 1) get array of {tags} in text
>   // these will be replaced with passed params
> 
>      preg_match_all("/{([^}]+)}/", $text, $var_matches);
> 
>      $replace_tags = $var_matches[1];
> 
>   // $replace_tags is an array of all tags we need to replace
>   // in original order.
> 
>    $num_args = func_num_args();
>    $num_replace_tags = sizeof($replace_tags);
> 
>    if( ($num_args - 1) < $num_replace_tags) {
>       trigger_error("More replace tags than arguments", E_USER_WARNING);
>    }
> 
>     $replace_map = array();
> 
>     // build a hash of tags & values to replace them with.
> 
>     for($c = 0; $c < $num_replace_tags; $c++) {
>       $replace_map[ $replace_tags[$c] ] = func_get_arg($c+1);
>     }
> 
> 
>    // 2) translate the text
>                       
>       $xlated = gettext($text);
> 
>    // 3) re-insert the values from the hash
>       
>       $xlated = preg_replace("/{([^\}]+)}/e", "\$replace_map[$1]" ,
> $text);]
>                                                               
>                       
>     return $xlated;
> 
> }
> 
> 
> Cheers,
> Hans
> 
> On Wed, 2002-07-24 at 10:11, Anatole Varin wrote:
> > Good question. I'll tell you my hack, however I'd be really curious to hear
> > other people's opinions as well.
> > 
> > For text without links I do something similar to the phpMyAdmin way, however
> > I put my language into an array, just so that if I use language inside of
> > functions I don't have to declare each variable as a global, just the one
> > array. For example (using romanji for the Japanese for non-Japanese enabled
> > mail clients on this list):
> > 
> > $lang = array(
> >     "verify" => "kakunin",
> >     "name" => "namae",
> >     "no" => iie",
> >     "delete" => "sakujo,
> >     "close_window" => "tojiru"
> > );
> > 
> > Then, when I want to use it in a function I just use "global $lang" and I
> > can use the bits that I want (i.e. <?php print($lang[name]); ?>
> > 
> > For pieces that are a bit more complex, such as phrases that contain links
> > or bolding or other attributes that might not line up because of the
> > differences in expressing English and Japanese, I use functions:
> > 
> > function lang_show_result($start,$finish) {
> >  $txt = "Showing results $start-$finish.";
> >  return($txt);
> > }
> > 
> > 
> > > It's very nice to see some activity on here from this end of the mailing
> > > list as well.  I am on the verge of putting together a php/mysql
> > > multilingual website from scratch and it's good to know that some people
> > > are reading up on the list.  I was wondering what people's opinion on
> > > the overall structure of a multi language php application is.  There are
> > > a number of ways to implement the frontend.
> > > 
> > > 1.  Do something similar to the way phpMyAdmin works and have different
> > > files layed out with the different encoding types and variables listed
> > > for each message displayed to the users.
> > > 
> > > 2.  Use gettext or some other widely used standard.
> > > 
> > > ..... Etc..
> > > 
> > > Of course even these 2 solutions have their good and bad points.  The
> > > first is quick but harder to maintain.  The second of course is easier
> > > to maintain but more difficult to setup from the beginning.  What do
> > > others think or what are they using at this time?
> > > 
> > > Thanks,
> > > -jeff
> > 
> > - AV
> > 
> > 
> > -- 
> > PHP Internationalization Mailing List (http://www.php.net/)
> > To unsubscribe, visit: http://www.php.net/unsub.php
> > 
> > 
> 
> 
> 
> 
> -- 
> PHP Internationalization Mailing List (http://www.php.net/)
> To unsubscribe, visit: http://www.php.net/unsub.php
> 
> 



--- End Message ---
--- Begin Message ---
Great solution - looks really nice. I appreciate the advice and I'll give it
a shot on my next site.

BTW, do you do something nifty to maintain the $language variable through
pages (currently I'm appending the variable as a hidden variable in all my
forms and appended to the end of links.

Thanks again,

Anatole
++++++++++++++
AichiNet
*Anatole Varin*
Programming
[EMAIL PROTECTED]





> Here's the actual wrapper function I use:

--- End Message ---
--- Begin Message ---
My feeling is that the easiest way to persist your current language
selection would be to use a session variable (which in most cases would
translate to a cookie on the user's machine).  Your method also works,
of course.

When you setup the session, you could set this automatically  using 
$_SERVER['HTTP_ACCEPT_LANGUAGE'] var.  Note, though, that you may need
to translate the 2-char value to a full language code (e.g. 'en' ->
'en_US' in order for gettext() to work).

Also, depending on how different the different lang versions of the site
are (e.g. different graphics, etc.) you may want to think about using
templates to store versions of your pages for the different languages 
(I use smarty: smarty.php.net).  Using Smarty, you could change the
template root based on the current $language session variable -- and
then all your PHP pages would automatically grab the correct
language-version of the template.

E.g.
        templates/en_US/
        templates/fr_FR/
etc.

HTH,
Hans

On Wed, 2002-07-24 at 11:10, Anatole Varin wrote:
> Great solution - looks really nice. I appreciate the advice and I'll give it
> a shot on my next site.
> 
> BTW, do you do something nifty to maintain the $language variable through
> pages (currently I'm appending the variable as a hidden variable in all my
> forms and appended to the end of links.
> 
> Thanks again,
> 
> Anatole
> ++++++++++++++
> AichiNet
> *Anatole Varin*
> Programming
> [EMAIL PROTECTED]
> 
> 
> 
> 
> 
> > Here's the actual wrapper function I use:
> 
> 



--- End Message ---
--- Begin Message ---
On Wednesday, July 24, 2002, at 10:57  AM, Hans Lellelid wrote:

> For translating text that might have dynamic values, I build a wrapper
> function for gettext() -- note that if you do this you'll probably need
> to use a shell/perl script to replace the wrapper function name with
> gettext() or _() before feeding it into thee xgettext tool.

I'm nearly finished with a huge gettext() based 
internationalization...there are 650+ static strings in my pot file. But 
I was a bit surprised to see your wrapper function, Hans.

The same result can be achieved using standard printf() functions around 
the gettext() call. See the sprintf() manual page, especially the 
section on "Argument swapping". (This applies only to PHP 4.0.6 or 
later).

Example:
printf(gettext("Search found %1\$d pages for %2\$s"),$count,$query);

will achieve the same results without writing your own wrapper. A 
translation would then look like

msgid "Search found %1\$d pages for %2\$s"
msgstr "En cherchant le database pour %2\$s, on a trouve %1\$d"

Other general app notes
-----------------------
1) I also have my app output a META content-type header with the 
appropriate charset declaration, based on the user's selected language.

2) I modified my submission forms as well, to include "accept-charset=" 
with any character sets I support to be permissible.

3) I store the user-selected language as a cookie, though it can be 
overridden by a $lang HTTP_GET_VAR. My "header.inc" file, which is 
included at the top of each page, has a section like this:

///////////////////////////////////////////////////////////////
// Language localization based on cookie variable or passed in
///////////////////////////////////////////////////////////////
$g_default_lang = 'en_US';
if (isset($lang)) {
        // GET_VARS trumps COOKIE_VARS
        if (isset($HTTP_GET_VARS['lang'])) {
                $g_lang = $HTTP_GET_VARS['lang'];
        } else {
                $g_lang = $HTTP_COOKIE_VARS['lang'];
        }
} else {
        $g_lang = $g_default_lang;
}
// Set language to desired language
putenv("LANG=$g_lang");
$checklang = setlocale(LC_ALL, $g_lang);
if ($checklang === FALSE) {
        error_log('Failure setting language to '.$g_lang);
} else {
        error_log("Setting language to $g_lang");
}
// Specify location of translation tables
bindtextdomain ("messages", "./locale");
textdomain ("messages");
setcookie('lang',$g_lang,time()+(60 * 60 * 24 * 
60),'/',$GLOBALS['HTTP_HOST']);
///////////////////////////////////////////////////////////////
// End language localization
///////////////////////////////////////////////////////////////

You may want to replace the $HTTP_GET_VARS, etc with the new 
superglobals, but the gist is still the same.

Cheers,
spud.

-------------------------------------------------------------------
a.h.s. boy
spud(at)nothingness.org            "as yes is to if,love is to yes"
http://www.nothingness.org/
-------------------------------------------------------------------

--- End Message ---
--- Begin Message ---
Spud,

  :-) Brilliant, yes -- I had no idea sprintf() could do argument
swapping.

Thanks!
Hans

On Wed, 2002-07-24 at 11:47, a.h.s.boy wrote:
> On Wednesday, July 24, 2002, at 10:57  AM, Hans Lellelid wrote:
> 
> > For translating text that might have dynamic values, I build a wrapper
> > function for gettext() -- note that if you do this you'll probably need
> > to use a shell/perl script to replace the wrapper function name with
> > gettext() or _() before feeding it into thee xgettext tool.
> 
> I'm nearly finished with a huge gettext() based 
> internationalization...there are 650+ static strings in my pot file. But 
> I was a bit surprised to see your wrapper function, Hans.
> 
> The same result can be achieved using standard printf() functions around 
> the gettext() call. See the sprintf() manual page, especially the 
> section on "Argument swapping". (This applies only to PHP 4.0.6 or 
> later).
> 
> Example:
> printf(gettext("Search found %1\$d pages for %2\$s"),$count,$query);
> 
> will achieve the same results without writing your own wrapper. A 
> translation would then look like
> 
> msgid "Search found %1\$d pages for %2\$s"
> msgstr "En cherchant le database pour %2\$s, on a trouve %1\$d"
> 
> Other general app notes
> -----------------------
> 1) I also have my app output a META content-type header with the 
> appropriate charset declaration, based on the user's selected language.
> 
> 2) I modified my submission forms as well, to include "accept-charset=" 
> with any character sets I support to be permissible.
> 
> 3) I store the user-selected language as a cookie, though it can be 
> overridden by a $lang HTTP_GET_VAR. My "header.inc" file, which is 
> included at the top of each page, has a section like this:
> 
> ///////////////////////////////////////////////////////////////
> // Language localization based on cookie variable or passed in
> ///////////////////////////////////////////////////////////////
> $g_default_lang = 'en_US';
> if (isset($lang)) {
>       // GET_VARS trumps COOKIE_VARS
>       if (isset($HTTP_GET_VARS['lang'])) {
>               $g_lang = $HTTP_GET_VARS['lang'];
>       } else {
>               $g_lang = $HTTP_COOKIE_VARS['lang'];
>       }
> } else {
>       $g_lang = $g_default_lang;
> }
> // Set language to desired language
> putenv("LANG=$g_lang");
> $checklang = setlocale(LC_ALL, $g_lang);
> if ($checklang === FALSE) {
>       error_log('Failure setting language to '.$g_lang);
> } else {
>       error_log("Setting language to $g_lang");
> }
> // Specify location of translation tables
> bindtextdomain ("messages", "./locale");
> textdomain ("messages");
> setcookie('lang',$g_lang,time()+(60 * 60 * 24 * 
> 60),'/',$GLOBALS['HTTP_HOST']);
> ///////////////////////////////////////////////////////////////
> // End language localization
> ///////////////////////////////////////////////////////////////
> 
> You may want to replace the $HTTP_GET_VARS, etc with the new 
> superglobals, but the gist is still the same.
> 
> Cheers,
> spud.
> 
> -------------------------------------------------------------------
> a.h.s. boy
> spud(at)nothingness.org            "as yes is to if,love is to yes"
> http://www.nothingness.org/
> -------------------------------------------------------------------
> 
> 
> -- 
> PHP Internationalization Mailing List (http://www.php.net/)
> To unsubscribe, visit: http://www.php.net/unsub.php
> 
> 



--- End Message ---
--- Begin Message ---
Hi!

I'm new to PHP & Mysql, and I need to build a new web site with Big5
characters.

Will the default installation of PHP and MySQL (both newest version) handle
Big5 character. Would a plain insert statement works???

Anything I need to check before insert / updating the DB

Thanks,

William


--- End Message ---

Reply via email to