我在做一个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];
}
}
答案 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
的文件,并且必须运行我网站上的任何文本字符串通过那个。现在,我会使用类似的方法,但拆分多个文件。
abstract class langpack {
public static $language = array();
public static function get($n) {
return isset(self::$language[$n]) ? self::$language[$n] : null;
}
}
final class English extends langpack {
public static $language = array(
'inbox' => 'Inbox',
'messages' => 'Messages',
'downloadError' => 'There was an error downloading your files',
);
}
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文件,然后返回数组,但我建议你将这些翻译拆分成更大的项目。如果您的项目不是那么大,那么您的功能绝对可以。