Saturday, March 8, 2014

zend framework 2 develop log 4 – multi language i18n translate

1.plan

1.1 why write this blog

because i want to share my experience  for your.

1.2 what purpose

my zend framework 2 index will detect user browser language,and intelligent redirect to other uri ex: xxx/controller/action/uilang/data locale id/other params.

2. do

2.1 designer draft

a. the detect user browser is implement in project/Application/view/application/index/index.phtml view file.it will used user browser header value $uilang = $_SERVER["HTTP_ACCEPT_LANGUAGE"].then give my mysql locale table,select localeid from localetable where locale=$uilang.and redirect to default target url.

b.default target url page will parse uilang and localeid param,when process data or redirect other uri,can used these value.

c.look up zend framework 2 route mechanism,and finished these step.

2.2 code

project/module/Application/src/Application/Controller/IndexController.php file source:

<?php

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

class IndexController extends AbstractActionController
{
public function indexAction()
{
return new ViewModel(array('controller' => $this));
}
}



project/module/Application/view/application/index/index.phtml view file source:


<?php 

$localeTable = $this->controller->getServiceLocator()->get('Api\Model\LocaleTable');
$locales = $localeTable->getLocales();

$uilang = \Application\View\Helper\LocaleHelper::getUserBrowserLocale();

$lid = \Application\View\Helper\LocaleHelper::getLidFromLocale($locales,$uilang);

$this->controller->plugin('redirect')->toRoute('application/rank',array('uilang' => $uilang, 'lid' => $lid));

?>


project/module/Application/src/Application/View/Helper/LocaleHelper.php file source:


<?php
/**
* Application\View\Helper
*
* @author liandeliang@gmail.com
* @version 1.0.0
*/
namespace Application\View\Helper;

use Zend\View\Helper\AbstractHelper;

/**
* View Helper
*/
class LocaleHelper extends AbstractHelper
{

public function __invoke($in)
{
// TODO Auto-generated UtilsHelper::__invoke
return $in;
}

private static function _getLocaleInfo($locale,$locales){
foreach($locales as &$item){
if($item['locale'] === $locale)
return $item;
}
return null;
}

public static function getLidFromLocale($locales,$locale){
$lid = 1;
do{
if(!$locales || !count($locales) || empty($locale))
break;

// direct query
$info = self::_getLocaleInfo($locale,$locales);
if($info){
$lid = $info['id'];
break;
}

// to lower query
$locale = strtolower($locale);
foreach($locales as &$item)
$item[locale] = strtolower($item[locale]);

$info = self::_getLocaleInfo($locale,$locales);
if($info){
$lid = $info['id'];
break;
}

// replace character query
$locale = strtok($locale,'_');
foreach($locales as &$item)
$item[locale] = strtok($item[locale],'_');

$info = self::_getLocaleInfo($locale,$locales);
if($info){
$lid = $info['id'];
break;
}

// get first lid
$info = $locales[0];
$lid = $info['id'];

}while(false);

return $lid;
}

public static function getUserBrowserLocale(){
$ret = 'en_US';
do{
if(!isset($_SERVER["HTTP_ACCEPT_LANGUAGE"]))
break;

// This means that you do not have the intl extension running. Locate your php.ini for 'intl' and enable it or contact your host (if youre on any hoster)
// return \Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']);

$langs = $_SERVER["HTTP_ACCEPT_LANGUAGE"];
if(empty($langs))
break;

$langs = explode(';', $langs);
if(!langs || !count($langs))
break;

$langs = explode(',', $langs[0]);
if(!langs || !count($langs))
break;

$ret = $langs[0];
$ret = str_replace('-', '_', $ret);
}while(false);

return $ret;
}

public static function setTranslateLocale($controller){
do{
$translator = $controller->getServiceLocator()->get('translator');
if(!$translator)
break;

$uilang = $controller->params('uilang');
if(empty($uilang))
$uilang = self::getUserBrowserLocale();

if(!empty($uilang)){
$translator->setLocale($uilang);
$translator->setFallbackLocale('en_US');
}
}while(false);
}
}


project/module/Application/config/module.config.php file source:

<?php

return array(
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
),
'application' => array(
'type' => 'Literal',
'options' => array(
'route' => '/application',
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Index',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'rank' => array(
'type' => 'Segment',
'options' => array(
'route' => '/rank[/:action[/:uilang[/:lid]]]',
'constraints' => array(
'action' => '[a-zA-Z0-9_-]*',
'lid' => '\d*',
'uilang' => '[a-zA-Z0-9_-]*',
),
'defaults' => array(
'controller' => 'Rank',
'action' => 'internet',
'uilang' => 'en',
'lid' => 1,
),
),
),
),
),
),
),
'service_manager' => array(
'factories' => array(
'translator' => 'Zend\I18n\Translator\TranslatorServiceFactory',
),
),
'translator' => array(
'locale' => 'en_US',
'translation_file_patterns' => array(
array(
'type' => 'gettext',
'base_dir' => __DIR__ . '/../language',
'pattern' => '%s.mo',
),
),
),
// ... other code
);





