[FORMAT] Run php-cs-fixer in php-gettext

This commit is contained in:
Diogo Cordeiro 2019-06-23 17:36:15 +01:00
parent a1edc2c6a9
commit b408208e4c
12 changed files with 1026 additions and 470 deletions

View File

@ -0,0 +1,41 @@
PACKAGE = php-gettext-$(VERSION)
VERSION = 1.0.12
DIST_FILES = \
gettext.php \
gettext.inc \
streams.php \
AUTHORS \
README \
COPYING \
Makefile \
examples/index.php \
examples/pigs_dropin.php \
examples/pigs_fallback.php \
examples/locale/sr_CS/LC_MESSAGES/messages.po \
examples/locale/sr_CS/LC_MESSAGES/messages.mo \
examples/locale/de_CH/LC_MESSAGES/messages.po \
examples/locale/de_CH/LC_MESSAGES/messages.mo \
examples/update \
tests/LocalesTest.php \
tests/ParsingTest.php
check:
phpunit --verbose tests
dist: check
if [ -d $(PACKAGE) ]; then \
rm -rf $(PACKAGE); \
fi; \
mkdir $(PACKAGE); \
if [ -d $(PACKAGE) ]; then \
cp -rp --parents $(DIST_FILES) $(PACKAGE); \
tar cvzf $(PACKAGE).tar.gz $(PACKAGE); \
rm -rf $(PACKAGE); \
fi;
sign: dist
gpg --armor --sign --detach-sig $(PACKAGE).tar.gz
clean:
rm -f $(PACKAGE).tar.gz $(PACKAGE).tar.gz.asc

View File

@ -1,4 +1,4 @@
PHP-gettext 1.0 (https://launchpad.net/php-gettext) PHP-gettext 1.0.12 (https://launchpad.net/php-gettext)
Copyright 2003, 2006, 2009 -- Danilo "angry with PHP[1]" Segan Copyright 2003, 2006, 2009 -- Danilo "angry with PHP[1]" Segan
Licensed under GPLv2 (or any later version, see COPYING) Licensed under GPLv2 (or any later version, see COPYING)
@ -28,7 +28,7 @@ Why?
I got used to having gettext work even without gettext I got used to having gettext work even without gettext
library. It's there in my favourite language Python, so I was library. It's there in my favourite language Python, so I was
surprised that I couldn't find it in PHP. I even searched for it, surprised that I couldn't find it in PHP. I even Googled for it,
but to no avail. but to no avail.
So, I said, what the heck, I'm going to write it for this So, I said, what the heck, I'm going to write it for this

View File

@ -0,0 +1,27 @@
<html>
<head>
<title>PHP-gettext examples</title>
</head>
<body>
<h1>PHP-gettext</h1>
<h2>Introduction</h2>
<p>PHP-gettext provides a simple gettext replacement that works independently from the system's gettext abilities.
It can read MO files and use them for translating strings.</p>
<p>This version has the ability to cache all strings and translations to speed up the string lookup.
While the cache is enabled by default, it can be switched off with the second parameter in the constructor (e.g. when using very large MO files
that you don't want to keep in memory)</p>
<h2>Examples</h2>
<ul>
<li><a href="pigs_dropin.php">PHP-gettext as a dropin replacement</a></li>
<li><a href="pigs_fallback.php">PHP-gettext as a fallback solution</a></li>
</ul>
<hr />
<p>Copyright (c) 2003-2006 Danilo Segan</p>
<p>Copyright (c) 2005-2006 Steven Armstrong</p>
</body>
</html>

View File

@ -0,0 +1,30 @@
# Sample translation for PHP-gettext 1.0
# Copyright (c) 2003 Danilo Segan <danilo@kvota.net>
#
msgid ""
msgstr ""
"Project-Id-Version: pigs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2003-10-23 04:50+0200\n"
"PO-Revision-Date: 2003-11-01 23:40+0100\n"
"Last-Translator: Danilo Segan <danilo@kvota.net>\n"
"Language-Team: Serbian (sr) <danilo@kvota.net>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#"Plural-Forms: nplurals=2; plural=n != 1;\n"
#: pigs.php:19
msgid ""
"This is how the story goes.\n"
"\n"
msgstr ""
"Und so geht die Geschichte.\n"
"\n"
#: pigs.php:21
#, php-format
msgid "%d pig went to the market\n"
msgid_plural "%d pigs went to the market\n"
msgstr[0] "%d Schwein ging zum Markt\n"
msgstr[1] "%d Schweine gingen zum Markt\n"

View File

@ -0,0 +1,30 @@
# Sample translation for PHP-gettext 1.0
# Copyright (c) 2003,2006 Danilo Segan <danilo@kvota.net>
#
msgid ""
msgstr ""
"Project-Id-Version: pigs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2003-10-23 04:50+0200\n"
"PO-Revision-Date: 2006-02-02 21:06+0100\n"
"Last-Translator: Danilo Segan <danilo@kvota.net>\n"
"Language-Team: Serbian (sr) <danilo@kvota.net>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
#: pigs.php:19
msgid ""
"This is how the story goes.\n"
"\n"
msgstr "Овако иде прича.\n\n"
#: pigs.php:21
#, php-format
msgid "%d pig went to the market\n"
msgid_plural "%d pigs went to the market\n"
msgstr[0] "%d мало прасе је отишло на пијац\n"
msgstr[1] "%d мала прасета су отишла на пијац\n"
msgstr[2] "%d малих прасића је отишло на пијац\n"

View File

@ -0,0 +1,94 @@
<?php
/*
Copyright (c) 2003,2004,2005,2009 Danilo Segan <danilo@kvota.net>.
Copyright (c) 2005,2006 Steven Armstrong <sa@c-area.ch>
This file is part of PHP-gettext.
PHP-gettext is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
PHP-gettext is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PHP-gettext; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
error_reporting(E_ALL | E_STRICT);
// define constants
define('PROJECT_DIR', realpath('./'));
define('LOCALE_DIR', PROJECT_DIR .'/locale');
define('DEFAULT_LOCALE', 'en_US');
require_once('../gettext.inc');
$supported_locales = array('en_US', 'sr_CS', 'de_CH');
$encoding = 'UTF-8';
$locale = (isset($_GET['lang']))? $_GET['lang'] : DEFAULT_LOCALE;
// gettext setup
T_setlocale(LC_MESSAGES, $locale);
// Set the text domain as 'messages'
$domain = 'messages';
bindtextdomain($domain, LOCALE_DIR);
// bind_textdomain_codeset is supported only in PHP 4.2.0+
if (function_exists('bind_textdomain_codeset')) {
bind_textdomain_codeset($domain, $encoding);
}
textdomain($domain);
header("Content-type: text/html; charset=$encoding");
?>
<html>
<head>
<title>PHP-gettext dropin example</title>
</head>
<body>
<h1>PHP-gettext as a dropin replacement</h1>
<p>Example showing how to use PHP-gettext as a dropin replacement for the native gettext library.</p>
<?php
print "<p>";
foreach ($supported_locales as $l) {
print "[<a href=\"?lang=$l\">$l</a>] ";
}
print "</p>\n";
if (!locale_emulation()) {
print "<p>locale '$locale' is supported by your system, using native gettext implementation.</p>\n";
} else {
print "<p>locale '$locale' is _not_ supported on your system, using the default locale '". DEFAULT_LOCALE ."'.</p>\n";
}
?>
<hr />
<?php
// using PHP-gettext
print "<pre>";
print _("This is how the story goes.\n\n");
for ($number=6; $number>=0; $number--) {
print sprintf(
T_ngettext(
"%d pig went to the market\n",
"%d pigs went to the market\n",
$number
),
$number
);
}
print "</pre>\n";
?>
<hr />
<p>&laquo; <a href="./">back</a></p>
</body>
</html>

View File

@ -0,0 +1,92 @@
<?php
/*
Copyright (c) 2003,2004,2005,2009 Danilo Segan <danilo@kvota.net>.
Copyright (c) 2005,2006 Steven Armstrong <sa@c-area.ch>
This file is part of PHP-gettext.
PHP-gettext is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
PHP-gettext is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PHP-gettext; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
error_reporting(E_ALL | E_STRICT);
// define constants
define('PROJECT_DIR', realpath('./'));
define('LOCALE_DIR', PROJECT_DIR .'/locale');
define('DEFAULT_LOCALE', 'en_US');
require_once('../gettext.inc');
$supported_locales = array('en_US', 'sr_CS', 'de_CH');
$encoding = 'UTF-8';
$locale = (isset($_GET['lang']))? $_GET['lang'] : DEFAULT_LOCALE;
// gettext setup
T_setlocale(LC_MESSAGES, $locale);
// Set the text domain as 'messages'
$domain = 'messages';
T_bindtextdomain($domain, LOCALE_DIR);
T_bind_textdomain_codeset($domain, $encoding);
T_textdomain($domain);
header("Content-type: text/html; charset=$encoding");
?>
<html>
<head>
<title>PHP-gettext fallback example</title>
</head>
<body>
<h1>PHP-gettext as a fallback solution</h1>
<p>Example showing how to use PHP-gettext as a fallback solution if the native gettext library is not available or the system does not support the requested locale.</p>
<?php
print "<p>";
foreach ($supported_locales as $l) {
print "[<a href=\"?lang=$l\">$l</a>] ";
}
print "</p>\n";
if (!locale_emulation()) {
print "<p>locale '$locale' is supported by your system, using native gettext implementation.</p>\n";
} else {
print "<p>locale '$locale' is <strong>not</strong> supported on your system, using custom gettext implementation.</p>\n";
}
?>
<hr />
<?php
// using PHP-gettext
print "<pre>";
print T_("This is how the story goes.\n\n");
for ($number=6; $number>=0; $number--) {
print sprintf(
T_ngettext(
"%d pig went to the market\n",
"%d pigs went to the market\n",
$number
),
$number
);
}
print "</pre>\n";
?>
<hr />
<p>&laquo; <a href="./">back</a></p>
</body>
</html>

View File

@ -0,0 +1,14 @@
#!/bin/sh
TEMPLATE=pigs.pot
xgettext -kT_ngettext:1,2 -kT_ -L PHP -o $TEMPLATE pigs_dropin.php
if [ "x$1" = "x-p" ]; then
msgfmt --statistics $TEMPLATE
else
if [ -f $1.po ]; then
msgmerge -o .tmp$1.po $1.po $TEMPLATE
mv .tmp$1.po $1.po
msgfmt --statistics $1.po
else
echo "Usage: $0 [-p|<basename>]"
fi
fi

147
extlib/php-gettext/gettext.php Normal file → Executable file
View File

@ -33,22 +33,23 @@
* second parameter in the constructor (e.g. whenusing very large MO files * second parameter in the constructor (e.g. whenusing very large MO files
* that you don't want to keep in memory) * that you don't want to keep in memory)
*/ */
class gettext_reader { class gettext_reader
{
//public: //public:
var $error = 0; // public variable that holds error code (0 if no error) public $error = 0; // public variable that holds error code (0 if no error)
//private: //private:
var $BYTEORDER = 0; // 0: low endian, 1: big endian public $BYTEORDER = 0; // 0: low endian, 1: big endian
var $STREAM = NULL; public $STREAM = null;
var $short_circuit = false; public $short_circuit = false;
var $enable_cache = false; public $enable_cache = false;
var $originals = NULL; // offset of original table public $originals = null; // offset of original table
var $translations = NULL; // offset of translation table public $translations = null; // offset of translation table
var $pluralheader = NULL; // cache header field for plural forms public $pluralheader = null; // cache header field for plural forms
var $total = 0; // total string count public $total = 0; // total string count
var $table_originals = NULL; // table for original strings (offsets) public $table_originals = null; // table for original strings (offsets)
var $table_translations = NULL; // table for translated strings (offsets) public $table_translations = null; // table for translated strings (offsets)
var $cache_translations = NULL; // original -> translation mapping public $cache_translations = null; // original -> translation mapping
/* Methods */ /* Methods */
@ -60,7 +61,8 @@ class gettext_reader {
* @access private * @access private
* @return Integer from the Stream * @return Integer from the Stream
*/ */
function readint() { public function readint()
{
if ($this->BYTEORDER == 0) { if ($this->BYTEORDER == 0) {
// low endian // low endian
$input=unpack('V', $this->STREAM->read(4)); $input=unpack('V', $this->STREAM->read(4));
@ -72,7 +74,8 @@ class gettext_reader {
} }
} }
function read($bytes) { public function read($bytes)
{
return $this->STREAM->read($bytes); return $this->STREAM->read($bytes);
} }
@ -82,7 +85,8 @@ class gettext_reader {
* @param int count How many elements should be read * @param int count How many elements should be read
* @return Array of Integers * @return Array of Integers
*/ */
function readintarray($count) { public function readintarray($count)
{
if ($this->BYTEORDER == 0) { if ($this->BYTEORDER == 0) {
// low endian // low endian
return unpack('V'.$count, $this->STREAM->read(4 * $count)); return unpack('V'.$count, $this->STREAM->read(4 * $count));
@ -98,9 +102,10 @@ class gettext_reader {
* @param object Reader the StreamReader object * @param object Reader the StreamReader object
* @param boolean enable_cache Enable or disable caching of strings (default on) * @param boolean enable_cache Enable or disable caching of strings (default on)
*/ */
function gettext_reader($Reader, $enable_cache = true) { public function gettext_reader($Reader, $enable_cache = true)
{
// If there isn't a StreamReader, turn on short circuit mode. // If there isn't a StreamReader, turn on short circuit mode.
if (! $Reader || isset($Reader->error) ) { if (! $Reader || isset($Reader->error)) {
$this->short_circuit = true; $this->short_circuit = true;
return; return;
} }
@ -137,11 +142,13 @@ class gettext_reader {
* *
* @access private * @access private
*/ */
function load_tables() { public function load_tables()
{
if (is_array($this->cache_translations) && if (is_array($this->cache_translations) &&
is_array($this->table_originals) && is_array($this->table_originals) &&
is_array($this->table_translations)) is_array($this->table_translations)) {
return; return;
}
/* get original and translations tables */ /* get original and translations tables */
if (!is_array($this->table_originals)) { if (!is_array($this->table_originals)) {
@ -154,7 +161,7 @@ class gettext_reader {
} }
if ($this->enable_cache) { if ($this->enable_cache) {
$this->cache_translations = array (); $this->cache_translations = array();
/* read all strings in the cache */ /* read all strings in the cache */
for ($i = 0; $i < $this->total; $i++) { for ($i = 0; $i < $this->total; $i++) {
$this->STREAM->seekto($this->table_originals[$i * 2 + 2]); $this->STREAM->seekto($this->table_originals[$i * 2 + 2]);
@ -173,11 +180,13 @@ class gettext_reader {
* @param int num Offset number of original string * @param int num Offset number of original string
* @return string Requested string if found, otherwise '' * @return string Requested string if found, otherwise ''
*/ */
function get_original_string($num) { public function get_original_string($num)
{
$length = $this->table_originals[$num * 2 + 1]; $length = $this->table_originals[$num * 2 + 1];
$offset = $this->table_originals[$num * 2 + 2]; $offset = $this->table_originals[$num * 2 + 2];
if (! $length) if (! $length) {
return ''; return '';
}
$this->STREAM->seekto($offset); $this->STREAM->seekto($offset);
$data = $this->STREAM->read($length); $data = $this->STREAM->read($length);
return (string)$data; return (string)$data;
@ -190,11 +199,13 @@ class gettext_reader {
* @param int num Offset number of original string * @param int num Offset number of original string
* @return string Requested string if found, otherwise '' * @return string Requested string if found, otherwise ''
*/ */
function get_translation_string($num) { public function get_translation_string($num)
{
$length = $this->table_translations[$num * 2 + 1]; $length = $this->table_translations[$num * 2 + 1];
$offset = $this->table_translations[$num * 2 + 2]; $offset = $this->table_translations[$num * 2 + 2];
if (! $length) if (! $length) {
return ''; return '';
}
$this->STREAM->seekto($offset); $this->STREAM->seekto($offset);
$data = $this->STREAM->read($length); $data = $this->STREAM->read($length);
return (string)$data; return (string)$data;
@ -209,7 +220,8 @@ class gettext_reader {
* @param int end (internally used in recursive function) * @param int end (internally used in recursive function)
* @return int string number (offset in originals table) * @return int string number (offset in originals table)
*/ */
function find_string($string, $start = -1, $end = -1) { public function find_string($string, $start = -1, $end = -1)
{
if (($start == -1) or ($end == -1)) { if (($start == -1) or ($end == -1)) {
// find_string is called with only one parameter, set start end end // find_string is called with only one parameter, set start end end
$start = 0; $start = 0;
@ -218,28 +230,30 @@ class gettext_reader {
if (abs($start - $end) <= 1) { if (abs($start - $end) <= 1) {
// We're done, now we either found the string, or it doesn't exist // We're done, now we either found the string, or it doesn't exist
$txt = $this->get_original_string($start); $txt = $this->get_original_string($start);
if ($string == $txt) if ($string == $txt) {
return $start; return $start;
else } else {
return -1; return -1;
} else if ($start > $end) { }
} elseif ($start > $end) {
// start > end -> turn around and start over // start > end -> turn around and start over
return $this->find_string($string, $end, $start); return $this->find_string($string, $end, $start);
} else { } else {
// Divide table in two parts // Divide table in two parts
$half = (int)(($start + $end) / 2); $half = (int)(($start + $end) / 2);
$cmp = strcmp($string, $this->get_original_string($half)); $cmp = strcmp($string, $this->get_original_string($half));
if ($cmp == 0) if ($cmp == 0) {
// string is exactly in the middle => return it // string is exactly in the middle => return it
return $half; return $half;
else if ($cmp < 0) } elseif ($cmp < 0) {
// The string is in the upper half // The string is in the upper half
return $this->find_string($string, $start, $half); return $this->find_string($string, $start, $half);
else } else {
// The string is in the lower half // The string is in the lower half
return $this->find_string($string, $half, $end); return $this->find_string($string, $half, $end);
} }
} }
}
/** /**
* Translates a string * Translates a string
@ -248,26 +262,30 @@ class gettext_reader {
* @param string string to be translated * @param string string to be translated
* @return string translated string (or original, if not found) * @return string translated string (or original, if not found)
*/ */
function translate($string) { public function translate($string)
if ($this->short_circuit) {
if ($this->short_circuit) {
return $string; return $string;
}
$this->load_tables(); $this->load_tables();
if ($this->enable_cache) { if ($this->enable_cache) {
// Caching enabled, get translated string from cache // Caching enabled, get translated string from cache
if (array_key_exists($string, $this->cache_translations)) if (array_key_exists($string, $this->cache_translations)) {
return $this->cache_translations[$string]; return $this->cache_translations[$string];
else } else {
return $string; return $string;
}
} else { } else {
// Caching not enabled, try to find string // Caching not enabled, try to find string
$num = $this->find_string($string); $num = $this->find_string($string);
if ($num == -1) if ($num == -1) {
return $string; return $string;
else } else {
return $this->get_translation_string($num); return $this->get_translation_string($num);
} }
} }
}
/** /**
* Sanitize plural form expression for use in PHP eval call. * Sanitize plural form expression for use in PHP eval call.
@ -275,7 +293,8 @@ class gettext_reader {
* @access private * @access private
* @return string sanitized plural form expression * @return string sanitized plural form expression
*/ */
function sanitize_plural_expression($expr) { public function sanitize_plural_expression($expr)
{
// Get rid of disallowed characters. // Get rid of disallowed characters.
$expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr); $expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr);
@ -294,7 +313,7 @@ class gettext_reader {
$res .= ') : ('; $res .= ') : (';
break; break;
case ';': case ';':
$res .= str_repeat( ')', $p) . ';'; $res .= str_repeat(')', $p) . ';';
$p = 0; $p = 0;
break; break;
default: default:
@ -310,11 +329,13 @@ class gettext_reader {
* @access private * @access private
* @return string verbatim plural form header field * @return string verbatim plural form header field
*/ */
function extract_plural_forms_header_from_po_header($header) { public function extract_plural_forms_header_from_po_header($header)
if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs)) {
if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs)) {
$expr = $regs[2]; $expr = $regs[2];
else } else {
$expr = "nplurals=2; plural=n == 1 ? 0 : 1;"; $expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
}
return $expr; return $expr;
} }
@ -324,7 +345,8 @@ class gettext_reader {
* @access private * @access private
* @return string plural form header * @return string plural form header
*/ */
function get_plural_forms() { public function get_plural_forms()
{
// lets assume message number 0 is header // lets assume message number 0 is header
// this is true, right? // this is true, right?
$this->load_tables(); $this->load_tables();
@ -349,21 +371,25 @@ class gettext_reader {
* @param n count * @param n count
* @return int array index of the right plural form * @return int array index of the right plural form
*/ */
function select_string($n) { public function select_string($n)
{
if (!is_int($n)) { if (!is_int($n)) {
throw new InvalidArgumentException( throw new InvalidArgumentException(
"Select_string only accepts integers: " . $n); "Select_string only accepts integers: " . $n
);
} }
$string = $this->get_plural_forms(); $string = $this->get_plural_forms();
$string = str_replace('nplurals',"\$total",$string); $string = str_replace('nplurals', "\$total", $string);
$string = str_replace("n",$n,$string); $string = str_replace("n", $n, $string);
$string = str_replace('plural',"\$plural",$string); $string = str_replace('plural', "\$plural", $string);
$total = 0; $total = 0;
$plural = 0; $plural = 0;
eval("$string"); eval("$string");
if ($plural >= $total) $plural = $total - 1; if ($plural >= $total) {
$plural = $total - 1;
}
return $plural; return $plural;
} }
@ -376,13 +402,15 @@ class gettext_reader {
* @param string number * @param string number
* @return translated plural form * @return translated plural form
*/ */
function ngettext($single, $plural, $number) { public function ngettext($single, $plural, $number)
{
if ($this->short_circuit) { if ($this->short_circuit) {
if ($number != 1) if ($number != 1) {
return $plural; return $plural;
else } else {
return $single; return $single;
} }
}
// find out the appropriate form // find out the appropriate form
$select = $this->select_string($number); $select = $this->select_string($number);
@ -411,26 +439,25 @@ class gettext_reader {
} }
} }
function pgettext($context, $msgid) { public function pgettext($context, $msgid)
{
$key = $context . chr(4) . $msgid; $key = $context . chr(4) . $msgid;
$ret = $this->translate($key); $ret = $this->translate($key);
if (strpos($ret, "\004") !== FALSE) { if (strpos($ret, "\004") !== false) {
return $msgid; return $msgid;
} else { } else {
return $ret; return $ret;
} }
} }
function npgettext($context, $singular, $plural, $number) { public function npgettext($context, $singular, $plural, $number)
{
$key = $context . chr(4) . $singular; $key = $context . chr(4) . $singular;
$ret = $this->ngettext($key, $plural, $number); $ret = $this->ngettext($key, $plural, $number);
if (strpos($ret, "\004") !== FALSE) { if (strpos($ret, "\004") !== false) {
return $singular; return $singular;
} else { } else {
return $ret; return $ret;
} }
} }
} }
?>

View File

@ -23,75 +23,88 @@
// Simple class to wrap file streams, string streams, etc. // Simple class to wrap file streams, string streams, etc.
// seek is essential, and it should be byte stream // seek is essential, and it should be byte stream
class StreamReader { class StreamReader
{
// should return a string [FIXME: perhaps return array of bytes?] // should return a string [FIXME: perhaps return array of bytes?]
function read($bytes) { public function read($bytes)
{
return false; return false;
} }
// should return new position // should return new position
function seekto($position) { public function seekto($position)
{
return false; return false;
} }
// returns current position // returns current position
function currentpos() { public function currentpos()
{
return false; return false;
} }
// returns length of entire stream (limit for seekto()s) // returns length of entire stream (limit for seekto()s)
function length() { public function length()
{
return false; return false;
} }
}; };
class StringReader { class StringReader
var $_pos; {
var $_str; public $_pos;
public $_str;
function StringReader($str='') { public function StringReader($str='')
{
$this->_str = $str; $this->_str = $str;
$this->_pos = 0; $this->_pos = 0;
} }
function read($bytes) { public function read($bytes)
{
$data = substr($this->_str, $this->_pos, $bytes); $data = substr($this->_str, $this->_pos, $bytes);
$this->_pos += $bytes; $this->_pos += $bytes;
if (strlen($this->_str)<$this->_pos) if (strlen($this->_str)<$this->_pos) {
$this->_pos = strlen($this->_str); $this->_pos = strlen($this->_str);
}
return $data; return $data;
} }
function seekto($pos) { public function seekto($pos)
{
$this->_pos = $pos; $this->_pos = $pos;
if (strlen($this->_str)<$this->_pos) if (strlen($this->_str)<$this->_pos) {
$this->_pos = strlen($this->_str); $this->_pos = strlen($this->_str);
}
return $this->_pos; return $this->_pos;
} }
function currentpos() { public function currentpos()
{
return $this->_pos; return $this->_pos;
} }
function length() { public function length()
{
return strlen($this->_str); return strlen($this->_str);
} }
}; };
class FileReader { class FileReader
var $_pos; {
var $_fd; public $_pos;
var $_length; public $_fd;
public $_length;
function FileReader($filename) { public function FileReader($filename)
{
if (file_exists($filename)) { if (file_exists($filename)) {
$this->_length=filesize($filename); $this->_length=filesize($filename);
$this->_pos = 0; $this->_pos = 0;
$this->_fd = fopen($filename,'rb'); $this->_fd = fopen($filename, 'rb');
if (!$this->_fd) { if (!$this->_fd) {
$this->error = 3; // Cannot read file, probably permissions $this->error = 3; // Cannot read file, probably permissions
return false; return false;
@ -102,7 +115,8 @@ class FileReader {
} }
} }
function read($bytes) { public function read($bytes)
{
if ($bytes) { if ($bytes) {
fseek($this->_fd, $this->_pos); fseek($this->_fd, $this->_pos);
@ -117,37 +131,43 @@ class FileReader {
$this->_pos = ftell($this->_fd); $this->_pos = ftell($this->_fd);
return $data; return $data;
} else return ''; } else {
return '';
}
} }
function seekto($pos) { public function seekto($pos)
{
fseek($this->_fd, $pos); fseek($this->_fd, $pos);
$this->_pos = ftell($this->_fd); $this->_pos = ftell($this->_fd);
return $this->_pos; return $this->_pos;
} }
function currentpos() { public function currentpos()
{
return $this->_pos; return $this->_pos;
} }
function length() { public function length()
{
return $this->_length; return $this->_length;
} }
function close() { public function close()
{
fclose($this->_fd); fclose($this->_fd);
} }
}; };
// Preloads entire file in memory first, then creates a StringReader // Preloads entire file in memory first, then creates a StringReader
// over it (it assumes knowledge of StringReader internals) // over it (it assumes knowledge of StringReader internals)
class CachedFileReader extends StringReader { class CachedFileReader extends StringReader
function CachedFileReader($filename) { {
public function CachedFileReader($filename)
{
if (file_exists($filename)) { if (file_exists($filename)) {
$length=filesize($filename); $length=filesize($filename);
$fd = fopen($filename,'rb'); $fd = fopen($filename, 'rb');
if (!$fd) { if (!$fd) {
$this->error = 3; // Cannot read file, probably permissions $this->error = 3; // Cannot read file, probably permissions
@ -155,13 +175,9 @@ class CachedFileReader extends StringReader {
} }
$this->_str = fread($fd, $length); $this->_str = fread($fd, $length);
fclose($fd); fclose($fd);
} else { } else {
$this->error = 2; // File doesn't exist $this->error = 2; // File doesn't exist
return false; return false;
} }
} }
}; };
?>

View File

@ -0,0 +1,88 @@
<?php
require_once('gettext.inc');
class LocaleTest extends PHPUnit_Framework_TestCase
{
public function test_setlocale()
{
putenv("LC_ALL=");
// _setlocale defaults to a locale name from environment variable LANG.
putenv("LANG=sr_RS");
$this->assertEquals('sr_RS', _setlocale(LC_MESSAGES, 0));
}
public function test_setlocale_system()
{
putenv("LC_ALL=");
// For an existing locale, it never needs emulation.
putenv("LANG=C");
_setlocale(LC_MESSAGES, "");
$this->assertEquals(0, locale_emulation());
}
public function test_setlocale_emulation()
{
putenv("LC_ALL=");
// If we set it to a non-existent locale, it still works, but uses
// emulation.
_setlocale(LC_MESSAGES, "xxx_XXX");
$this->assertEquals('xxx_XXX', _setlocale(LC_MESSAGES, 0));
$this->assertEquals(1, locale_emulation());
}
public function test_get_list_of_locales()
{
// For a locale containing country code, we prefer
// full locale name, but if that's not found, fall back
// to the language only locale name.
$this->assertEquals(
array("sr_RS", "sr"),
get_list_of_locales("sr_RS")
);
// If language code is used, it's the only thing returned.
$this->assertEquals(
array("sr"),
get_list_of_locales("sr")
);
// There is support for language and charset only.
$this->assertEquals(
array("sr.UTF-8", "sr"),
get_list_of_locales("sr.UTF-8")
);
// It can also split out character set from the full locale name.
$this->assertEquals(
array("sr_RS.UTF-8", "sr_RS", "sr"),
get_list_of_locales("sr_RS.UTF-8")
);
// There is support for @modifier in locale names as well.
$this->assertEquals(
array("sr_RS.UTF-8@latin", "sr_RS@latin", "sr@latin",
"sr_RS.UTF-8", "sr_RS", "sr"),
get_list_of_locales("sr_RS.UTF-8@latin")
);
// We can pass in only language and modifier.
$this->assertEquals(
array("sr@latin", "sr"),
get_list_of_locales("sr@latin")
);
// If locale name is not following the regular POSIX pattern,
// it's used verbatim.
$this->assertEquals(
array("something"),
get_list_of_locales("something")
);
// Passing in an empty string returns an empty array.
$this->assertEquals(
array(),
get_list_of_locales("")
);
}
}

View File

@ -0,0 +1,97 @@
<?php
class ParsingTest extends PHPUnit_Framework_TestCase
{
public function test_extract_plural_forms_header_from_po_header()
{
$parser = new gettext_reader(null);
// It defaults to a "Western-style" plural header.
$this->assertEquals(
'nplurals=2; plural=n == 1 ? 0 : 1;',
$parser->extract_plural_forms_header_from_po_header("")
);
// Extracting it from the middle of the header works.
$this->assertEquals(
'nplurals=1; plural=0;',
$parser->extract_plural_forms_header_from_po_header(
"Content-type: text/html; charset=UTF-8\n"
."Plural-Forms: nplurals=1; plural=0;\n"
."Last-Translator: nobody\n"
)
);
// It's also case-insensitive.
$this->assertEquals(
'nplurals=1; plural=0;',
$parser->extract_plural_forms_header_from_po_header(
"PLURAL-forms: nplurals=1; plural=0;\n"
)
);
// It falls back to default if it's not on a separate line.
$this->assertEquals(
'nplurals=2; plural=n == 1 ? 0 : 1;',
$parser->extract_plural_forms_header_from_po_header(
"Content-type: text/html; charset=UTF-8" // note the missing \n here
."Plural-Forms: nplurals=1; plural=0;\n"
."Last-Translator: nobody\n"
)
);
}
/**
* @expectedException InvalidArgumentException
*/
public function test_select_string_disallows_nonint_numbers()
{
$pofile_data = ''
."msgid \"\"\n"
."msgstr \"\"\n"
."\"Content-Type: text/plain; charset=utf-8\\n\"\n"
."\"Plural-Forms: nplurals=2; plural= n == 1 ? 0 : 1;\\n\"\n";
$mofile = tempnam(sys_get_temp_dir(), "pg");
$msgfmt = popen("msgfmt -o $mofile -", "w");
fwrite($msgfmt, $pofile_data);
pclose($msgfmt);
$modata = new CachedFileReader($mofile);
unlink($mofile);
$parser = new gettext_reader($modata);
// It defaults to a "Western-style" plural header.
$this->assertEquals(
'nplurals=2; plural=n == 1 ? 0 : 1;',
$parser->extract_plural_forms_header_from_po_header("")
);
$new_tempfile = tempnam(sys_get_temp_dir(), "pg");
$parser->select_string(
"(file_put_contents('$new_tempfile', 'boom'))"
);
$this->assertEquals("", file_get_contents($new_tempfile));
unlink($new_tempfile);
}
/**
* @dataProvider data_provider_test_npgettext
*/
public function test_npgettext($number, $expected)
{
$parser = new gettext_reader(null);
$result = $parser->npgettext(
"context",
"%d pig went to the market\n",
"%d pigs went to the market\n",
$number
);
$this->assertSame($expected, $result);
}
public static function data_provider_test_npgettext()
{
return array(
array(1, "%d pig went to the market\n"),
array(2, "%d pigs went to the market\n"),
);
}
}