Print message in all languages using single store, date on specified localization

screen

Did you maybe try to print one message in “all” languages on a single page?

First, let me tell you when I needed to do that. Recently I needed to develop functionality that will send some “custom” emails. You already know that we can set transactional emails for each website / store view and have those emails translated in administration/db. Challenge in my case was that I needed to translate some “random” sentences in one transactional email so using predefined email template wasn’t possible. Sure that we can inject variables and/or objects into email templates, but that didn’t help in my case.

If you have installed any version of Magento community edition >= 1.4.2.0 we can start with our translate module.

  1. tell magento about our module
  2. create module structure
  3. fill config.xml with content
  4. fill model Translate.php with content
  5. fill model Locale.php with content
  6. fill helper Data.php with content
  7. fill controller Index.php with content

1. Create file in app/etc/modules/Inchoo_Translation.xml with following content:

<?xml version="1.0"?>
<config>
    <modules>
        <Inchoo_Translate>
            <active>true</active>
            <codePool>local</codePool>
        </Inchoo_Translate>
    </modules>
</config>

2. create in app/code/local/Inchoo/Translate folders: etc, controllers, Model, Helper

3. create file in app/code/local/Inchoo/Translate/config.xml with following content:

<?xml version="1.0"?>
<config>
 
	<modules>
		<Inchoo_Translate>
			<version>0.1.0</version>
		</Inchoo_Translate>
	</modules>
 
	<frontend>
		<routers>
			<Inchoo_Translate>
				<use>standard</use>
				<args>
					<module>Inchoo_Translate</module>
					<frontName>inchoo</frontName>
				</args>
			</Inchoo_Translate>
		</routers>
	</frontend>
 
	<global>
		<models>
			<inchoo_translate>
				<class>Inchoo_Translate_Model</class>
			</inchoo_translate>
 
			<core>
				<rewrite>
					<locale>Inchoo_Translate_Model_Mage_Core_Model_Locale</locale>
					<translate>Inchoo_Translate_Model_Mage_Core_Model_Translate</translate>
				</rewrite>
			</core>
		</models>
 
		<helpers>
			<inchoo_translate>
				<class>Inchoo_Translate_Helper</class>
			</inchoo_translate>
		</helpers>
	</global>
 
</config>

As you can see we needed to rewrite 2 Magento models. From Translate model we needed to remove one if statement and in Locale model we just added few more “*ByLocaleCode” methods so we can use storeCode for all of our actions.

In helper file we’ll add method that will handle dates (regarding to localization). Because when Magento initialize some request it will load all sorts of caches in memory for specified localization and when you try to do something like this: Mage::helper(‘core’)->__(“translate me”) – Magento will use from cache/memory.
You can see that in:

/**
 * Translate model
 *
 * @author      Magento Core Team <core@magentocommerce.com>
 */
class Mage_Core_Model_Translate
//...
 
/**
     * Return translated string from text.
     *
     * @param string $text
     * @param string $code
     * @return string
     */
    protected function _getTranslatedString($text, $code)
    {
        $translated = '';
        if (array_key_exists($code, $this->getData())) {
            $translated = $this->_data[$code];
        }
        elseif (array_key_exists($text, $this->getData())) {
            $translated = $this->_data[$text];
        }
        else {
            $translated = $text;
        }
        return $translated;
    }

4. create file in app/code/local/Inchoo/Translate/Model/Mage/Core/Model/Translate.php with following content:

<?php
 
/**
 * Translate model
 *
 * @author      Inchoo <ivan.galambos@inchoo.net>
 */
class Inchoo_Translate_Model_Mage_Core_Model_Translate extends Mage_Core_Model_Translate
{
     /**
     * Retrieve locale
     *
     * @return string
     */
    public function getLocale()
    {
		$this->_locale = Mage::app()->getLocale()->getLocaleCode();
		return $this->_locale;
	}
}

As you can notice in code above, we just removed if from getLocale() method

5. create file in app/code/local/Inchoo/Translate/Model/Mage/Core/Model/Locale.php with following content:

<?php
/**
 * Locale model
 * 
 * @author     Inchoo <ivan.galambos@inchoo.net>
 */
 