xxx/Model/Locale.php file source code:

<?php
namespace Api\Model;

class Locale
{
public $id;
public $locale;
public $country;

public function exchangeArray($data)
{
$this->id = (isset($data['id'])) ? $data['id'] : null;
$this->locale = (isset($data['locale'])) ? $data['locale'] : null;
$this->country = (isset($data['country'])) ? $data['country'] : null;
}

public function toArray(){
$ret = array();
$ret['id'] = $this->id;
$ret['locale'] = $this->locale;
$ret['country'] = $this->country;
return $ret;
}
}



xxx/Model/LocaleTable.php file source code:


<?php
namespace Api\Model;

use Zend\Db\TableGateway\TableGateway;

/*
CREATE TABLE `locale` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`locale` char(5) NOT NULL,
`country` varchar(128) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `locale` (`locale`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
*/
class LocaleTable
{
protected $tableGateway;

public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}

public function fetchAll()
{
$resultSet = $this->tableGateway->select();
return $resultSet;
}

public function getLocales()
{
$rowset = $this->tableGateway->select();

$ret = array();
foreach ($rowset as $row) {
$ret []= $row->toArray();
}

return $ret;
}

public function getLocale($id)
{
$id = (int)$id;

if(!$this->tableGateway->isInitialized())
$this->tableGateway->initialize();

$rowset = $this->tableGateway->select(array('id' => $id));
$ret = $rowset->current();
if($$ret)
$ret = $ret->toArray();

return $ret;
}

public function saveLocale(Locale $locale)
{
$data = array(
'id' => $locale->id,
'locale' => $locale->locale,
'country' => $locale->country,
);

$id = (int)$locale->id;
if ($id == 0) {
$this->tableGateway->insert($data);
} else {
if ($this->getLocale($id)) {
$this->tableGateway->update($data, array('id' => $id));
} else {
throw new \Exception('Locale id does not exist');
}
}
}

public function deleteKeyword($id)
{
$this->tableGateway->delete(array('id' => $id));
}
}




mysql locale data table and data:



CREATE TABLE IF NOT EXISTS `locale` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`locale` char(5) NOT NULL,
`country` varchar(128) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `locale` (`locale`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=47 ;


INSERT INTO `locale` (`id`, `locale`, `country`) VALUES
(1, 'en', 'English'),
(2, 'zh_CN', '简体中文'),
(3, 'af', 'Afrikaans'),
(4, 'bg', 'Bulgarian'),
(5, 'ca', 'Catalonian'),
(6, 'cs', 'Czech'),
(7, 'da', 'Danish'),
(8, 'de', 'German'),
(9, 'el_GR', 'ελληνικά'),
(10, 'en_GB', 'English (UK)'),
(11, 'es', 'Spanish/Latin American'),
(12, 'fa', 'فارسی (فارسی)'),
(13, 'fi', 'Finnish'),
(14, 'fr_CA', 'France (Canadian)'),
(15, 'fr', 'France (France)'),
(16, 'gr', 'Ελληνικά (παλαιά έκδοση)'),
(17, 'he', 'Hebrew'),
(18, 'hr', 'hrvatski'),
(19, 'hu', 'Hungarian'),
(20, 'id', 'Indonesian'),
(21, 'it', 'Italian'),
(22, 'ja', '日本'),
(23, 'ko', '한국의'),
(24, 'lt', 'Lithuanian'),
(25, 'lv', 'Latvian'),
(26, 'mk', 'Македонија'),
(27, 'nl', 'Dutch'),
(28, 'no_NB', 'Norwegian Bokm?l'),
(29, 'no_NN', 'Norwegian Nynorsk'),
(30, 'pl', 'Polish'),
(31, 'pt_BR', 'Portuguese/Brazil'),
(32, 'pt_PT', 'Portuguese/Portugal'),
(33, 'ro', 'Romanian'),
(34, 'ru', 'Россия'),
(35, 'sk', 'Slovak'),
(36, 'sl', 'Slovenian'),
(37, 'sr_RS', 'Српски Ћирилица'),
(38, 'sr', 'Serbiae Latine'),
(39, 'sv_SE', 'Swedish'),
(40, 'th', 'Thailand'),
(41, 'tr', 'Turkish'),
(42, 'ukr', 'Український'),
(43, 'vn', 'Việt'),
(44, 'zh_TW', '中華臺灣'),
(45, 'zh_HK', '中國香港'),
(46, 'reser', 'Reserve');





3.check


when i access default uri:http:// localhost/projectname/


then it redirect to http:// localhost/projectname/rank/internet/zh_CN/2


next timer,when i want to redirect to other url in rank/index view,then get $uilang = $this->controller->params(‘uilang’,’en_US’) and $lid = $this->controller->params(‘lid,1); ,and get new other target uri by code:

$this->controller->plugin('url')->fromRoute('application/image',array('q' => $item['key'],'uilang' => $uilang))



4.action


interflow with me,wait for improve,


5.last


thanks!

No comments: