Commit a9cbd19b authored by David Mudrák's avatar David Mudrák
Browse files

MDL-26804 core_string_manager::get_list_of_translations() can use a cache again

This patch reimplements the internal cache that was used to store the
list of available translations in Moodle 1.x. By default, the method
get_list_of_translations() still uses the file
moodledata/cache/languages to store the list of available translations.
The location of that file can be redefined in config.php. The internal
format of the cache file is JSON now (used to be a plain text list).

The patch also fixes a usage of the global $CFG in translation_exists()
methods where the internal property should be used instead.
parent 92a387b4
......@@ -53,11 +53,6 @@ define('INSTALLATION_OF_SELECTED_LANG', 2);
define('UPDATE_ALL_LANG', 5);
//reset and diagnose lang cache permissions
if (file_exists($CFG->dataroot.'/cache/languages')) {
print_error('cannotdeletelangcache', 'error');
$notice_ok = array();
......@@ -10,7 +10,7 @@ if ($hassiteconfig) {
$temp->add(new admin_setting_configselect('lang', get_string('lang', 'admin'), get_string('configlang', 'admin'), current_language(), get_string_manager()->get_list_of_translations())); // $CFG->lang might be set in installer already, default en is in setup.php
$temp->add(new admin_setting_configcheckbox('langmenu', get_string('langmenu', 'admin'), get_string('configlangmenu', 'admin'), 1));
$temp->add(new admin_setting_langlist());
$temp->add(new admin_setting_configcheckbox('langcache', get_string('langcache', 'admin'), get_string('configlangcache', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('langcache', get_string('langcache', 'admin'), get_string('langcache_desc', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('langstringcache', get_string('langstringcache', 'admin'), get_string('configlangstringcache', 'admin'), 1));
$temp->add(new admin_setting_configtext('locale', get_string('localetext', 'admin'), get_string('configlocale', 'admin'), '', PARAM_FILE));
$temp->add(new admin_setting_configselect('latinexcelexport', get_string('latinexcelexport', 'admin'), get_string('configlatinexcelexport', 'admin'), '0', array('0'=>'Unicode','1'=>'Latin')));
......@@ -357,6 +357,13 @@ $CFG->admin = 'admin';
// $CFG->langcacheroot = '/var/www/moodle/htdocs/altcache/lang';
// If $CFG->langcache is enabled (which should always be in production
// environment), Moodle stores the list of available languages in a cache file.
// By default, the file $CFG->dataroot/languages is used. You may wish to
// specify an alternative location of this cache file.
// $CFG->langmenucachefile = '/var/www/moodle/htdocs/altcache/languages';
// Site default language can be set via standard administration interface. If you
// want to have initial error messages for eventual database connection problems
// localized too, you have to set your language code here.
......@@ -246,7 +246,6 @@ $string['configjabberpassword'] = 'The password to use when connecting to the Ja
$string['configjabberport'] = 'The port to use when connecting to the Jabber server';
$string['configkeeptagnamecase'] = 'Check this if you want tag names to keep the original casing as entered by users who created them';
$string['configlang'] = 'Choose a default language for the whole site. Users can override this setting using the language menu or the setting in their personal profile.';
$string['configlangcache'] = 'Cache the language menu. Saves a lot of memory and processing power. If you enable this, the menu takes a few minutes to update after you have added or removed languages.';
$string['configlangstringcache'] = 'Caches all the language strings into compiled files in the data directory. If you are translating Moodle or changing strings in the Moodle source code then you may want to switch this off. Otherwise leave it on to see performance benefits.';
$string['configlangdir'] = 'Most languages are printed left-to-right, but some, like Arabic and Hebrew, are printed right-to-left.';
$string['configlanglist'] = 'Leave this blank to allow users to choose from any language you have in this installation of Moodle. However, you can shorten the language menu by entering a comma-separated list of language codes that you want. For example: en,es_es,fr,it';
......@@ -632,6 +631,7 @@ $string['jabberport'] = 'Jabber port';
$string['keeptagnamecase'] = 'Keep tag name casing';
$string['lang'] = 'Default language';
$string['langcache'] = 'Cache language menu';
$string['langcache_desc'] = 'Cache the language menu. If enabled, the list of available translations is cached. The cache is automatically refreshed when you install or delete a language pack via the in-built language packs management tool. If you install a new language pack manually, you have to use Purge all caches feature to refresh the cached list.';
$string['langedit'] = 'Language editing';
$string['langimport'] = 'Language import utility';
$string['langimportdisabled'] = 'Language import feature has been disabled. You have to update your language packs manually at the file-system level.';
......@@ -61,7 +61,6 @@ $string['cannotdeletecourse'] = 'You do not have the permission to delete this c
$string['cannotdeletecustomfield'] = 'Error deleting custom field data';
$string['cannotdeletedir'] = 'Cannot delete ({$a})';
$string['cannotdeletefile'] = 'Cannot delete this file';
$string['cannotdeletelangcache'] = 'Language cache cannot be deleted, please fix permissions in dataroot/cache/languages!';
$string['cannotdeleterole'] = 'It cannot be deleted, because {$a}';
$string['cannotdeleterolewithid'] = 'Could not delete role with ID {$a}';
$string['cannotdeletethisrole'] = 'You cannot delete this role because it is used by the system, or because it is the last role with administrator capabilities.';
......@@ -5484,17 +5484,28 @@ function get_string_manager($forcereload=false) {
if ($singleton === null) {
if (empty($CFG->early_install_lang)) {
if (empty($CFG->langcacheroot)) {
$langcacheroot = $CFG->dataroot . '/cache/lang';
} else {
$langcacheroot = $CFG->langcacheroot;
if (empty($CFG->langlist)) {
$translist = array();
} else {
$translist = explode(',', $CFG->langlist);
$singleton = new core_string_manager($CFG->langotherroot, $CFG->langlocalroot, $langcacheroot, !empty($CFG->langstringcache), $translist);
if (empty($CFG->langmenucachefile)) {
$langmenucache = $CFG->dataroot . '/cache/languages';
} else {
$langmenucache = $CFG->langmenucachefile;
$singleton = new core_string_manager($CFG->langotherroot, $CFG->langlocalroot, $langcacheroot,
!empty($CFG->langstringcache), $translist, $langmenucache);
} else {
$singleton = new install_string_manager();
......@@ -5624,22 +5635,26 @@ class core_string_manager implements string_manager {
protected $usediskcache;
/* @var array limit list of translations */
protected $translist;
/** @var string location of a file that caches the list of available translations */
protected $menucache;
* Crate new instance of string manager
* Create new instance of string manager
* @param string $otherroot location of downlaoded lang packs - usually $CFG->dataroot/lang
* @param string $localroot usually the same as $otherroot
* @param string $cacheroot usually lang dir in cache folder
* @param bool $usediskcache use disk cache
* @param array $translist limit list of visible translations
* @param string $menucache the location of a file that caches the list of available translations
public function __construct($otherroot, $localroot, $cacheroot, $usediskcache, $translist) {
public function __construct($otherroot, $localroot, $cacheroot, $usediskcache, $translist, $menucache) {
$this->otherroot = $otherroot;
$this->localroot = $localroot;
$this->cacheroot = $cacheroot;
$this->usediskcache = $usediskcache;
$this->translist = $translist;
$this->menucache = $menucache;
......@@ -6007,15 +6022,13 @@ class core_string_manager implements string_manager {
* @return boot true if exists
public function translation_exists($lang, $includeall = true) {
global $CFG;
if (strpos($lang, '_local') !== false) {
// _local packs are not real translations
return false;
if (!$includeall and !empty($CFG->langlist)) {
$enabled = explode(',', $CFG->langlist);
if (!in_array($lang, $enabled)) {
if (!$includeall and !empty($this->translist)) {
if (!in_array($lang, $this->translist)) {
return false;
......@@ -6036,7 +6049,30 @@ class core_string_manager implements string_manager {
$languages = array();
//TODO: add some translist cache stored in normal cache dir
if ($CFG->langcache and is_readable($this->menucache)) {
// try to re-use the cached list of all available languages
$cachedlist = json_decode(file_get_contents($this->menucache), true);
if (is_array($cachedlist) and !empty($cachedlist)) {
// the cache file is restored correctly
if (!$returnall and !empty($this->translist)) {
// return just enabled translations
foreach ($cachedlist as $langcode => $langname) {
if (in_array($langcode, $this->translist)) {
$languages[$langcode] = $langname;
return $languages;
} else {
// return all translations
return $cachedlist;
// the cached list of languages is not available, let us populate the list
if (!$returnall and !empty($this->translist)) {
// return only some translations
......@@ -6080,6 +6116,12 @@ class core_string_manager implements string_manager {
if ($CFG->langcache and !empty($this->menucache)) {
// cache the list so that it can be used next time
file_put_contents($this->menucache, json_encode($languages));
......@@ -6111,8 +6153,16 @@ class core_string_manager implements string_manager {
global $CFG;
// clear the on-disk disk with aggregated string files
// clear the in-memory cache of loaded strings
$this->cache = array();
// clear the cache containing the list of available translations
// and re-populate it again
......@@ -1290,7 +1290,6 @@ function upgrade_language_pack($lang='') {
$status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
if ($status == COMPONENT_INSTALLED) {
if ($parentlang = get_parent_language($lang)) {
if ($cd = new component_installer('', 'langpack/2.0', $parentlang.'.zip', 'languages.md5', 'lang')) {
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment