4

私はPHPを(常に)学んでおり、翻訳を処理するクラスを少し前に作成しました。gettext をエミュレートしたいのですが、データベースから翻訳された文字列を取得します。しかし、もう一度見てみると、クラスであるため、それを呼び出すには、 を使用する必要があります$Translate->text('String_keyword');$T->a('String_keyword');それは完全に直感的ではないので、どちらも使用する必要はありません。

シンプルな_('String_keyword')gettext スタイルで呼び出されるようにする方法について多くのことを考えてきましたが、SO から学んだことから、これを達成するための「優れた」方法を見つけることができませんでした。どういうわけかデフォルトの言語を関数に渡す必要があります。それを呼び出すたびに渡したくありません_('String_keyword', $User->get('Language')))。_()また、毎回実行する必要はなく、一度だけ実行する必要があるため、関数にユーザー検出スクリプトを含めたくありません。

最も簡単な方法はGLOBALSを使用することですが、ここでそれらが完全に禁止されていることを知りました (使用できるのはこれだけでしょうか? ) 。しかし、それはグローバルと同じようです。これらは私が見ることができる2つの主なオプションです。依存性注入のような他の方法があることは知っていますが、非常に単純な要求には複雑すぎるようで、まだそれらを掘り下げる時間がありません.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');

現在、ラッパー関数を介して導入することを検討している、またはレジストリ/シングルトンソリューションが他の場所で提案しているように、グローバルスコープと同じ量のカップリングといじりを導入することはありません。唯一の欠点は、オブジェクト変数の無意味な名前付けです$_()

于 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 に答える