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.
Related
I want to save a file to Windows using Japanese characters in the filename.
The PHP file is saved with UTF-8 encoding
<?php
$oldfile = "test.txt";
$newfile = "日本語.txt";
copy($oldfile,$newfile);
?>
The file copies, but appears in Windows as
日本語.txt
How do I make it save as
日本語.txt
?
I have ended up using the php-wfio extension from https://github.com/kenjiuno/php-wfio
After putting php_wfio.dll into php\ext folder and enabling the extension, I prefixed the filenames with wfio:// (both need to be prefixed or you get a Cannot rename a file across wrapper types error)
My test code ends up looking like
<?php
$oldfile = "wfio://test.txt";
$newfile = "wfio://日本語.txt";
copy($oldfile,$newfile);
?>
and the file gets saved in Windows as 日本語.txt which is what I was looking for
Starting with PHP 7.1, i would link you to this answer https://stackoverflow.com/a/38466772/3358424 . Unfortunately, the most of the recommendations are not valid, that are listed in the answer that strives to be the only correct one. Like "just urlencode the filename" or "FS expects iso-8859-1", etc. are terribly wrong assumptions that misinform people. That can work by luck but are only valid for US or almost western codepages, but are otherwise just wrong. PHP 7.1 + default_charset=UTF-8 is what you want. With earlier PHP versions, wfio or wrappers to ext/com_dotnet might be indeed helpful.
Thanks.
Update:
Preparing a bug report to the great people that make PHP 7 possible I revised my research once more and tried to melt it down to a few simple lines of code. While doing this I found that PHP itself is not the cause of the problem. I will share my results here when I'm done. Just so you know and don't possibly waste your time or something :)
Synopsis: PHP7 now seems able to write UTF-8 filenames but is unable to access them?
Preamble: I read about 10-15 articles here touching the subject but they did not help me solve the problem and they all are older than the PHP7 release. It seems to me that this is probably a new issue and I wonder if it might be a bug. I spent a lot of time experimenting with en-/decoding of the strings and trying to figure out a way to make it work - to no avail.
Good day everybody and greetings from Germany (insert shy not-my-native-language-remark here), I hope you can help me out with this new phenomenon I encountered. It seems to be "new" in the sense that it came with PHP 7.
I think most people working with PHP on a Windows system are very familiar with the problem of filenames and the transparent wrapper of PHP that manages access to files that have non-ASCII filenames (or windows-1252 or whatever is the system code page).
I'm not quite sure how to approach the subject and as you can see I'm not very experienced in composing questions so please don't rip my head off instantly. And yes I will strive to keep it short. Here we go:
First symptom: after updating to PHP7 I sometimes encountered problems with accessing files generated by my software. Sometimes it worked as usual, sometimes not. I found out the difference was that PHP7 now seems able to write UTF-8 filenames but is unable to access files with those names.
After generating said files on two separate "identical" systems (differing only in the PHP version) this is how the files are named on the hard drive:
PHP 5.5: Lokaltest_KG_æ¼¢å—_汉å—_Krümhold-DEZ1604-140081-complete.zip
PHP 7: Lokaltest_KG_漢字_汉字_Krümhold-DEZ1604-140081-complete.zip
Splendid, PHP 7 is capable of writing unicode-filenames on the HDD, and UTF-16 is used on windows afaik. Now the downside is that when I try to access those files for example with is_file() PHP 5.5 works but PHP 7 does not.
Consider this code snippet (note: I "hacked" into this function because it was the simplest way, it was not written for this purpose). This function gets called after a zip-file gets generated taking on the name of the customer and other values to determine a proper name. Those come out of the database. Database and internal encoding of PHP are both UTF-8. clearstatcache is per se not necessary but I included it to make things clearer. Important: Everything that happens is done with PHP7, no other entity is responsible for creating the zip-file. To be precise it is done with class ZipArchive. Actually it does not even matter that it is a zip-archive, the point is that the filename and the content of the file are created by PHP7 - successfully.
public static function downloadFileAsStream( $file )
{
clearstatcache();
print $file . "<br/>";
var_dump(is_file($file));
die();
}
Output is:
D:/htdocs/otm/.data/_tmp/Lokaltest_KG_漢字_汉字_Krümhold-DEZ1604-140081-complete.zip
bool(false)
So PHP7 is able to generate the file - they indeed DO exist on the harddrive and are legit and accessible and all - but is incapable of accessing them. is_file is not the only function that fails, file_exists() does too for example.
A little experiment with encoding conversion to give you a taste of the things I tried:
public static function downloadFileAsStream( $file )
{
clearstatcache();
print $file . "<br/>";
print mb_detect_encoding($file, 'ASCII,UTF-16,windows-1252,UTF-8', false) . "<br/>";
print mb_detect_encoding($file, 'ASCII,UTF-16,windows-1252,UTF-8', true) . "<br/>";
if (($detectedEncoding = mb_detect_encoding($file, 'ASCII,UTF-16,windows-1252,UTF-8', true)) != 'windows-1252')
{
$file = mb_convert_encoding($file, 'UTF-16', $detectedEncoding);
}
print $file . "<br/>";
var_dump(is_file($file));
die();
}
Output is:
D:/htdocs/otm/.data/_tmp/Lokaltest_KG_漢字_汉字_Krümhold-DEZ1604-140081-complete.zip
UTF-8
UTF-8
D:/htdocs/otm/.data/_tmp/Lokaltest_KG_o"[W_lI[W_Kr�mhold-DEZ1604-140081-complete.zip
NULL
So converting from UTF-8 (database/internal encoding) to UTF-16 (windows file system) does not seem to work either.
I am at the end of my rope here and sadly the issue is very important to us since we cannot update our systems with this problem looming in the background. I hope somebody can shed a little light on this. Sorry for the long post, I'm not sure how well I could get my point across.
Addition:
$file = utf8_decode($file);
var_dump(is_file($file));
die();
Delivers false for the filename with the japanese letters. When I change the input used to create the filename so that the filename now is Lokaltest_KG_Krümhold-DEZ1604-140081-complete.zip above code delivers true. So utf8_decode helps but only with a small part of unicode, german umlauts?
Answering my own question here: The actual bad boy was the component ZipArchive which created files with incorrectly encoded filenames. I have written a hopefully helpful bug report: https://bugs.php.net/bug.php?id=72200
Consider this short script:
print "php default_charset: ".ini_get('default_charset')."\n"; // just 4 info (UTF-8)
$filename = "bugtest_müller-lüdenscheid.zip"; // just an example
$filename = utf8_encode($filename); // simulating my database delivering utf8-string
$zip = new ZipArchive();
if( $zip->open($filename, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true )
{
$zip->addFile('bugtest.php', 'bugtest.php'); // copy of script file itself
$zip->close();
}
var_dump( is_file($filename) ); // delivers ?
output:
output PHP 5.5.35:
php default_charset: UTF-8
bool(true)
output PHP 7.0.6:
php default_charset: UTF-8
bool(false)
I'm trying to use PHP to read a Windows folder where the folder content contains files with Spanish names (for example Español.doc)
However the filenames print out incorrectly, "Espan??ol.doc" in the above case.
The function mb_detect_encoding($file) returns ASCII but somehow the ñ is not displayed. Is there a quick fix for this?
I am using PHP 5.4.16, Windows 7 Home Premium Edition Service Pack 1, Apache/2.4.4 and (Win32) OpenSSL/0.9.8y.
Try converting to filename to cp1252 like this:
if (file_exists(iconv('utf-8', 'cp1252', $utffilename)));
Here is something I've tried on 5.3.x/Ubuntu, in a console environment:
<?php
$file = 'Español.doc';
echo file_get_contents($file);
The file contains the word "Hello", and it prints to the screen fine. Thus, I think it is safe to say that even older versions of PHP support UTF-8 file names.
Could the problem be that PHP on Windows behaves differently? Try this in a console too.
Also, check with your browser to see what rendering mode it is using. For Firefox, use View Page Info and check the Encoding in the General tab.
I've searched hours for a solution for this including in the documentation.
trying to use gettext for hebrew translations,
using PHP 5.3.1 and wamp,
it prints out "hello world" and not the Hebrew equivalent
$directory = '/locale';
$domain = 'messages';
$locale ="he_IL";
putenv("LANG=".$locale); //not needed for my tests, but people say it's useful for windows
setlocale( LC_ALL, $locale);
bindtextdomain($domain, $directory);
textdomain($domain);
bind_textdomain_codeset($domain, 'UTF-8');
echo _("hello world");
I use poedit to create the mo/po files, they are located on:
./locale/he_IL/LC_MESSAGES/messages.mo
the php file is at "./"
Why don't I get the hebrew text?
Ok solved,
Had to update to PHP version 5.3.5/5.3.10
and because I'm using windows I had to use this locale "Hebrew_Israel.1255"
instead of "he_IL" (that's how windows calls the hebrew locale anyway).
Of course I had to also rename the folders in the ./locale to "Hebrew_Israel.1255"
Now the system successfully chooses the locale
as pointed out by MarcB, PHP isn't magically going to translate the words into different language for you. but there are several different solutions out there to help you out. you can make use of google translator API to convert the text between different languages for example.
try {
$gt = new Gtranslate;
echo "Translating [Hello World] from English to German => ".$gt->english_to_german("hello world")."<br/>";
echo "Translating [Ciao mondo] Italian to English => ".$gt->it_to_en("Ciao mondo")."<br/>";
} catch (GTranslateException $ge) {
echo $ge->getMessage();
}
you can read more about google translator API here http://code.google.com/p/gtranslate-api-php/
You should check that "he_IL" locale is installed in your system. I don't know how to do it in Windows, but in Linux you can run "locale -a"(http://linux.about.com/library/cmd/blcmdl1_locale.htm) to see all locales installed.
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