SugarCRM Labels Hierarchy

sugarcrmdevelopers —  May 24, 2012

Labels can seem very straight forward when you’re working within Studio, but when you dive into code you’ll likely find that the system labels for a particular module or for dropdown definitions are strewn throughout several places in the system. Let’s examine the different places for label data and the hierarchy the system uses to compile the labels together and resolve conflicts.


First, know that there are three sets of labels within the system, $mod_strings is an array that carries the labels for a given module (e.g. Contacts or Accounts), while $app_strings and $app_list_strings contain system labels like translated module names, dropdown lists and system button labels (e.g. the “Print” link at the bottom of nearly every page). I find that $app_strings and $app_list_strings seem to have a bit of overlap, so the point to understand is consistency; if you define a label in $app_list_strings, you’ll want to call it from $app_list_strings.


Let’s start with the module-specific labels. You’ll find the original, vanilla labels are stored in the module-specific directories. For Contacts, that would be /modules/Contacts/language/. Language files are prefixed with the international language identifier, and SugarCRM supports 22 languages (and more are available around the ‘net). An example would for American English would be en_us, or Spanish (Español) as es_ES.

That said, the English language file would be en_us.lang.php. In that file is a single array, $mod_strings. The array keys are code references, always in CAPS and usually prefixed by LBL_. The values are the translated labels. For example,

$mod_strings = array(
     'LBL_FIRST_NAME' => 'First Name:',

This directory holds the stock language files, but to maintain an upgrade-safe system we don’t want to touch these files. Instead, we have two options for placing custom language definitions.

The easiest option for custom language files mirrors the original directory in the custom directory, again using Contacts that would be /custom/modules/Contacts/language/en_us.lang.php. This file will be structured the exact same way as the original file; the two arrays are merged when the screen is being generated for the user. If there are conflicts, the custom definition takes precedence. This method of custom language definition is ideal if you’re customizing a single system, i.e. not packaging changes up for mass-distribution and not having to work via Module Loader for a hosted system. Changes to language files made in Studio will write to this directory.

The second option for custom language files makes use of the Custom Extension directory and the cascading file-merge performed by Repair and Rebuild. If you’re not familiar, I’ll give an example. Let’s modify the LBL_FIRST_NAME label in Contacts. Create a file at /custom/Extension/modules/Contacts/Ext/Language/en_us.PSI_TopLevelLanguageChange.php. The file name itself is arbitrary, anything is allowed so long as you provide the proper language-determining prefix. It’s a good idea to also prepend an author key (similar to creating a module) to avoid collisions. Within that file we’ll create individual pieces of the $mod_strings array:

$mod_strings['LBL_FIRST_NAME'] = 'Forename';

Notice how we are explicit about setting the key and value within the already-existing array. Do not create the entire array. This array is not merged into the master language list the same way that /custom/modules/Contacts/language/ is. It is actually lower-priority, because it is intended for mass-distribution. You may notice that when exporting changes from Studio, the generated module uses this method to load the language files.

Also realize that merely creating this file did nothing. What we’ve done is placed the file in a directory that Repair and Rebuild will scan and create a compiled language definition from all files within the directory. The Repair and Rebuild process will create /custom/modules/Contacts/Ext/Language/en_us.lang.ext.php which holds the compiled field-explicit language adjustments from the Extension language definitions. You’ll also notice that in this file is a repeated warning message, “WARNING: The contents of this file are auto-generated.” Heed this warning; adjustments to this direct file will be wiped out on the next Repair and Rebuild.

So the hierarchy is this, in order of precedence:

  1. custom/modules/<ModuleName>/language/en_us.lang.php
  2. custom/modules/<ModuleName>/Ext/Language/en_us.lang.ext.php
  3. modules/<ModuleName>/language/en_us.lang.php

$app_list_strings and $app_strings

With an understanding of the hierarchy for $mod_strings, $app_strings and $app_list_strings make pretty good sense. These work similarly to $mod_strings, but base all custom definitions in slightly different directories:

  • /custom/include/language/en_us.lang.php for Studio-created or basic changes.
  • /custom/Extension/application/Ext/Language/en_us.PSI_ArbitraryName.php for the more easily-distributed field-specific or labels-specific, explicit changes. Remember that creating this file doesn’t actually affect anything until you perform the Repair and Rebuild, which creates…
  • /custom/application/Ext/Language/en_us.lang.ext.php for the compiled language files.
  • Default/Stock language definitions are kept in /include/language/en_us.lang.php.