Adding support for i18n in PHP with gettext? - php

I've always heard about gettext - I know it's some sort of unix command to lookup a translation based on the string argument provided, and then produces a .pot file but can someone explain to me in layman's terms how this is taken care of in a web framework?
I might get around to looking at how some established framework has done it, but a layman's explanation would help because it just might help clear the picture a bit more before I actually delve into things to provide my own solution.

The gettext system echoes strings from a set of binary files that are created from source text files containing the translations in different languages for the same sentence.
The lookup key is the sentence in a "base" language.
in your source code you will have something like
echo _("Hello, world!");
for each language you will have a corresponding text file with the key and the translated version (note the %s that can be used with printf functions)
french
msgid "Hello, world!"
msgstr "Salut, monde!"
msgid "My name is %s"
msgstr "Mon nom est %s"
italian
msgid "Hello, world!"
msgstr "Ciao, mondo!"
msgid "My name is %s"
msgstr "Il mio nome è %s"
These are the main steps you need to go through for creating your localizations
all your text output must use gettext functions (gettext(), ngettext(), _())
use xgettext (*nix) to parse your php files and create the base .po text file
use poedit to add translation texts to the .po files
use msgfmt (*nix) to create the binary .mo file from the .po file
put the .mo files in a directory structure like
locale/de_DE/LC_MESSAGES/myPHPApp.mo
locale/en_EN/LC_MESSAGES/myPHPApp.mo
locale/it_IT/LC_MESSAGES/myPHPApp.mo
then you php script must set the locale that need to be used
The example from the php manual is very clear for that part
<?php
// Set language to German
setlocale(LC_ALL, 'de_DE');
// Specify location of translation tables
bindtextdomain("myPHPApp", "./locale");
// Choose domain
textdomain("myPHPApp");
// Translation is looking for in ./locale/de_DE/LC_MESSAGES/myPHPApp.mo now
// Print a test message
echo gettext("Welcome to My PHP Application");
// Or use the alias _() for gettext()
echo _("Have a nice day");
?>
Always from the php manual look here for a good tutorial

Related

How to disable references in poedit

How to disable adding references to *.po file? in POedit?
poedit adds references, but do not need it.
Example of my gettext file:
#: ../../../tests/cases/Command/SysInfoTest.php:49
#: ../../../tests/cases/Command/SysInfoTest.php:238
#: ../../../tests/cases/Command/SysInfoTest.php:248
msgid "ERROR__SYSINFO__INVALID_SAVE_PATH"
msgstr "The source type for the request is invalid."
and here is how I would like to:
msgid "ERROR__SYSINFO__INVALID_SAVE_PATH"
msgstr "The source type for the request is invalid."
is there any solutions? or do I need to parse and delete references manually?
The GNU gettext manual documents the --no-location flag for xgettext that does exactly what you want.

PHP Gettext - No translation

