|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2010-11-07 12:09 UTC] jeanseb at au-fil-du dot net
Description:
------------
man bindtextdomain :
If dirname is NULL, the function returns the previously set base directory for domain domainname.
In PHP we are returning the CWD.
I have attached a patch with 2 tests.
ext/gettext/tests/gettext_bindtextdomain-nulldir-alreadyset.phpt
=> PASS with my patch
ext/gettext/tests/gettext_bindtextdomain-nulldir.phpt
=> Fail, my patch introduce a BC. I'm not sure we want this but I don't see any workarround.
Test script:
---------------
<?php
echo 'getcwd() : ' . getcwd() . PHP_EOL;
echo 'bindtextdomain("messages", "./locale") : ' . bindtextdomain("messages", "./locale") . PHP_EOL;
echo 'bindtextdomain("messages",NULL) : ' . bindtextdomain("messages",NULL) . PHP_EOL;
Expected result:
----------------
getcwd() : /home/jeanseb
bindtextdomain("messages", "./locale") : /home/jeanseb/locale
bindtextdomain("messages",NULL) : /home/jeanseb/locale
Actual result:
--------------
getcwd() : /home/jeanseb
bindtextdomain("messages", "./locale") : /home/jeanseb/locale
bindtextdomain("messages",NULL) : /home/jeanseb
Patchesfix_broken_bindtextdomain (last revision 2010-11-26 17:09 UTC by greno at verizon dot net)Test_if_NULL_or_empty (last revision 2010-11-24 22:38 UTC by pajoye@php.net) gettext.patch (last revision 2010-11-07 11:49 UTC by jeanseb at au-fil-du dot net) Pull Requests
Pull requests:
HistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Fri Oct 24 20:00:01 2025 UTC |
The previous expected PHP results shown are not correct for 'bindtextdomain'. The expected results should be: getcwd() : /home/jeanseb bindtextdomain("messages", "./locale") : ./locale bindtextdomain("messages",NULL) : ./locale When I test using python 'bindtextdomain' I get the correct result: # cat test.py #!/usr/bin/env python from gettext import * print bindtextdomain("messages", "./locale"); print bindtextdomain("messages",None); # python test.py ./locale ./locale Relative base directories are allowed.And to clarify regarding the case where no previous bindtextdomain call was made prior to the bindtextdomain call with a NULL directory argument. In this case bindtextdomain should return the default locale directory for the system. In the case of Linux this is '/usr/share/locale'. I tested this again using python and it produces the correct result: # cat test2.py #!/usr/bin/env python from gettext import * ### no previous bindtextdomain call in effect print bindtextdomain("messages",None); # python test2.py /usr/share/localeFixing the broken bindtextdomain behavior is not going to create any confusion for any user. In fact, right now I can simulate the correct behavior by having an app store/restore the domain directory mapping from a separate tracking mechanism and all of gettext including bindtextdomain in PHP then works perfectly as it should. The issue is that most users would be expecting bindtextdomain to work correctly so that they could retrieve the current directory mapping using a NULL argument without having to resort to creating their own separate tracking mechanisms for keeping track of that state. When I create a small PHP file holding something like: bindtextdomain("messages", "./locale"); textdomain("messages"); And then I import that file into my files such as: /index.php /subapp1/index.php /subapp2/index.php It means that each of the directories ( /, /subapp1, /subapp2 ) are expected to have their own 'locale' directories. This way all translations related to /subapp1 are stored in /subapp1/locale/..., those for /subapp2 are stored in /subapp2/locale/... Because the binding is relative you do not need to be resetting and manipulating the domain directory binding all the time to achieve translations using a local locale directory. There should be no difference between the PHP implementation of bindtextdomain and the GNU implementation(C) which is also the same as is found in Java, Python, and other languages. If you have any doubt go test these languages. // HERE IS THE BEHAVIOR THAT SHOULD OCCUR: // no mapping in effect yet bindtextdomain("messages", NULL); // should return default system locale directory, eg: "/usr/share/locale" on Linux // now we create a relative mapping bindtextdomain("messages", "./locale"); // set a relative domain directory mapping bindtextdomain("messages", NULL); // should return "./locale" // now we create an absolute mapping bindtextdomain("messages", "/absolutepath/locale"); // set an absolute domain directory mapping bindtextdomain("messages", NULL); // should return "/absolutepath/locale" And this is exactly the behavior of the other languages and of the GNU (C) implementation. And PHP needs needs to fix its broken behavior. As far as getting this fix in the RC's for 5.2.15 and 5.3.4. This change fixes something that is badly broken and it warrants an exception. .In addition, consider the case where you need to temporarily remap the domain directory to another translation store. // WORKING WITH MULTIPLE TRANSLATION STORES: bindtextdomain("messages", "./locale"); textdomain("messages"); ... // work with local translation store ... // now need to get some translations from a different translation store savedmapping = bindtextdomain("messages", NULL); bindtextdomain("messages", "/pathtodifferentstore/locale"); ... // temporarily work with different translation store ... // now we need to restore previous mapping bindtextdomain("messages", savedmapping); ... // once again working with previous translation store ... Right now with PHP you cannot work with any nested heirarchy of multiple translation stores because you have no idea what is the current domain directory mapping so you cannot save it and restore it later. .Looking at bindtextdomain gettext.c in the current 5_3 tree: PHP_NAMED_FUNCTION(zif_bindtextdomain) { char *domain, *dir; int domain_len, dir_len; char *retval, dir_name[MAXPATHLEN]; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &domain, &domain_len, &dir, &dir_len) == FAILURE) { return; } PHP_GETTEXT_DOMAIN_LENGTH_CHECK if (domain[0] == '\0') { php_error(E_WARNING, "The first parameter of bindtextdomain must not be empty"); RETURN_FALSE; } if (dir[0] != '\0' && strcmp(dir, "0")) { if (!VCWD_REALPATH(dir, dir_name)) { RETURN_FALSE; } } else if (!VCWD_GETCWD(dir_name, MAXPATHLEN)) { RETURN_FALSE; } retval = bindtextdomain(domain, dir_name); RETURN_STRING(retval, 1); } ================================================== This logic in that function makes no sense with respect to bindtextdomain. The function should ONLY need to do this: PHP_NAMED_FUNCTION(zif_bindtextdomain) { char *domain, *dir; int domain_len, dir_len; char *retval, dir_name[MAXPATHLEN]; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &domain, &domain_len, &dir, &dir_len) == FAILURE) { return; } PHP_GETTEXT_DOMAIN_LENGTH_CHECK if (domain[0] == '\0') { php_error(E_WARNING, "The first parameter of bindtextdomain must not be empty"); RETURN_FALSE; } retval = bindtextdomain(domain, dir_name); RETURN_STRING(retval, 1); } ================================================== All that should be necessary is to check that the first argument (domain) is not NULL and then just return the result of calling the underlying bindtextdomain. Nothing else needs to be checked. All that is happening is that a string representing a potential directory path is being bound to a domain name OR a NULL directory arg is passed in which case the underlying bindtextdomain will return the previous setting. Can this change PLEASE be made asap and put into 5.2.15 and 5.3.3? It needs to get into 5.2.15 because that is the last rev from my understanding for the 5.2 releases and as this is currently being used almost everywhere right now it is important that the 5.2 release series have a fix for the broken bindtextdomain function. The 5.3.3 is not as important but certainly would be nice to get this fix out quickly. .This still isn't working. I'm running PHP Version 7.4.3 on Ubuntu 20.04.4 LTS. bindtextdomain('strings', '/var/www/html/locale/'); echo bindtextdomain($domain, NULL); This code returns '/var/www/html'. The bindtextdomain manual entry (https://www.php.net/manual/en/function.bindtextdomain.php) states 'The directory path. If null, the currently set directory is returned.'Additionally, bind_textdomain_codeset is not returning the currently set encoding. bind_textdomain_codeset('strings', 'UTF-8'); echo bind_textdomain_codeset('strings', NULL); This code returns '' (nothing at all). The bind_textdomain_codeset manual entry (https://www.php.net/manual/en/function.bind-textdomain-codeset.php) states 'The code set. If null, the currently set encoding is returned.'