Multi-lingual resource in Zend Framework 1

To continue my previous post, but this time tie it to the Zend Framework (version 1), I have added a ZF application resource plugin to my library which redirects the visitor to the correct language sub-domain according to his browser’s settings. This plugin will take care of the redirection logic, and keep all the necessary information for the application to provide the user with the GUI elements for switching languages.

Resource plugins are Zend Framework application plugins which allow for extra application configuration during bootstrapping. They can also be referenced to at a later stage to inquire about the application’s configuration in the plugin’s domain. You can find available examples here, which come with the Zend Framework package.

To create your own resource plugin, create a class based on Zend_Application_Resource_ResourceAbstract. You can set the plugin options in your application’s configuration file. A few basic examples are the layout and view plugins, which are configured thus:

resources.layout.layoutPath = APPLICATION_PATH "/views/layouts"
resources.layout.layout = "default"
resources.view.doctype = "HTML5"
resources.view.charset = "UTF-8"

These options can be loaded with the getOptions() function of the Zend_Application_Resource_ResourceAbstract class.

Now back to the multi-language resource plugin. I simply named it multilanguage, and I envision it to do the following for me:

  1. Redirect to the correct language sub-domain or document tree based on the browser’s language setting
  2. Keep a list of supported languages
  3. Remember the currently used language

The list of the supported languages will be stored in the application’s configuration file as the resource’s options, for example:

resources.multilanguage.languages[] = "en"
resources.multilanguage.languages[] = "ja"
resources.multilanguage.languages[] = "nl"

The application will know it is available in English, Japanese and Dutch.

In the example of redirecting to a language sub-domain, we follow the next flow diagram:

Language detection and selection
Flow chart for automatic language detection and selection

As the default language, we pick the first language in the available languages list from the plugin options, in this example’s case English. As the plugin also needs to know what the main domain is in the first step of the flow-chart diagram, we need to add this to the plugin’s options:

resources.multilanguage.domain = "example.org"

With this added, we need to make sure we have the following domains ready in DNS, and in the application’s virtual host configuration:

  • example.org: main domain
  • en.example.org: English
  • ja.example.org: Japanese
  • nl.example.org: Dutch

For the Apache2 virtual host configuration, I would use the main domain as the ServerName, and the other ones added as ServerAlias-es.

The following is a starting point for implementing this resource, so that it redirects the application based on the browser’s language setting:

class ZFE_Resource_Multilanguage extends Zend_Application_Resource_ResourceAbstract
{
    /**
     * Note: check Zend_Controller_Action_Helper_Redirect::_redirect for
     * a more sophisticated protocol detection for the $proto variable.
     */
    public function init()
    {
        $options = $this->getOptions();
        if (null === $options) return null;
 
        // Check options
        if (!isset($options['domain'])) {
            throw new Zend_Application_Resource_Exception();
        }
        if (!isset($options['languages']) || count($options['languages']) == 0) {
            throw new Zend_Application_Resource_Exception();
        }
 
        $domain = $_SERVER['SERVER_NAME'];
        if ($domain === $options['domain']) {
            // Detect browser language
            $locale = $this->getBootstrap()->getResource('locale');
            if (null === $locale) $locale = new Zend_Locale();
 
            $lang = $locale->getLanguage();
            if (!in_array($lang, $options['languages'])) {
                $lang = $options['languages'][0];
            }
 
            // Perform HTTP 302 redirect
            $proto = "http";
            $redirect = $proto . "://" . $lang . "." . $options['domain'];
            $redirect .= $_SERVER['REQUEST_URI'];
            header('HTTP/1.1 302');
            header('Location: ' . $redirect);
            exit();
        }
    }
}

The version in my library (May 8th 2013) also has special handling for the different scripts in Chinese, and to convert them into acceptable sub-domain parts (e.g. zh_Hant becomes zh-hant). Feel free to jump to the latest version to see what it has become.

If you have more ideas or suggestions that this resource plugin could do, please let me know in the comments below!

One thought on “Multi-lingual resource in Zend Framework 1”

What are your thoughts?