I am trying to use the PHP gettext extension in order to translate some strings. All functions appear to return the correct values but calling gettext()/_() returns the original string only. The PO/MO files seem correct and I believe I have set the directories up correctly. I am running WAMP Server with PHP 5.3.10 on Windows (also tried running 5.3.4 and 5.3.8 because I have the installations).
Firstly, see /new2/www/index.php:
$locale = 'esn'; # returns Spanish_Spain.1252 in var dump
putenv("LC_ALL={$locale}"); // Returns TRUE
setlocale(LC_ALL, $locale); // Returns 'Spanish_Spain.1252'
$domain = 'messages';
bindtextdomain($domain, './locale'); // Returns C:\wamp\www\new2\www\locale
bind_textdomain_codeset($domain, 'UTF-8'); // Returns UTF-8
textdomain($domain); // Returns'messages'
print gettext("In the dashboard"); // Prints the original text, not the translation.
exit;
I have created the following file structure:
www/new2/www/locale/Spanish_Spain.1252/LC_MESSAGES/messages.mo
I have also tried replacing Spanish_Spain.1252 with: es_ES, esn, esp, Spanish, and Spanish_Spain.
The PO file used to generate the MO is like so (only the relevant entry given):
#: C:\wamp\www\new2/www/index.php:76
msgid "In the dashboard"
msgstr "TRANSLATED es_ES DASHBOARD"
This was generated using PoEdit. I have restarted Apache after adding any new .MO file. Also note that I was previously using Zend_Translate with Gettext and it was translating correctly. I wish to rely on the native gettext extension, though, in part because I am attempting to create a lightweight framework of my own.
Any help would be appreciated.
Edit: Amended directory structure. Note - will be able to try recent answers within 24hrs.
I set this up on my XAMPP instance and figure it out.
Flat out setlocale does not work on Windows, so what it returns is irrelevant.
For Windows you set the locale using the standard language/country codes (in this case es_ES is Spanish as spoken in Spain)
Under your locale directory create es_ES/LC_MESSAGES/. This where your messages.mo file lives.
$locale = 'es_ES';
putenv("LC_ALL={$locale}"); // Returns TRUE
$domain = 'messages';
bindtextdomain($domain, './locale');
bind_textdomain_codeset($domain, 'UTF-8');
textdomain($domain); // Returns'messages'
print gettext("In the dashboard");
exit;
I am not sure if this made a different, but I did two things when creating the po file. In poEdit under File -> Preferences I changed the Line ending format to Windows. And after I created the initial po with poEdit I opened the file in Notepad++ and switched the encoding type to UTF-8 as poEdit did not do this.
I hope this at least points you in the right direction.
References
PHP Localization Tutorial on Windows
Country Codes
Language Codes
Your code mentions this as the return value from bindtextdomain:
C:\wamp\www\new2\www\locale
With the setlocale of Spanish_Spain.1252 and textdomain of messages, calls to gettext will look in this path:
C:\wamp\www\new2\www\locale\Spanish_Spain.1252\LC_MESSAGES\messages.mo
But you created the file structure of:
www/new2/locale/Spanish_Spain.1252/LC_MESSAGES/messages.mo
^^
www/ missing here
Edit
Okay, so that didn't help. I've created a test script on Windows and using POEdit like you:
$locale = "Dutch_Netherlands.1252";
putenv("LC_ALL=$locale"); // 'true'
setlocale(LC_ALL, $locale); // 'Dutch_Netherlands.1252'
bindtextdomain("messages", "./locale"); // 'D:\work\so\l10n\locale'
textdomain("messages"); // 'messages'
echo _("Hello world"); // 'Hallo wereld'
My folder structure is like this:
D:\work\so\l10n\
\locale\Dutch_Netherlands.1252\LC_MESSAGES\messages.mo
\locale\Dutch_Netherlands.1252\LC_MESSAGES\messages.po
\test.php
Hope it helps, although it looks almost identical to yours. A few things I found online:
It's important to set the character set in .po file
Spaces inside the localization file might have a UTF8 alternative, so be wary of key lookups failing. Probably the best thing to test first is keys without spaces at all.
A suggestion: you may need the full locale for the .mo file. This is probably Spanish_Spain.UTF8 or esn_esn.UTF8 or esn_esp.UTF8 (not 1252, as you change the code base).
To track what directory it's looking for, you can install Process monitor (http://technet.microsoft.com/en-us/sysinternals/bb896645). It spews out bucket loads on info, but you should be able to find out which file/directory is being looked for.
(My other thought is to check file permissions - but if you already had something similar in Zend_Translate, then probably not the cause, but worth checking anyway).
Sorry if not good - but might give you a clue.
Look here. It works for me on windows and on linux also. The last values in the array works for windows. List of languages names can be found here. My catalogs are in
./locales/en/LC_MESSAGES/domain.mo
/cs/LC_MESSAGES/domain.mo
I have never tried using gettext on Windows, but each time I had problems with gettext on linux systems, the reason was that an appropriate language pack was not installed.
Problem can be also that when you change your *.po and *.mo files, you have to restart the Apache Server. This can be problem, so you can use workaround - always rename these files to some new name and they will be reloaded.