class Inchoo_Translate_Model_Mage_Core_Model_Locale extends Mage_Core_Model_Locale
{
    /**
     * Create Zend_Date object with date converted to store timezone and store Locale
     *
     * @param   mixed $store Information about store
     * @param   string|integer|Zend_Date|array|null $date date in UTC
     * @param   boolean $includeTime flag for including time to date
     * @return  Zend_Date
     */
    public function getStoreDate($store=null, $date=null, $includeTime=false)
    {
        $timezone = Mage::app()->getStore($store)->getConfig(self::XML_PATH_DEFAULT_TIMEZONE);
        $locale = Mage::app()->getStore($store)->getConfig(self::XML_PATH_DEFAULT_LOCALE);
        $date = new Zend_Date($date, null, $locale);
        $date->setTimezone($timezone);
        if (!$includeTime) {
            $date->setHour(0)
                ->setMinute(0)
                ->setSecond(0);
        }
        return $date;
    }
 
    /**
	 * Returns a localized information string, supported are several types of informations.
	 * For detailed information about the types look into the documentation
	 *
	 * @param  string             $value  Name to get detailed information about
	 * @param  string             $path   (Optional) Type of information to return
	 * @return string|false The wished information in the given language
	 */
	public function getTranslationByLocaleCode($value = null, $path = null, $localeCode = null)
	{
		return $this->getLocale()->getTranslation($value, $path, $localeCode/*$this->getLocale()*/);
	}
	/**
	 * Retrieve ISO date format
	 *
	 * @param   string $type
	 * @return  string
	 */
	public function getDateFormatByLocaleCode($type=null, $localeCode)
	{
		return $this->getTranslationByLocaleCode($type, 'date', $localeCode);
	}
 
	/**
	 * Retrieve ISO time format
	 *
	 * @param   string $type
	 * @return  string
	 */
	public function getTimeFormatByLocaleCode($type=null, $localeCode)
	{
		return $this->getTranslationByLocaleCode($type, 'time', $localeCode);
	}
 
	/**
	 * Retrieve ISO datetime format
	 *
	 * @param   string $type
	 * @return  string
	 */
	public function getDateTimeFormatByLocaleCode($type, $localeCode)
	{
		return $this->getDateFormatByLocaleCode($type, $localeCode) . ' ' . $this->getTimeFormatByLocaleCode($type, $localeCode);
	}
}

Note that I added several “*ByLocaleCode” methods so we can left core Magento methods untouched.

6. create helper file in app/code/local/Inchoo/Translate/Helper/Data.php with following content:

<?php
 
/**
 * Translate helper
 *
 * @author      Inchoo <ivan.galambos@inchoo.net>
 */
class Inchoo_Translate_Helper_Data extends Mage_Core_Helper_Abstract
{
 
	/**
	 * Format date using specifed locale
	 *
	 * @param   date|Zend_Date|null $date in GMT timezone
	 * @param   string $format
	 * @param   bool $showTime
	 * @return  string
	 */
	public function formatDateByLocaleCode($date=null, $format='short', $showTime=false, $localeCode=null)
	{
		if ($localeCode === null || !is_string($localeCode)) {
			$localeCode = Mage::getStoreConfig('general/locale/code');
		}
		if (Mage_Core_Model_Locale::FORMAT_TYPE_FULL    	!==$format &&
				Mage_Core_Model_Locale::FORMAT_TYPE_LONG    !==$format &&
				Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM  !==$format &&
				Mage_Core_Model_Locale::FORMAT_TYPE_SHORT   !==$format) {
			return $date;
		}
		if (!($date instanceof Zend_Date) && $date && !strtotime($date)) {
			return '';
		}
		if (is_null($date)) {
			$date = Mage::app()->getLocale()->date(Mage::getSingleton('core/date')->gmtTimestamp(), null, null);
		}
		elseif (!$date instanceof Zend_Date) {
			$date = Mage::app()->getLocale()->date(strtotime($date), null, null, $showTime);
		}
 
		if ($showTime) {
			$format = Mage::app()->getLocale()->getDateTimeFormatByLocaleCode($format, $localeCode);
		}
		else {
			$format = Mage::app()->getLocale()->getDateFormatByLocaleCode($format, $localeCode);
		}
		return $date->toString($format);
	}
}

