我正在学习PHP(不断),我前段时间创建了一个处理翻译的课程。我想emulate gettext但是从数据库中获取翻译的字符串。但是,现在我再次看到它,我不喜欢它,作为一个类,称之为我需要使用$Translate->text('String_keyword');
。我不想要使用$T->a('String_keyword');
,因为这完全不直观。
我一直在考虑如何使用简单的_('String_keyword')
gettext样式调用它,但是从我从SO中学到的东西,我还没有找到'实现这一目标的绝佳方式。我需要以某种方式将默认语言传递给函数,我不想在每次调用它时传递它,因为它将是_('String_keyword', $User->get('Language'))
)。我也不想在_()
函数中包含用户检测脚本,因为它只需要运行一次而不是每次都运行。
最简单的方法是使用GLOBALS,但我在这里已经知道它们完全被禁止了(这可能是can use them?}的唯一情况,然后我想DEFINE一个使用用户语言的变量,如define ( USER_LANGUAGE , $User->get('Language') )
,但它似乎与全局相同。这些是我可以看到的两个主要选项,我知道还有其他一些方法,比如依赖注入,但它们似乎为一个如此简单的请求添加了太多的复杂性,我还没有时间深入研究它们。
我正在考虑首先创建一个包装器来测试它。像这样:
function _($Id, $Arg = null)
{
$Translate = new Translate (USER_LANGUAGE);
return $Translate -> text($Id, $Arg)
}
这是翻译代码。在创建之前检测语言并将其传递给对象。
// Translate text strings
// TO DO: SHOULD, SHOULD change it to PDO! Also, merge the 2 tables into 1
class Translate
{
private $Lang;
function __construct ($Lang)
{
$this->Lang = $Lang;
}
// Clever. Adds the translation so when codding I don't get annoyed.
private function add ($Id, $Text)
{
$sql="INSERT INTO htranslations (keyword, en, page, last) VALUES ('$Id', '$Text', '".$_SERVER['PHP_SELF']."', now())";
mysql_query($sql);
}
private function retrieve ( $Id )
{
$table = is_int ($Id) ? "translations" : "htranslations"; // A small tweak to support the two tables, but they should be merged.
$results = mysql_query ("SELECT ".mysql_real_escape_string($this->Lang)." FROM ".$table." WHERE keyword='".mysql_real_escape_string($Id)."'");
$row = mysql_fetch_assoc ($results);
return mysql_num_rows ($results) ? stripslashes ($row[$this->Lang]) : null;
}
// If needed to insert a name, for example, pass it in the $Arg
public function text($Id, $Arg = null)
{
$Text = $this->retrieve($Id);
if (empty($Text))
{
$Text = str_replace("_", " ", $Id); // If not found, replace all "_" with " " from the input string.
$this->add($Id, $Text);
}
return str_replace("%s", $Arg, $Text); // Not likely to have more than 2 variables into a single string.
}
}
您如何以正确而简单(编码)的方式实现这一目标?任何提议的方法是否有效,或者您能找到更好的方法吗?
答案 0 :(得分:6)
如果问题只是那个
$Translate->text('String_keyword');
感觉很长,然后考虑通过实施__invoke
将Translate对象变为Functor:
class Translate
{
// all your PHP code you already have
public function __invoke($keyword, $Arg = null)
{
return $this->text($keyword, $Arg)
}
}
然后,您可以定期使用所有必需的依赖项和设置实例化对象并调用它:
$_ = new Translate(/* whatever it needs */);
echo $_('Hallo Welt');
这不会引入相同数量的耦合和摆弄全局范围,正如您目前考虑通过包装函数或其他地方建议的Registry / Singleton解决方案引入的那样。唯一的缺点是对象变量的非语句命名为$_()
。
答案 1 :(得分:1)
我会使用注册表或使Translate
成为单身人士。当我第一次初始化它时,我将传递在请求的引导阶段不会的语言。然后我会在必要时添加更改语言的方法。
完成后,您的功能变得非常简单:
// singleton version
function _($id, $arg = null) {
return Translate::getInstance()->text($id, $arg);
}
// registry version
function _($id, $arg = null) {
return Registry::get('Translate')->text($id, $arg);
}
然后在你的bootstap阶段你会做类似的事情:
$lang = get_user_lang(); // replace with however you do this
//registry version
Registry::set('Tranlaste', new Translate($lang));
// or the singleton version
// youd use create instance instead of getInstance
// so you can manage the case where you try to call
// getInstance before a language is set
Translate::createInstance($lang);