How to run or load .po/.mo files for localization in php

I have installed poedit and running my file through it, it creates .po and .mo files for them. But I have a problem to load and use these files for translating my text. I don't know how to load or open the translated files and to show the translated content.
Can anyone help me about this. I tried every possible source but not succeeded.
First of all you need to inform PHP which locale and domain you are using.
putenv("LANG=da_DK");
setlocale('LC_ALL', "da_DK");
bindtextdomain("mycatalog", "./locale/");
textdomain("mycatalog");
In this case I'm having a Danish translation and a file called mycatalog.mo (and .po). These files are placed (from your root) here: locale/da_DK/LC_MESSAGES/mycatalog.mo/po
In order to show your translation, you will do this:
echo _("Hello world"); // Which would become "Hej verden"
_(); is an alias of gettext(); The smart thing about gettexts is that if there's no translation you will not have an ugly language code like "MSG_HELLO_WORLD" in your UI, but instead a better alternative: Simply the plain English text.
In the messages.po file you must have all the messages (case-sensitive and also with respect to used commas, dots, colons, etc.) on this form:
msgid "Hello world!"
msgstr "Hej verden!"
When you have added this to your .po file, you open this file in poedit, hit "Save" and it will generate a .mo file. This file is uploaded to the same directory as the .po file (typically something like \locale\da_DK\LC_MESSAGES\ from the script root)
To translate dynamic/variable content you can use - among other things - sprintf, in this manner:
echo sprintf(_("My name is %s"), $name);
In this case the %s will occur in the .po file; When you have the translated string (which contains the %s), sprintf will make sure to replace the %s with the variable content. IF the variable must be translated too, you can do this:
echo sprintf(_("The color of my house is %s"), _($color));
Then you don't need a full sentence for every color, but you still get the colors translated.
It is important to note that the first time a .mo is run on the server it is cached - and there is no way of removing this file from the cache without restarting (Apache or the like itself should be enough). This means that any changes you make to the .mo after the first time it is used, will not be effective. There are a number of hacks to work around this, but honestly, they are mostly not very pretty (they include copying the .mo, add the time() behind it and then import and cache it again). This last paragraph is only of importance if you aren't going to translate the whole thing at once, but in chunks.
If you want to create your own translation tool at some point, this tool helps you convert .po to .mo using PHP:
http://www.josscrowcroft.com/2011/code/php-mo-convert-gettext-po-file-to-binary-mo-file-php/
See (and explore) http://php.net/manual/en/book.gettext.php. There are user-comments on that page that should give you an idea on how to procede.
Also, your question is a duplicate of Get translations from .po or .mo file

gettext: retrieve msgid from msgstr

Is it possible to retrieve the msgid from a given msgstr without messing around with the po-files?
Reverse lookup? Not with the native PHP gettext extension. But you can use gettext.php from upgradephp. Specifically look for gettext___load_mo($fn,"domain"). It fills up a global $_GETTEXT array from the raw .mo data, and you could use array_flip($_GETTEXT["domain"]) to receive a msgstr->msgid mapping.

Localization .po file format

I am working on web application (used PHP, javascript language) , I have provided localization support to my application. Currently supported English language.
I am supporting another languages.
I know basic format of .po file i.e. :
msgid "Unknown login error"
msgstr “Please enter corrent credientioals"
I wanted to know standard format for writing po file.
Please suggest me, from where I will get po file standard format through with I can build good po file
http://www.gnu.org/software/hello/manual/gettext/PO-Files.html
Those are the most used tags:
#: = source file.
msgid = original string.
msgstr = denotes the string which to become the translation.
Example:
#: Folder/File.extension
msgid "Original String"
msgstr ""
Documentation

Categories