2

一元化された言語システムを使用した多言語アプリケーションに取り組んでいます。これは、各言語の言語ファイルと単純なヘルパー関数に基づいています。

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];
}

これまで、すべての文字列は現在のユーザーに宛てられたシステムメッセージでした。したがって、私は常にその方法でそれを行うことができました。次に、文字列が動的な値に依存する他のメッセージを作成する必要があります。たとえば、テンプレートファイルで、アクションポイントの数をエコーし​​たいと思います。ユーザーが1ポイントしかない場合は、「1ポイントあります。」とエコーする必要があります。ただし、0ポイントまたは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;
}

関数の呼び出しはのようになり__s('current_points', array($points))ます。

$lang['current_points']この場合は、で"You have %s point(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;
}

関数の呼び出しはまだのように見えます__s('current_points', array($points))

$lang['current_points']array("You have %d point.","You have %d points.")です。

これら2つの機能をどのように組み合わせるのでしょうか。たとえば、ポイントと一緒にユーザー名を印刷したい場合(ランキングのように)。関数呼び出しは、のよう__x('current_points', array($username,$points))$lang['current_points']なりarray("$s has %d point.","%s has %d points.")ます。

採用しようとしましpreg_replace_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);

どうやら、関数がwhileループを離れていないかのように「メモリ不足」エラーが発生しているため、$subsは定義されていません。

誰かが私を正しい方向に向けることができますか?この問題に取り組むには、おそらく完全に異なる(そしてより良い)方法があります。また、私はまだそれを次のように拡張したいと思います:

$lang['invite_party'] = "%u invited you to $g party.";Adam invited you to his party."男性と女性のためになるべき"Betty invited you to her party."です。$subs両方$uに渡された値は$g、ユーザーオブジェクトになります。

4

3 に答える 3

4

コメントで述べたように、 gettext()は代替手段だと思います

ただし、別のアプローチが必要な場合は、ここに回避策があります

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 !

これにより、言語の可能性を一元化して、1つまたは別のテキストを解決するための独自の関数を作成する方法についてのアイデアが得られる場合があります。

これがお役に立てば幸いです。

于 2012-10-03T15:09:12.847 に答える
0

しばらく前にこのようなことをしたが、関心の分離によってあなたが直面しているすべての落とし穴を避けた場合。

下位レベルでは、言語固有のすべてを処理するフォーマッターをテンプレートに挿入しました。たとえば、数値や日付をフォーマットします。これには、$ value、$ singular、$pluralの3つのパラメーターを持つ関数"plural"があり、値に基づいて、後者の2つのうちの1つが返されました。数値のフォーマットに残されているため、値自体はエコーされませんでした。

翻訳全体はテンプレートエンジン内で行われました。テンプレートの継承ができるのはDwooだったので、すべてのHTML構造とたくさんのプレースホルダーを含むマスターテンプレートを設定しました。各言語はこのHTMLマスターを継承し、すべてのプレースホルダーを適切な言語出力に置き換えました。しかし、私たちはまだテンプレートエンジンの世界にいるので、フォーマッター関数の使用法を「変換」することができました。Dwooは、最初の呼び出しでテンプレートの継承をコンパイルします。これには、変換されたすべてのパラメーターを含む、フォーマッターへの後続のすべての呼び出しが含まれます。

性別の問題は、基本的に同じ解決策になります。性別($ sex、$ male、$ female)、$ sexは対象の性別、その他のパラメーターは男性または女性の表現です。

于 2012-10-03T14:44:31.133 に答える
0

おそらく、より良いアプローチは、Drupalの関数tで使用されるアプローチです。見てみましょう。

http://api.drupal.org/api/drupal/includes!bootstrap.inc/function/t/7

http://api.drupal.org/api/drupal/includes!bootstrap.inc/function/format_string/7

于 2012-10-03T14:56:07.063 に答える