4

我正在(不断地)学习 PHP,并且前段时间我创建了一个处理翻译的类。我想模拟 gettext但从数据库中获取翻译后的字符串。但是,现在我再次看到它,我不喜欢这样,作为一个班级,我需要使用$Translate->text('String_keyword');. 我不想使用任何一个,$T->a('String_keyword');因为这完全不直观。

我一直在思考如何使用简单_('String_keyword')的 gettext 样式调用它,但是,从我从 SO 中学到的东西,我还没有找到一个“好”的方法来实现这一点。我需要以某种方式将默认语言传递给函数,我不想每次调用它时都传递它_('String_keyword', $User->get('Language')))。我也不想在_()函数中包含用户检测脚本,因为它只需要运行一次而不是每次都运行。

最简单的方法是使用 GLOBALS,但我在这里了解到它们是完全被禁止的(这可能是我可以使用它们的唯一情况吗?),然后我想用用户的语言定义一个变量,例如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.
    }
  }

您将如何以适当而简单(用于编码)的方式完成此任务?任何建议的方法是否有效,或者您能提供更好的方法吗?

4

2 回答 2

6

如果问题仅仅是这样

$Translate->text('String_keyword');

感觉很长,然后考虑通过实现将 Translate 对象变成 Functor __invoke

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 解决方案那样引入与全局范围相同数量的耦合和摆弄。唯一的缺点是对象变量的非口语命名为$_().

于 2012-11-04T19:24:03.363 回答
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);
}

然后在您的引导阶段,您将执行以下操作:

$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);
于 2012-11-04T19:15:34.540 回答