Creating an intelligent language pack
For quite some time I have been maintaining the Dutch language pack for SugarCRM while working at Madcap. A number of users turned out to have a simple request: Change the name of a module throughout the application. However simple this may sound, it proves to be a tiresome job when using Sugar's flat language files. This article shows a solution for this common problem which requires a lot less effort to implement.
The usual actions taken to change the name of a module in SugarCRM are:
- Change the module name in an custom application strings file (both plural and singular), and in the related beans dropdowns
- Go through all modules and create custom files with updated module names where needed
For changing a common module such as Accounts to "Organizations" this would require the creation of dozens of custom language files, all of which require programming, testing, acceptance and deployment in the production environment. And when you for some reason decide to rename the module again you may do all the work over again, too.
Dynamic module names
The solution we came up with is removing all module names from all language files except for in $modList and $modListSingular and to refer to those two arrays in every instance in which we need a module name. This can be facilitated by a few simple functions.
For all code on this page:
<?php
/**
* Copyright (c) 2009 Madcap B.V. (<a href="http://madcap.nl" title="http://madcap.nl">http://madcap.nl</a>)
* All rights reserved.
*
* Permission is granted for use, copying, modification, distribution,
* and distribution of modified versions of this work as long as the
* above copyright notice is included.
*/
?>Custom language file:
<?php
/**
* Gender list for moduleList.
*
* Genders are used to format short sentences for a module.
*/
$app_list_strings['moduleListGender'] = array(
'Contacts' => 'de',
'Accounts' => 'de',
'Opportunities' => 'de',
'Cases' => 'de',
'Notes' => 'de',
'Calls' => 'het',
'Emails' => 'de',
'Meetings' => 'de',
'Tasks' => 'de',
'Leads' => 'de',
'Activities' => 'de',
'Bugs' => 'de',
'Feeds' => 'de',
'TimePeriods' => 'het',
'Project' => 'het',
'ProjectTask' => 'de',
'Campaigns' => 'de',
'Documents' => 'het',
'Users' => 'de',
'ProspectLists' => 'de',
'Prospects' => 'de',
'EmailTemplates' => 'de',
'Newsletters' => 'de',
'Releases' => 'de',
'Currencies' => 'de',
);
$app_list_strings['moduleList']['Accounts'] = 'Organisaties';
$app_list_strings['moduleListSingular']['Accounts'] = 'Organisatie';
?>dutch_langpack_utils.php:
<?php
/**
* @author Loek van Gool <l.vgool@madcap.nl>
*/
/**
* Return a module string respecting moduleList(-Singular).
*
* Types of output supported:
* - "module name": Just the module name
* - "new": A string usable as create link (nieuw/nieuwe)
* - "this": Translation of "This $module" (dit/deze)
*
* @param string $module The module name
* @param boolean $lc Lowercase output switch
* @param boolean $singular Singular output switch
* @param string $type Type of string required
*/
function dpl_mod_get($module, $lc, $singular, $type = "module name") {
global $app_list_strings;
if(empty($module)) {
return false;
}
$res = null;
switch ($type) {
case "module name":
if($singular) {
//As long as Bug #31110 is here, keep this
$app_list_strings = return_app_list_strings_language_madcap($GLOBALS['current_language']);
$res = $app_list_strings['moduleListSingular'][$module];
} else {
$res = $app_list_strings['moduleList'][$module];
}
if(empty($res)) {
$s = ($singular) ? "singular" : "plural";
echo __METHOD__.": No ".$s." translation for ".$module."<br>";
$GLOBALS['log']->error(__METHOD__.": No ".$s." translation for ".$module);
echo "<pre>";print_r($app_list_strings);echo "</pre>";
$res = $module."(!)";
}
break;
case "new":
switch($app_list_strings['moduleListGender'][$module]) {
case "het":
$res = "Nieuw ".dpl_mod_get($module, true, $singular, "module name");
break;
default:
$res = "Nieuwe ".dpl_mod_get($module, true, $singular, "module name");
break;
}
if($lc === true) {
return strtolower($res);
}
return $res;
case "this":
switch($app_list_strings['moduleListGender'][$module]) {
case "het":
$res = "Dit ".dpl_mod_get($module, true, $singular, "module name");
break;
default:
$res = "Deze ".dpl_mod_get($module, true, $singular, "module name");
break;
}
if($lc === true) {
return strtolower($res);
}
return $res;
case "double":
switch($app_list_strings['moduleListGender'][$module]) {
case "het":
$res = "Dubbel ".dpl_mod_get($module, true, $singular, "module name");
break;
default:
$res = "Dubbele ".dpl_mod_get($module, true, $singular, "module name");
break;
}
if($lc === true) {
return strtolower($res);
}
return $res;
case "suffix":
switch($app_list_strings['moduleListGender'][$module]) {
case "het":
$res = " ".dpl_mod_get($module, true, $singular, "module name");
break;
default:
$res = "e ".dpl_mod_get($module, true, $singular, "module name");
break;
}
if($lc === true) {
return strtolower($res);
}
return $res;
default:
return false;
}
if($lc === true) {
return strtolower($res);
}
return $res;
}
?>Note that this function supports the creation of short sentences and language articles which are required in Dutch. This way, we can alter the gender of the module without the need for any alterations in the code.
in Contacts' language files:
<?php
require_once 'custom/include/dutch/dutch_langpack_utils.php';
[...]
'LBL_ACCOUNT_ID' => dpl_mod_get("Accounts", false, true).' ID:',
'LBL_ACCOUNT_NAME' => dpl_mod_get("Accounts", false, true).':',
'LBL_CAMPAIGN' => dpl_mod_get("Campaigns", false, true).':',
'LBL_ACTIVITIES_SUBPANEL_TITLE' => dpl_mod_get("Activities", false, false).':',
[...]
?>We need a separate function to rebuild dropdowns with module names in them (because they are read from the default file first before the custom module names are loaded, they would otherwise be outdated).
<?php
/**
* Update a language array.
*
* Match the keys to moduleList or moduleListSingular and update values.
*
* @param array $array The target
* @param array $source The mother
* @return void
*/
function dlp_update($array, $source) {
$val = null;
foreach($array AS $key=>&$val) {
if(!empty($source[$key])) {
// The key is known in the source array, overwrite
$val = $source[$key];
}
}
return $array;
}
?>And we call this as follows:
<?php
if(isset($app_list_strings['product_category_dom'])
&& is_array($app_list_strings['product_category_dom'])
) {
$app_list_strings['product_category_dom'] = dlp_update($app_list_strings['product_category_dom'], $app_list_strings['moduleList']);
}
?>Interface
It proved to be a little effort to copy and alter Sugar's native Tab Rename functionality to allow $moduleListSingular and our new $moduleListGender to be altered in the same way. So in our Dutch Language Pack, all three can be customized through the interface.
Other languages
This pack is specifically made for the Dutch language, but can probably be altered to support more languages. The dpl_mod_get() function is easily extended to support more language constructs, and the gender functionality is also optional.
Download
You may check out the pack here: http://www.sugarforge.org/frs/?group_id=563.
- Topic:
