mirror of
https://github.com/Yetangitu/ampache
synced 2025-10-05 02:39:47 +02:00
391 lines
No EOL
12 KiB
PHP
391 lines
No EOL
12 KiB
PHP
<?php
|
|
/*
|
|
api: PHP
|
|
type: functions
|
|
title: gettext()
|
|
description: emulates PHP gettext extension functionality
|
|
priority: auto
|
|
category: library
|
|
|
|
This include script simulates gettext() functionality.
|
|
- It could read translation data from .mo and .po files.
|
|
- Lookup of plural forms mostly work (but not 100% compliant,
|
|
no real interpreter for Plural-Forms: expression).
|
|
- Categories/codesets are ignored.
|
|
|
|
Besides using setlocale() you should change the $_ENV["LANG"] var
|
|
to the desired language manually. Additionally all your scripts
|
|
could contain following (may also work with standard gettext):
|
|
$_ENV["LANGUAGE"] = $_SERVER["HTTP_ACCEPT_LANGUAGE"];
|
|
That's often more user-friendly than hardwired server-side values.
|
|
*/
|
|
|
|
|
|
#-- emulate only if not present in current PHP interpreter
|
|
if (!function_exists("gettext")) {
|
|
|
|
#-- all-in-one combined implementation
|
|
# (in original API only the first parameter is present)
|
|
function gettext($msg, $msg2=NULL, $domain=NULL, $category=NULL, $plural=NULL) {
|
|
global $_GETTEXT;
|
|
|
|
#-- get default params if corresponding args are empty
|
|
if (!isset($domain)) {
|
|
$domain = $_GETTEXT['%domain'];
|
|
}
|
|
if (empty($_GETTEXT[$domain])) {
|
|
bindtextdomain($domain); // auto load from system dirs
|
|
}
|
|
|
|
#-- plural array position
|
|
if (!isset($plural)) {
|
|
$pli = 0;
|
|
}
|
|
elseif ($ph = $_GETTEXT[$domain]['%plural-c']) {
|
|
$pli = gettext___plural_guess($ph, $plural);
|
|
}
|
|
else {
|
|
$pli = ($plural != 1) ? 1 : 0; // English
|
|
}
|
|
|
|
#-- look up string
|
|
if (isset($_GETTEXT[$domain][$msg]) && ($trans = $_GETTEXT[$domain][$msg])
|
|
or ($pli) and ($trans = $_GETTEXT[$domain][$msg2]))
|
|
{
|
|
// handle plural entries
|
|
if (is_array($trans)) {
|
|
if (!isset($trans[$pli])) {
|
|
$pli = 0; // missing translation
|
|
}
|
|
$trans = $trans[$pli];
|
|
}
|
|
// only return, if something found
|
|
if (strlen($trans)) {
|
|
$msg = $trans;
|
|
}
|
|
}
|
|
|
|
#-- handle $category (???)
|
|
// recode() ...
|
|
|
|
#-- give out whatever we have
|
|
return($msg);
|
|
}
|
|
|
|
|
|
#-- return plural form array index for algorithm type
|
|
# (compacted from C expression string beforehand)
|
|
function gettext___plural_guess(&$type, $n) {
|
|
|
|
#-- guess from string with C expression and set integer shorthand
|
|
if (is_string($type)) {
|
|
if (($type == "nplurals=1;plural=0;") || !strlen($type)) {
|
|
$type = -1; // no plurals
|
|
}
|
|
elseif ($type == "nplurals=2;plural=n!=1;") {
|
|
$type = 1; // English
|
|
}
|
|
elseif ($type == "nplurals=2;plural=n>1;") {
|
|
$type = 2; // French
|
|
}
|
|
// special cases
|
|
elseif (strpos($type, "n%100!=11")) {
|
|
if (strpos($type, "n!=0")) {
|
|
$type == 21; // Latvian
|
|
}
|
|
if (strpos($type, "n%10<=4")) {
|
|
$type = 22; // a few Slavic langs (code similar to Polish below)
|
|
}
|
|
if (strpos($type, "n%10>=2")) { // Lithuanian
|
|
$type = 23;
|
|
}
|
|
$type = 0;
|
|
}
|
|
// specials, group 2
|
|
elseif (strpos($type, "n<=4")) { // Slovak
|
|
$type = 25;
|
|
}
|
|
elseif (strpos($type, "n==2")) { // Irish
|
|
$type = 31;
|
|
}
|
|
elseif (strpos($type, "n%10>=2")) { // Polish
|
|
$type = 26;
|
|
}
|
|
elseif (strpos($type, "n%100==3")) { // Slovenian
|
|
$type = 28;
|
|
}
|
|
// fallbacks
|
|
elseif (strpos($type, ";plural=n;")) {
|
|
$type = 7; // unused
|
|
}
|
|
// first at this point a tokenizer/parser/interpreter would have made sense
|
|
else {
|
|
$type = 0; // no plurals
|
|
}
|
|
}
|
|
|
|
#-- return plural index value from pre-set formulas
|
|
switch ($type) {
|
|
case -1: // no plural forms
|
|
return(0);
|
|
case 1: // English, and lots of others...
|
|
return($n != 1 ? 1 : 0);
|
|
case 2: // French, Brazilian Protuguese
|
|
return($n > 1 ? 1 : 0);
|
|
case 7: // unused
|
|
return($n);
|
|
|
|
case 21: // Latvian
|
|
return (($n%10==1) && ($n%100!=11)) ? (0) : ($n!=0 ? 1 : 2) ;
|
|
case 22: // Slavic langs
|
|
return ($n%10==1) && ($n%100!=11) ? 0 :
|
|
( ($n%10>=2) && ($n%10<=4) && ($n%100<10 || $n%100>=20) ? 1 : 2 ) ;
|
|
case 23: // Lithuanian
|
|
return ($n%10==1) && ($n%100!=11) ? 0 :
|
|
( ($n%10>=2) && ($n%100<10 || $n%100>=20) ? 1 : 2 ) ;
|
|
case 25: // Slovak
|
|
return $n==1 ? 0 : ($n>=2 && $n<=4 ? 1 : 2) ;
|
|
case 26: // Polish
|
|
return $n==1 ? 0 : ( $n%10>=2 && $n%10<=4 && ($n%100<10 || $n%100>=20) ? 1 : 2 ) ;
|
|
case 28: // Slovenian
|
|
return $n%100==1 ? 0 : ($n%100==2 || $n%100==3 || $n%100==4 ? 2 : 3) ;
|
|
case 31: // Irish
|
|
return ($n == 1) ? (0) : (($n == 2) ? 1 : 2) ;
|
|
|
|
default:
|
|
$type = -1;
|
|
} // unsupported, always return non-plural index [0]
|
|
return(0);
|
|
}
|
|
|
|
|
|
#-- wrappers around monster function above
|
|
function ngettext($msg1, $msg2, $plural) {
|
|
return gettext($msg1, $msg2, NULL, NULL, $plural);
|
|
}
|
|
function dngettext($domain, $msg1, $msg2, $plural) {
|
|
return gettext($msg1, $msg2, $domain, NULL, $plural);
|
|
}
|
|
function dcngettext($domain, $msg1, $msg2, $plural, $category) {
|
|
return gettext($msg1, $msg2, $domain, $category, $plural);
|
|
}
|
|
function dcgettext($domain, $msg, $category) {
|
|
return gettext($msg, NULL, $domain, $category);
|
|
}
|
|
function dgettext($domain, $msg) {
|
|
return gettext($msg, NULL, $domain);
|
|
}
|
|
|
|
|
|
#-- sets current translation data source
|
|
# (must have been loaded beforehand)
|
|
function textdomain($default="NULL") {
|
|
global $_GETTEXT;
|
|
$prev = isset($_GETTEXT['%domain']) ? $_GETTEXT['%domain'] : NULL;
|
|
if (isset($default)) {
|
|
$_GETTEXT['%domain'] = $default;
|
|
}
|
|
return $prev;
|
|
}
|
|
|
|
|
|
#-- loads data files
|
|
function bindtextdomain($domain, $directory="/usr/share/locale:/usr/local/share/locale:./locale") {
|
|
global $_GETTEXT;
|
|
if (isset($_GETTEXT[$domain]) && (count($_GETTEXT[$domain]) > 3)) {
|
|
return; // don't load twice
|
|
}
|
|
$_GETTEXT[$domain]['%dir'] = $directory;
|
|
$_GETTEXT['%locale'] = setlocale(LC_CTYPE, 0);
|
|
|
|
#-- allowed languages
|
|
$langs = @$_ENV['LANGUAGE'] . ',' . @$_ENV['LC_ALL'] . ','
|
|
. @$_ENV['LC_MESSAGE'] .',' . @$_ENV['LANG'] . ','
|
|
. @$_GETTEXT['%locale'] . ',' . @$_SERVER['HTTP_ACCEPT_LANGUAGE']
|
|
. ',C,en';
|
|
|
|
#-- add shortened language codes (en_UK.UTF-8 -> + en_UK, en)
|
|
foreach (explode(',', $langs) as $d) {
|
|
$d = trim($d);
|
|
// $dir2[] = $d;
|
|
$d = strtok($d, "@.-+=%:; ");
|
|
if (strlen($d)) {
|
|
$dir2[] = $d;
|
|
}
|
|
if (strpos($d, '_')) {
|
|
$dir2[] = strtok($d, '_');
|
|
}
|
|
}
|
|
|
|
#-- search for matching directory and load data file
|
|
foreach (explode(':', $directory) as $directory) {
|
|
foreach ($dir2 as $lang) {
|
|
$base_fn = "$directory/$lang/LC_MESSAGES/$domain";
|
|
|
|
#echo "GETTEXT:$lang:$base_fn\n";
|
|
|
|
#-- binary format
|
|
if (file_exists($fn = "$base_fn.mo") && ($f = fopen($fn, "rb")))
|
|
{
|
|
gettext___load_mo($f, $domain);
|
|
break 2;
|
|
}
|
|
|
|
#-- text file
|
|
elseif (function_exists("gettext___load_po")
|
|
and file_exists($fn = "$base_fn.po") && ($f = fopen($fn, "r")))
|
|
{
|
|
gettext___load_po($f, $domain);
|
|
break 2;
|
|
}
|
|
}
|
|
}//foreach
|
|
|
|
#-- extract headers
|
|
if ($head = $_GETTEXT[$domain][""]) {
|
|
foreach (explode("\n", $head) as $line) {
|
|
$header = strtok(':', $line);
|
|
$line = trim(strtok("\n"));
|
|
$_GETTEXT[$domain]['%po-header'][strtolower($header)] = $line;
|
|
}
|
|
|
|
#-- plural-forms header
|
|
if (function_exists("gettext___plural_guess")
|
|
and ($h = @$_GETTEXT[$domain]['%po-header']["plural-forms"]))
|
|
{
|
|
$h = preg_replace("/[(){}\[\]^\s*\\]+/", "", $h); // rm whitespace
|
|
gettext___plural_guess($h, 0); // pre-decode into algorithm type integer
|
|
$_GETTEXT[$domain]['%plural-c'] = $h;
|
|
}
|
|
}
|
|
|
|
#-- set as default textdomain
|
|
if (empty($_GETTEXT['%domain'])) {
|
|
textdomain($domain);
|
|
}
|
|
return($domain);
|
|
}
|
|
|
|
|
|
#-- load string data from binary .mo files (ign checksums)
|
|
function gettext___load_mo($f, $domain) {
|
|
global $_GETTEXT;
|
|
|
|
#-- read in data file completely
|
|
$data = fread($f, 1<<20);
|
|
fclose($f);
|
|
|
|
#-- extract header fields and check file magic
|
|
if ($data) {
|
|
$header = substr($data, 0, 20);
|
|
$header = unpack("L1magic/L1version/L1count/L1o_msg/L1o_trn", $header);
|
|
extract($header);
|
|
if ((dechex($magic) == "950412de") && ($version == 0)) {
|
|
|
|
#-- fetch all entries
|
|
for ($n=0; $n<$count; $n++) {
|
|
|
|
#-- msgid
|
|
$r = unpack("L1len/L1offs", substr($data, $o_msg + $n * 8, 8));
|
|
$msgid = substr($data, $r["offs"], $r["len"]);
|
|
unset($msgid_plural);
|
|
if (strpos($msgid, "\000")) {
|
|
list($msgid, $msgid_plural) = explode("\000", $msgid);
|
|
}
|
|
|
|
#-- translation(s)
|
|
$r = unpack("L1len/L1offs", substr($data, $o_trn + $n * 8, 8));
|
|
$msgstr = substr($data, $r["offs"], $r["len"]);
|
|
if (strpos($msgstr, "\000")) {
|
|
$msgstr = explode("\000", $msgstr);
|
|
}
|
|
|
|
#-- add
|
|
$_GETTEXT[$domain][$msgid] = $msgstr;
|
|
if (isset($msgid_plural)) {
|
|
$_GETTEXT[$domain][$msgid_plural] = &$_GETTEXT[$domain][$msgid];
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#-- read from textual .po source file (not fully correct, and redundant
|
|
# because the original gettext/libintl doesn't support this at all)
|
|
function gettext___load_po($f, $domain) {
|
|
global $_GETTEXT;
|
|
$c_esc = array("\\n"=>"\n", "\\r"=>"\r", "\\\\"=>"\\", "\\f"=>"\f", "\\t"=>"\t", "\\"=>"");
|
|
|
|
#-- read line-wise from text file
|
|
do {
|
|
$line = trim(fgets($f));
|
|
|
|
#-- check what's in the current line
|
|
$space = strpos($line, " ");
|
|
// comment
|
|
if ($line[0] == "#") {
|
|
//continue;
|
|
}
|
|
// msgid
|
|
elseif (strncmp($line, "msgid", 5)==0) {
|
|
$msgid[] = trim(substr($line, $space+1), '"');
|
|
}
|
|
// translation
|
|
elseif (strncmp($line, "msgstr", 6)==0) {
|
|
$msgstr[] = trim(substr($line, $space+1), '"');
|
|
}
|
|
// continued (could be _id or _str)
|
|
elseif ($line[0] == '"') {
|
|
$line = trim($line, '"');
|
|
if (isset($msggstr)) {
|
|
$msgstr[count($msgstr)] .= $line;
|
|
}
|
|
else {
|
|
$msgid[count($msgid)] .= $line;
|
|
}
|
|
}
|
|
|
|
#-- append to global $_GETTEXT hash as soon as we have a complete dataset
|
|
if (isset($msgid) && isset($msgstr) && (empty($line) || ($line[0]=="#") || feof($f)) )
|
|
{
|
|
$msgid[0] = strtr($msgid[0], $c_esc);
|
|
foreach ($msgstr as $v) {
|
|
$_GETTEXT[$domain][$msgid[0]] = strtr($v, $c_esc);
|
|
}
|
|
if ($msgid[1]) {
|
|
$msgid[1] = strtr($msgid[1], $c_esc);
|
|
$_GETTEXT[$domain][$msgid[1]] = &$_GETTEXT[$domain][$msgid[0]];
|
|
}
|
|
|
|
$msgid = array();
|
|
$msgstr = array();
|
|
}
|
|
|
|
} while (!feof($f));
|
|
fclose($f);
|
|
}
|
|
|
|
|
|
#-- ignored setting (no idea what it really should do)
|
|
function bind_textdomain_codeset($domain, $codeset) {
|
|
global $_GETTEXT;
|
|
$_GETTEXT[$domain]["%codeset"] = $codeset;
|
|
return($domain);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#-- define gettexts preferred function name _ separately
|
|
if (!function_exists("_")) {
|
|
function _($str) {
|
|
return gettext($str);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
?>
|