Auto detect user locale with Zend\Http\Request headers and ext/intl
With the recent beta5 release of Zend Framework 2, a completely new
Zend\I18n
component is shipped. The component is (without any
misunderstanding about the work to get this done) a kind-of helper layer on
top of ext/intl, a php extension for all kind of i18n tasks.
Since this Zend\I18n
release I was thinking about using the Accept-Language
header a browser sends with a request. When there is no Accept-Language
header, or all the accepted languages are not in a list of supported
languages, a default locale is set. It is really useful here to use the
Zend\Http\Header\AcceptLanguage
object here, as it returns a
Zend\Stdlib\PriorityQueue
. You can iterate the queue, having the best-choice
language first until you get to the least-best match for a language.
To make this happen, I created a listener in a module for the bootstrap event, to register a default locale as fast as possible. For example the Module class of your Application module:
namespace Application;
use Locale;
use Zend\EventManager\EventInterface;
use Zend\ModuleManager\Feature;
class Module implements
Feature\BootstrapListenerInterface
{
public function onBootstrap(Event $e)
{
$default = 'en-GB';
$supported = array('en-GB', 'en-US', 'en-GB', 'nl-NL', 'nl-NL');
$app = $e->getApplication();
$headers = $app->getRequest()->getHeaders();
if ($headers->has('Accept-Language')) {
$locales = $headers->get('Accept-Language')->getPrioritized();
// Loop through all locales, highest priority first
foreach ($locales as $locale) {
if (!!($match = Locale::lookup($supported, $locale))) {
// The locale is one of our supported list
Locale::setDefault($match);
break;
}
}
if (!$match) {
// Nothing from the supported list is a match
Locale::setDefault($default);
}
} else {
Locale::setDefault($default);
}
}
}
Perhaps later on I will update it to a decent listener in a separate class. I could then use a factory to inject a default locale and a list of supported locales from the configuration. But for now, it is simple and “good enough”.