PHP简单的翻译方法 - 您的意见

时间:2009-12-29 12:53:17

标签: php internationalization translation

我在做一个PHP网站,没有使用任何框架。我需要该网站有多种语言版本,我正在阅读它,它似乎有点令人困惑。有几种解决方案,但似乎都依赖于特定的框架。

您如何看待使用如下所示的简单翻译功能?

我的意思是,我想知道使用这些代码会有什么不利之处。 这是(这只是一个简单而不完整的样本):

class Translator{

    private $translations;

    public function __construct(){
        $this->translations = array(
            'Inbox'  => array(
                'en' => 'Inbox',
                'fr' => 'the french word for this'
            ),
            'Messages' => array(
                'en' => 'Messages',
                'fr' => 'the french word for this'
            )
            //And so on...
        );
    }

    public function translate($word,$lang){
        echo $this->translations[$word][$lang];
    }
}

10 个答案:

答案 0 :(得分:16)

看起来不错。我已经看过很多次了。

但是,我会根据每种语言在一个文件中分隔不同的字符串。至少,或者如果文件变大,每种语言每个模块一个文件。

然后,每次使用新语言时,您的翻译课程都可以加载和缓存语言文件(如果您不依赖任何其他缓存系统)。

我的意思的一个小例子

class Translator {
    private $lang = array();
    private function findString($str,$lang) {
        if (array_key_exists($str, $this->lang[$lang])) {
            return $this->lang[$lang][$str];
        }
        return $str;
    }
    private function splitStrings($str) {
        return explode('=',trim($str));
    }
    public function __($str,$lang) {
        if (!array_key_exists($lang, $this->lang)) {
            if (file_exists($lang.'.txt')) {
                $strings = array_map(array($this,'splitStrings'),file($lang.'.txt'));
                foreach ($strings as $k => $v) {
                    $this->lang[$lang][$v[0]] = $v[1];
                }
                return $this->findString($str, $lang);
            }
            else {
                return $str;
            }
        }
        else {
            return $this->findString($str, $lang);
        }
    }
}

这将查找以具有此条目的语言命名的.txt文件

  

富= FOO
  条= BAR

如果找不到任何翻译,它总是会回到原始字符串。

这是一个非常简单的例子。但是,如果您不需要更大的框架,我自己这样做是没有错的。

要以更简单的方式使用它,您始终可以执行此操作并创建名为“EN_Example.txt”的文件

class Example extends Translator {
    private $lang = 'EN';
    private $package = 'Example';
    public function __($str) {
        return parent::__($str, $this->lang . '_' . $this->package);
    }
}

有时您希望翻译包含变量的字符串。其中一种方法是我觉得这种方法很容易随时使用。

// Translate string "Fox=FOX %s %s"
$e = new Example();
// Translated string with substituted arguments
$s = printf($e->__('Fox'),'arg 1','arg 2');

为了进一步整合变量替换,printf功能可以放在__()函数中,就像这样

public function __() {
    if (func_num_args() < 1) {
        return false;
    }
    $args = func_get_args();
    $str = array_shift($args);
    if (count($args)) {
        return vsprintf(parent::__($str, $this->lang . '_' . $this->package),$args);
    }
    else {
        return parent::__($str, $this->lang . '_' . $this->package);
    }
}

答案 1 :(得分:4)

有些事情你似乎没有考虑过:

  • 你只是翻译单个单词吗?语言之间的句子结构和语法怎么样?
  • 当一个单词或句子还没有被翻译成某种语言时你会怎么做?
  • 您的翻译是否支持变量?句子中单词的顺序可以在不同的语言中有所不同,如果你有一个变量,通常只是简单地将单词分成句子就不够了。

我使用了两种解决方案,并建议用于PHP:

答案 2 :(得分:2)

不使用框架没关系。我看到你的功能唯一的问题是它将大量数据加载到内存中。我建议为每种语言使用数组,这样你只需要加载正在使用的语言。

答案 3 :(得分:2)

使用类或函数的优点是,您可以随着项目的增长更改语言的存储。如果您只有几个字符串,那么您的解决方案绝对没有问题。

如果你有很多字符串,可能需要时间,内存和硬盘资源来加载所有页面加载的语言数组。然后,您可能希望将其拆分为不同的文件,甚至可能使用数据库后端。如果使用i数据库,请考虑使用缓存(例如memcached),这样您就不需要在每次加载页面时数百次查询数据库。

您还可以查看gettext,它使用非常快的预编译语言文件。

答案 4 :(得分:2)

我原以为简单地为每种语言使用include可能更容易,其中的内容可能只是一个定义列表。

通过这样做,您可以避免包含所有语言数据的开销以及定期调用“翻译”功能的开销。

然而,这种方法将限制未来灵活性方面的问题。 (但这可能不是一个因素。)

答案 5 :(得分:1)

很久以前,当我遇到这样的问题(但对于一个非常小的网站,只有几页)时,我创建了一个名为langpack.php的文件,并且必须运行我网站上的任何文本字符串通过那个。现在,我会使用类似的方法,但拆分多个文件。

示例OOP方法

langpack.php

abstract class langpack {
    public static $language = array();

    public static function get($n) {
        return isset(self::$language[$n]) ? self::$language[$n] : null;
    }
}

english.php

final class English extends langpack {
    public static $language = array(
        'inbox' => 'Inbox',
        'messages' => 'Messages',
        'downloadError' => 'There was an error downloading your files',
    );
}

french.php

final class French extends langpack {
    public static $language = array(
        'inbox' => 'Inbioux',
        'messages' => 'Omelette du Fromage',
        'downloadError' => 'C\'est la vie',
    );
}

你应该从那里得到这个想法。在配置文件中实现autoloader然后加载语言应该是您可以通过会话,URL或其他任何方式轻松完成的操作,通过使用PHP的变量特性以及类实例化,如下所示:

$langpack = new $_SESSION['language'];
echo $langpack::get('inbox');

当然,所有这一切都可以通过简单的数组来完成,并以命令式样式访问(通过$GLOBALS处理绝对引用)以减少一些开销,甚至可能使得所有这些都被处理的机制有点透明,但是,嘿,那不会是OO,是吗?

答案 6 :(得分:1)

使用常量(定义)是一种不好的做法吗?

这就是我设置它的方式。这只是为了获得多种语言支持。

我有一个葡萄牙文件和一个填充的英文文件:

define('CONST','Meaning');

也许这有点像记忆,但我可以从我想要的任何地方访问:)

我可能会改用oop方法,但现在我有了这个。

答案 7 :(得分:1)

也可以使用Symfony translation component,不需要框架,composer有助于处理依赖项:

composer install --prefer-dist "symfony/translation":"@stable"

答案 8 :(得分:0)

如果您因其他原因没有使用任何框架,我认为没问题。当你不能/不想使用更有条理的翻译框架时,我们和你的情况一样:

我们正在一个小型的PHP项目中寻找一些简单的翻译机制。我们使用了与您类似的数组方法,但每个语言文本都有单独的文件。我们设置了一个小部件,以保持尽可能干净。

如果您想看看,我们会在https://github.com/BrainCrumbz/simple-php-translate上分享。请随时改进它!

答案 9 :(得分:0)

我只使用带控制器和语言输入的函数,例如:

function getLanguageFile($controller, $lang){
 // security: only allow letters a-z in both strings
 $controller = preg_replace('/([^a-z]*)/', '', $controller);
 $lang = preg_replace('/([^a-z]*)/', '', $lang);
 // return language details if present on disk
 if (is_file('lang/'.$controller.'/'.$lang.'.json')){
  return json_decode(file_get_contents('lang/'.$controller.'/'.$lang.'.json'));
 }
 return false;
}

如果控制器是索引并且语言是en,则只需将json格式的字符串放在lang / index / en.json中。 您可以为依赖项添加一个函数(例如,您希望在访问另一个控制器时加载索引控制器值),您所要做的就是合并结果。 你可以简单地包含带有数组的php文件,然后返回数组,但我建议你将这些翻译拆分成更大的项目。如果您的项目不是那么大,那么您的功能绝对可以。