Note that we are calling in last if/else block ->getDate(Time/Format)ByLocaleCode(…. Those methods are placed in our Locale model (model that we rewrite).

7. create controller file in app/code/local/Inchoo/Translate/controllers/IndexController.php with following content:

<?php
 
/**
 * http://films.local/index.php/ExpiringFilmsNotifier/index/notify
 */
class Inchoo_Translate_IndexController extends Mage_Core_Controller_Front_Action
{
    public function translateAction()
    {
    	echo "<pre>";
 
    	$defaultStore = Mage::app()->getStore()->getCode();
    	$defaultLocale = Mage::app()->getLocale()->getLocaleCode();
    	$stores = array(1,2,3);
 
    	foreach ($stores as $storeId) {
    		Mage::app()->setCurrentStore($storeId);
    		$currentStore 	= Mage::app()->getStore()->getCode();
    		$currentLocale 	= Mage::getModel('core/locale')->getLocaleCode();
    		Mage::app()->getLocale()->setLocale($currentLocale);
    		// reinitialize translation cache
    		Mage::app()->getTranslator()->init('frontend', true);
 
    		echo Mage::helper('core')->__("Welcome, %s!", Mage::helper('inchoo_translate')
    			->formatDateByLocaleCode('2012-05-05 00:00:00', 'medium', false, $currentLocale))  . PHP_EOL;
    	}
    	//restore app to default values
    	Mage::app()->setCurrentStore($defaultStore);
    	Mage::app()->getLocale()->setLocale($defaultLocale);
    	Mage::app()->getTranslator()->init('frontend', true);
 
    	echo 'Did system restore default initialization?' . PHP_EOL;
    	echo Mage::helper('core')->__("Welcome, %s!", Mage::helper('inchoo_translate')
    			->formatDateByLocaleCode('2012-05-05 00:00:00', 'medium', false, $currentLocale))  . PHP_EOL;
    	exit;
    }
}

Note that we first create 2 variables: $defaultStore and $defaultLocale so we can revert back Magento initialization on customer view

If you have 3 stores (Magento Sample Data) be sure that you set localization for them. E.g. de_DE and fr_FR for Germany and France.
I created those two folders in app/etc/locale/de_DE/ and app/etc/locale/fr_FR/ with file Mage_Page.csv with following content:
For German:
“Welcome, %s!”,”de_DE Welcome, %s!”
For France :
“Welcome, %s!”,”fr_FR Welcome, %s!”

And last step is to visit something like: http://1620.magento.loc/inchoo/index/translate and you should see on screen:

Welcome, 5.5.2012.!
de_DE Welcome, 05.05.2012!
fr_FR Welcome, 5 05. 2012!
Did system restore default initialization?
Welcome, 5 05. 2012!

Last and for performance important thing to remember: Magento on each request initialize translation caches,… so if you need to run some cron with lots of translations,… be sure that you firstly sort your e.g. transactional emails by store_code and don’t reinitialize on each step translation caches. Instead of 1000 reinitialization you can do just 4-5 of them…


5 comments

  1. @dhilip
    check table customer_entity and see if email address is unique. If it is then you should remove that key… Otherwise you can trace where Magento store email address and check for uniqueness – you can comment that check. Also check other parts of Magento and see if it use somewhere select customer by email, as well as other extensions… I wouldn’t recommend you to do that, find another solution rather than modifying “core functionality”. Otherwise you could have some really big issues with other parts of the system/3rd part extensions.
    Gl

  2. First, let me tell you when I needed to do that. Recently I needed to develop functionality that will send some “custom” emails. You already know that we can set transactional emails for each website / store view and have those emails translated in administration/db. Challenge in my case was that I needed to translate some “random” sentences in one transactional email so using predefined email template wasn’t possible. Sure that we can inject variables and/or objects into email templates, but that didn’t help in my case.

  3. Hello Inchoo.net

    Thanks for Nice tutorials in support for Magento Developers.
    Tutorials are excellent to use and improve the skills.

    I have a requirement but no where I found the solution, so I’m posting it here, Please support me…

    My requirement, I want to allow customers with duplicate E-mail Id’s.
    Means same email id can be used by more customers. I’m using a custom module for login with user name.

    Its a very urgent requirement and I’m a very new bee to zend and magento as well, I believe I can expect this article soon.

  4. Thanks on pointing that out Alexander.
    Yes. That was my first attempt and project on which I’m working have some crazy requests so I couldn’t use that. I needed to develop this Module. Additional note is that I could have in one email several different sentences on different localization, depending on which store someone bought items. Functionality was build as ExpirationNotificationEmail module so I needed collect all items that should expire in some period and based on customer_id I needed to collect all items and send one email per customer :).
    What I did – separate everything in two pieces:
    1) fill data in database
    2) send emails from database 100 per cycle), delete record from database

  5. Did you consider using Mage_Core_Model_App_Emulation like they do Mage_Sales_Model_Order:sendNewOrderEmail ?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.