Magento: Translate untranslatable labels in admin area

Tweet about this on TwitterShare on LinkedInShare on Google+Share on FacebookEmail this to someone

During the last 3 weeks I’ve had to write a couple of modules that work in the Magento admin section. From here, I got the idea to write a series of short articles about the things I learned during this period.

Quick Overview

I’ll begin with an article that describes one way of translating the labels of some of the form fields in the admin section, which are generally not subject to translation from a CSV file or the Magento inline translation system. I decided to pack my idea into a module that, if you want, you can download and use for your own purposes.

Download: CeckosLab_UntranslatableAdmin

I found another approach, that solves the same problem. You can check it on blog and the articles is written by Ivan Galambos: How to translate form labels in Magento’s Admin Area …. check it, because it is possible this approach to be more useful for your needs 😉

Personally, when working in the admin section, I prefer to have the interface translated into the default language, i.e. English. My client, however, said he’d like the interface translated into his own language.

Let me give you some examples that will help me make my point:

magento untraslatable admin labels

This image shows the category creation and editing section. The inline translation system is switched on and the texts which are subject to translation are enclosed in red rectangles. Some of the fields covered by this article are those, which are not highlighted in red, and namely “Name”, “Description”, etc. These not being highlighted gives a clear signal that they are not being printed by the Magento translation system. This means that the strings printed here are not enclosed in the __(‘Example String’) translation function.

I’ll cut it short, but what I found after examining the source code and the database is that these fields cannot be translated using the standard tools in Magento.

One way to translate them is by changing the label names directly in the ‘eav_attribute’ database table. This, in my opinion, is not a good approach, because it makes it prone to errors and does not make clear the exact way of doing it. In a word, I’d say that modifying the values ​​in this manner is a knife that cuts both ways. It may yield results quickly, but has unforseeable consequences in the future.

I studied a few other possible approaches to solving this problem:

  1. Enclose the labels in the __() translation function somewhere in the code
  2. Replace the names using JavaScript after printing them on the screen

I went for the second approach, because I decided it was more portable. Also, my fingers were itching and I decided to implement some new techniques I’d read about on the blog.

Articles, that I used for reference:

In order to complete my task, the following steps had to be performed:

  1. Locate the block containing the labels I want to translate.
  2. Extract the translations from the CSV file, which is in my module’s folder.
  3. Insert a JavaScript snippet, which, through DOM manipulation and string replacement, will complete the translation.

Let’s look at these steps in a little more detail:

1. Locate the block

The idea of ​​how to locate the block where I want to insert the translations is not mine. I read about it in the article “How you could build your Magento extensions without view files“. In short, an event handler is created – ‘core_block_abstract_to_html_after’ and a check is carried out of the block we need.

Unlike the example he has given, I use a different condition in order to check if I have found the block I need.

class CeckosLab_UntranslatableAdmin_Model_Observer {
	const MODULE_NAME = 'CeckosLab_UntranslatableAdmin';
	public function appendTranslationFix($observer = NULL) {
		if (!$observer) {
		if ($observer->getEvent()->getBlock() instanceof Mage_Adminhtml_Block_Catalog_Category_Edit_Form) {
			if (!Mage::getStoreConfig('advanced/modules_disable_output/' . self::MODULE_NAME)) {
				$transport = $observer->getEvent()->getTransport();
				$block = new CeckosLab_UntranslatableAdmin_Block_Translate();
		return $this;

After some debugging, I found out that the name of the block, which I was interested in is “category.edit.child0”. So I decided to do the check using the class name rather than by the block name because the block name is automatically generated and could not find a suitable way to determine what block name I should expect.

2. Extract the translations from the CSV file

I decided to look into the Magento code to see how the reading of CSV files is done in the Magento way. I ran into the Varien_File_Csv class, which did a perfect job.

class CeckosLab_UntranslatableAdmin_Helper_Data extends Mage_Core_Helper_Abstract
	const CSV_SEPARATOR     = ',';

    public function getExtTranslationFile($fileName)
        return __DIR__.DS.'..'.DS.DS.'translations'.DS.$fileName;
     * Retrieve data from file
     * @param   string $file
     * @return  array
    public function getTranslationsArray($fileName) {
    	$data = array();
    	$file = $this->getExtTranslationFile($fileName);
        if (file_exists($file)) {
            $parser = new Varien_File_Csv();
            $data = $parser->getData($file);
        return $data;


In the CSV file, I have three values ​​in each row, and the form of the CSV file is as follows:

“Value attribute of the label element I would like to translate”,
“Source text (English)”,

For example:

"group_7name", "Name", "име"
"group_7description", "Description", "Описание"

Here is a short piece of HTML code, which elucidates the exact way I define what values ​​to insert itno the CSV file.


I need the value of the “for” attribute in order to specify the exact location to do the translation. This is the best way I could figure out. I’ll be happy if someone offers a better approach :)

3. Insert a JavaScript snippet

class CeckosLab_UntranslatableAdmin_Block_Translate extends Mage_Core_Block_Text
    protected $_nameInLayout = 'translation.javascript.fix';
    protected $_alias = 'javascript_fix';
    public function setPassingTransport($transport)
        $this->setData('text', $transport . $this->getTranslationJs());
	public function getTranslationJs() {		
		$helper = Mage::helper('untranslatableadmin');
		$translations = $helper->getTranslationsArray('category_edit.csv');
		if(!empty($translations)) {
			$varienObject = new Varien_Object($translations);
			$json = $varienObject->toJson();
			$text = ' 
		return $text;

After consulting a colleague, I decided to convert the array that I get from reading the CSV file in JSON, to take advantage of the toJson() method to escape some characters for me. You may also notice that I execute the JavaScript before I have loaded the entire document. Perhaps if I printed the script before the html I want to manipulate, this would have caused complications. In my case, however, I am quite sure that the JavaScript gets printed after the html.


Usually, when we decide to edit a category, an AJAX request is made to Magento, the response to which is data in a json format. These data are then dynamically inserted into the page and they only refresh the section where the category gets edited. The JavaScript I use for the translations is also included in these data. On several occasions, I submitted a JavaScript having the wrong syntax and here is the result I got on my screen:

Broken AJAX Response

I’ve error-proofed my code for errors as much as I could, but still, be careful when using it. If you find something wrong in it, I hope you’ll let me know.

Something still makes me think that Magento has a normal way to do translations that I might have missed. What I’ve proposed above is a workaround and a bit unnatural. I’d be glad if someone offers a different approach.

Tweet about this on TwitterShare on LinkedInShare on Google+Share on FacebookEmail this to someone

Tsvetan Stoychev

Tsvetan aka. Cecko is the founder of Cecko's Lab. He is Magento addicted since Magento CE and has worked on over 30 Magento projects. At the moment he is in charge to take care about the money flow of the company, to keep constant communication with the clients and to keep the people in the office busy.

More Posts

Follow Me: