如何在PHP中根据性别和计数翻译字符串?
我正在使用一个集中的语言系统开发多语言应用程序。它基于每种语言的语言文件和一个简单的辅助函数: en.php如何在PHP中根据性别和计数翻译字符串?,php,preg-replace,multilingual,Php,Preg Replace,Multilingual,我正在使用一个集中的语言系统开发多语言应用程序。它基于每种语言的语言文件和一个简单的辅助函数: en.php $lang['access_denied'] = "Access denied."; $lang['action-required'] = "You need to choose an action."; ... return $lang; language_helper.php ... function __($line) { return $lang[$line]; } 到目
$lang['access_denied'] = "Access denied.";
$lang['action-required'] = "You need to choose an action.";
...
return $lang;
language_helper.php
...
function __($line) {
return $lang[$line];
}
到目前为止,所有字符串都是发送给当前用户的系统消息,因此我总是可以这样做。现在,我需要创建其他消息,其中字符串应该依赖于动态值。例如,在模板文件中,我要回显动作点的数量。如果用户只有1分,则应回显“您有1分。”;但如果分数为零或超过1分,则应为“你得了12分。”
出于替换目的(字符串和数字),我创建了一个新函数
function __s($line, $subs = array()) {
$text = $lang[$line];
while (count($subs) > 0) {
$text = preg_replace('/%s/', array_shift($subs), $text, 1);
}
return $text;
}
对函数的调用类似于\u s('current_points',array($points))
$lang['current_points']
在这种情况下将是“您有%s个点。”
,这很有效
更进一步,我想去掉“(s)”部分。所以我创建了另一个函数
function __c($line, $subs = array()) {
$text = $lang[$line];
$text = (isset($sub[0] && $sub[0] == 1) ? $text[0] : $text[1];
while (count($subs) > 0) {
$text = preg_replace('/%d/', array_shift($subs), $text, 1);
}
return $text;
}
对函数的调用看起来仍然像\uu s('current_points',array($points))
$lang['current_points']
现在是数组(“您有%d个点。”,“您有%d个点。”)
现在我将如何组合这两个功能。例如,如果我想打印用户名和分数(如排名)。函数调用类似于\uux('current_upoints',array($username,$points))
,其中$lang['current_upoints']
是数组($s有%d个点,“%s有%d个点)。
我尝试使用preg\u replace\u callback()
,但是我在将替换值传递给该回调函数时遇到了问题
$text = preg_replace_callback('/%([sd])/',
create_function(
'$type',
'switch($type) {
case "s": return array_shift($subs); break;
case "d": return array_shift($subs); break;
}'),
$text);
显然,$subs并没有被定义为“内存不足”错误,就好像函数没有离开while循环一样
谁能给我指一下正确的方向吗?可能有一种完全不同(更好)的方法来解决这个问题。另外,我还想这样扩展它:
$lang['invite_party']=%u邀请您参加$g派对。“
应该变成亚当邀请你参加他的派对。“
对于男性和”贝蒂邀请你参加她的派对。“
适用于女性。为$u
和$g
传递的$subs
值都将是一个用户对象。如果之前做过类似的事情,但通过分离关注点避免了所有陷阱
在较低的级别上,我在模板中注入了一个格式化程序,负责处理特定于语言的所有内容。设置数字或日期等格式。它有一个带有三个参数的“复数”函数:$value、$singular、$plural,并根据返回的值选择后两个参数中的一个。它没有回显值本身,因为这是留给数字格式化的
整个翻译是在模板引擎中完成的。它是Dwoo,可以进行模板继承,所以我设置了一个主模板,其中包含所有HTML结构和大量占位符。每种语言都继承了此HTML母版,并用正确的语言输出替换了所有占位符。但由于我们仍处于模板引擎领域,所以有可能“翻译”格式化程序函数的用法。Dwoo将在第一次调用时编译模板继承,包括对格式化程序的所有后续调用,包括所有转换的参数
性别问题将得到基本相同的解决方案:性别($sex,$male,$female),其中$sex是主题的性别,其他参数是男性或女性的措辞。如果之前做过类似的事情,但通过分离关注点避免了所有陷阱 在较低的级别上,我在模板中注入了一个格式化程序,负责处理特定于语言的所有内容。设置数字或日期等格式。它有一个带有三个参数的“复数”函数:$value、$singular、$plural,并根据返回的值选择后两个参数中的一个。它没有回显值本身,因为这是留给数字格式化的 整个翻译是在模板引擎中完成的。它是Dwoo,可以进行模板继承,所以我设置了一个主模板,其中包含所有HTML结构和大量占位符。每种语言都继承了此HTML母版,并用正确的语言输出替换了所有占位符。但由于我们仍处于模板引擎领域,所以有可能“翻译”格式化程序函数的用法。Dwoo将在第一次调用时编译模板继承,包括对格式化程序的所有后续调用,包括所有转换的参数
性别问题将得到基本相同的解决方案:性别($sex,$male,$femal),其中$sex是主题的性别,其他参数是男性或女性措辞。也许更好的方法是Drupal中函数t使用的方法,请看:
也许更好的方法是Drupal中的函数t使用的方法,请看:
正如评论中提到的,我想这是另一种选择 但是,如果您需要另一种方法,这里有一个变通方法
class ll
{
private $lang = array(),
$langFuncs = array(),
$langFlags = array();
function __construct()
{
$this->lang['access'] = 'Access denied';
$this->lang['points'] = 'You have %s point{{s|}}';
$this->lang['party'] = 'A %s invited you to {{his|her}} parteh !';
$this->lang['toto'] = 'This glass seems %s, {{no one drank in already|someone came here !}}';
$this->langFuncs['count'] = function($in) { return ($in>1)?true:false; };
$this->langFuncs['gender'] = function($in) { return (strtolower($in)=='male')?true:false; };
$this->langFuncs['emptfull'] = function($in) { return ($in=='empty')?true:false; };
$this->langFlags['points'] = 'count';
$this->langFlags['toto'] = 'emptfull';
$this->langFlags['party'] = 'gender';
}
public function __($type,$param=null)
{
if (isset($this->langFlags[$type])) {
$f = $this->lang[$type];
preg_match("/{{(.*?)}}/",$f,$m);
list ($ifTrue,$ifFalse) = explode("|",$m[1]);
if($this->langFuncs[$this->langFlags[$type]]($param)) {
return $this->__s(preg_replace("/{{(.*?)}}/",$ifTrue,$this->lang[$type]),$param);
} else {
return $this->__s(preg_replace("/{{(.*?)}}/",$ifFalse,$this->lang[$type]),$param);
}
} else {
return $this->__s($this->lang[$type],$param);
}
}
private function __s($s,$i=null)
{
return str_replace("%s",$i,$s);
}
}
$ll = new ll();
echo "Call : access - NULL\n";
echo $ll->__('access'),"\n\n";
echo "Call : points - 1\n";
echo $ll->__('points',1),"\n\n";
echo "Call : points - 175\n";
echo $ll->__('points',175),"\n\n";
echo "Call : party - Male\n";
echo $ll->__('party','Male'),"\n\n";
echo "Call : party - Female\n";
echo $ll->__('party','Female'),"\n\n";
echo "Call : toto - empty\n";
echo $ll->__('toto','empty'),"\n\n";
echo "Call : toto - full\n";
echo $ll->__('toto','full');
这个输出
Call : access - NULL
Access denied
Call : points - 1
You have 1 point
Call : points - 175
You have 175 points
Call : party - Male
A Male invited you to his parteh !
Call : party - Female
A Female invited you to her parteh !
Call : toto - empty
This glass seems empty, no one drank in already
Call : toto - full
This glass seems full, someone came here !
这可能会让您了解如何集中您的语言可能性,创建自己的函数来解析一个或另一个文本
希望这对您有所帮助。正如评论中提到的,我想这是另一种选择 但是,如果您需要另一种方法,这里有一个变通方法
class ll
{
private $lang = array(),
$langFuncs = array(),
$langFlags = array();
function __construct()
{
$this->lang['access'] = 'Access denied';
$this->lang['points'] = 'You have %s point{{s|}}';
$this->lang['party'] = 'A %s invited you to {{his|her}} parteh !';
$this->lang['toto'] = 'This glass seems %s, {{no one drank in already|someone came here !}}';
$this->langFuncs['count'] = function($in) { return ($in>1)?true:false; };
$this->langFuncs['gender'] = function($in) { return (strtolower($in)=='male')?true:false; };
$this->langFuncs['emptfull'] = function($in) { return ($in=='empty')?true:false; };
$this->langFlags['points'] = 'count';
$this->langFlags['toto'] = 'emptfull';
$this->langFlags['party'] = 'gender';
}
public function __($type,$param=null)
{
if (isset($this->langFlags[$type])) {
$f = $this->lang[$type];
preg_match("/{{(.*?)}}/",$f,$m);
list ($ifTrue,$ifFalse) = explode("|",$m[1]);
if($this->langFuncs[$this->langFlags[$type]]($param)) {
return $this->__s(preg_replace("/{{(.*?)}}/",$ifTrue,$this->lang[$type]),$param);
} else {
return $this->__s(preg_replace("/{{(.*?)}}/",$ifFalse,$this->lang[$type]),$param);
}
} else {
return $this->__s($this->lang[$type],$param);
}
}
private function __s($s,$i=null)
{
return str_replace("%s",$i,$s);
}
}
$ll = new ll();
echo "Call : access - NULL\n";
echo $ll->__('access'),"\n\n";
echo "Call : points - 1\n";
echo $ll->__('points',1),"\n\n";
echo "Call : points - 175\n";
echo $ll->__('points',175),"\n\n";
echo "Call : party - Male\n";
echo $ll->__('party','Male'),"\n\n";
echo "Call : party - Female\n";
echo $ll->__('party','Female'),"\n\n";
echo "Call : toto - empty\n";
echo $ll->__('toto','empty'),"\n\n";
echo "Call : toto - full\n";
echo $ll->__('toto','full');
这个输出
Call : access - NULL
Access denied
Call : points - 1
You have 1 point
Call : points - 175
You have 175 points
Call : party - Male
A Male invited you to his parteh !
Call : party - Female
A Female invited you to her parteh !
Call : toto - empty
This glass seems empty, no one drank in already
Call : toto - full
This glass seems full, someone came here !
这可能会让您了解如何集中您的语言可能性,创建自己的函数来解析一个或另一个文本
希望这对您有所帮助。您正在重新发明车轮。你看过
gettext
扩展了吗?你正在重新发明轮子。你看过gettext
扩展了吗?哇,谢谢你,我来看看。我真的