caching translations for 10days and changing translation url, when translations are changing --> saves server-roundtrip for each translation

This commit is contained in:
Ralf Becker 2014-01-09 15:32:07 +00:00
parent 13572c472a
commit 400240f1e4
7 changed files with 57 additions and 41 deletions

View File

@ -135,14 +135,14 @@ class etemplate_new extends etemplate_widget_template
{ {
if (!in_array($l_app, array($currentapp, 'custom'))) if (!in_array($l_app, array($currentapp, 'custom')))
{ {
$langRequire[$l_app] = array('app' => $l_app, 'lang' => $lang); $langRequire[$l_app] = array('app' => $l_app, 'lang' => $lang, 'etag' => translation::etag($l_app, $lang));
} }
} }
foreach(array($currentapp, 'custom') as $l_app) foreach(array($currentapp, 'custom') as $l_app)
{ {
if (isset(translation::$loaded_apps[$l_app])) if (isset(translation::$loaded_apps[$l_app]))
{ {
$langRequire[$l_app] = array('app' => $l_app, 'lang' => translation::$loaded_apps[$l_app]); $langRequire[$l_app] = array('app' => $l_app, 'lang' => translation::$loaded_apps[$l_app], 'etag' => translation::etag($l_app, translation::$loaded_apps[$l_app]));
} }
} }

View File

@ -378,6 +378,9 @@ class config
} }
} }
} }
// some things need on client-side which are not direct configs
$client_config['phpgwapi']['lang_ctimes_md5'] = md5(json_encode(self::$configs['phpgwapi']['lang_ctimes']));
return $client_config; return $client_config;
} }

View File

@ -428,6 +428,29 @@ class translation
} }
} }
/**
* Get a state / etag for a given app's translations
*
* We currently only use a single state for all none-instance-specific apps depending on lang_ctimes.
*
* @param string $_app
* @param string $_lang
* @return string
*/
static function etag($_app, $_lang)
{
if (!in_array($_app, translation::$instance_specific_translations))
{
$etag = md5(json_encode($GLOBALS['egw_info']['server']['lang_ctimes']));
}
else
{
$etag = md5(json_encode(egw_cache::getCache(egw_cache::INSTANCE, __CLASS__, $_app.':'.$_lang)));
}
error_log(__METHOD__."('$_app', '$_lang') returning '$etag'");
return $etag;
}
/** /**
* Loads translations for an application direct from the lang-file(s) * Loads translations for an application direct from the lang-file(s)
* *

View File

@ -20,7 +20,7 @@ egw.extend('config', egw.MODULE_GLOBAL, function() {
/** /**
* Clientside config * Clientside config
* *
* @access: private, use egw.config(_name, _app="phpgwapi") * @access: private, use egw.config(_name, _app="phpgwapi")
*/ */
var configs = {}; var configs = {};
@ -28,7 +28,7 @@ egw.extend('config', egw.MODULE_GLOBAL, function() {
return { return {
/** /**
* Query clientside config * Query clientside config
* *
* @param string _name name of config variable * @param string _name name of config variable
* @param string _app default "phpgwapi" * @param string _app default "phpgwapi"
* @return mixed * @return mixed
@ -37,14 +37,14 @@ egw.extend('config', egw.MODULE_GLOBAL, function() {
{ {
if (typeof _app == 'undefined') _app = 'phpgwapi'; if (typeof _app == 'undefined') _app = 'phpgwapi';
if (typeof configs[_app] == 'undefined') return null; if (typeof this.configs[_app] == 'undefined') return null;
return configs[_app][_name]; return this.configs[_app][_name];
}, },
/** /**
* Set clientside configuration for all apps * Set clientside configuration for all apps
* *
* @param array/object * @param array/object
*/ */
set_configs: function(_configs) set_configs: function(_configs)

View File

@ -25,7 +25,7 @@ egw.extend('lang', egw.MODULE_GLOBAL, function() {
/** /**
* Translations * Translations
* *
* @access: private, use egw.lang() or egw.set_lang_arr() * @access: private, use egw.lang() or egw.set_lang_arr()
*/ */
var lang_arr = {}; var lang_arr = {};
@ -34,7 +34,7 @@ egw.extend('lang', egw.MODULE_GLOBAL, function() {
return { return {
/** /**
* Set translation for a given application * Set translation for a given application
* *
* @param string _app * @param string _app
* @param object _message message => translation pairs * @param object _message message => translation pairs
* @memberOf egw * @memberOf egw
@ -46,10 +46,10 @@ egw.extend('lang', egw.MODULE_GLOBAL, function() {
lang_arr[_app] = _messages; lang_arr[_app] = _messages;
} }
}, },
/** /**
* Translate a given phrase replacing optional placeholders * Translate a given phrase replacing optional placeholders
* *
* @param string _msg message to translate * @param string _msg message to translate
* @param string _arg1 ... _argN * @param string _arg1 ... _argN
*/ */
@ -62,7 +62,7 @@ egw.extend('lang', egw.MODULE_GLOBAL, function() {
} }
var translation = _msg; var translation = _msg;
_msg = _msg.toLowerCase(); _msg = _msg.toLowerCase();
// search apps in given order for a replacement // search apps in given order for a replacement
var apps = this.lang_order || ['custom', this.getAppName(), 'etemplate', 'common']; var apps = this.lang_order || ['custom', this.getAppName(), 'etemplate', 'common'];
for(var i = 0; i < apps.length; ++i) for(var i = 0; i < apps.length; ++i)
@ -75,9 +75,9 @@ egw.extend('lang', egw.MODULE_GLOBAL, function() {
} }
} }
if (arguments.length == 1) return translation; if (arguments.length == 1) return translation;
if (arguments.length == 2) return translation.replace('%1', arguments[1]); if (arguments.length == 2) return translation.replace('%1', arguments[1]);
// to cope with arguments containing '%2' (eg. an urlencoded path like a referer), // to cope with arguments containing '%2' (eg. an urlencoded path like a referer),
// we first replace all placeholders '%N' with '|%N|' and then we replace all '|%N|' with arguments[N] // we first replace all placeholders '%N' with '|%N|' and then we replace all '|%N|' with arguments[N]
translation = translation.replace(/%([0-9]+)/g, '|%$1|'); translation = translation.replace(/%([0-9]+)/g, '|%$1|');
@ -116,9 +116,10 @@ egw.extend('lang', egw.MODULE_GLOBAL, function() {
{ {
if (typeof lang_arr[_apps[i].app] === "undefined") if (typeof lang_arr[_apps[i].app] === "undefined")
{ {
jss.push(this.webserverUrl jss.push(this.webserverUrl +
+ '/phpgwapi/lang.php?app=' '/phpgwapi/lang.php?app=' + _apps[i].app +
+ _apps[i].app + '&lang=' + _apps[i].lang); '&lang=' + _apps[i].lang +
'&etag=' + (_apps[i].etag || this.config('lang_ctimes_md5')));
} }
apps.push(_apps[i].app); apps.push(_apps[i].app);
} }
@ -138,7 +139,7 @@ egw.extend('lang', egw.MODULE_GLOBAL, function() {
{ {
// Require a "ready postpone token" // Require a "ready postpone token"
var token = ready.readyWaitFor(); var token = ready.readyWaitFor();
// Call "readyDone" once all js files have been included. // Call "readyDone" once all js files have been included.
files.includeJS(jss, function () { files.includeJS(jss, function () {
ready.readyDone(token); ready.readyDone(token);

View File

@ -457,7 +457,7 @@ egw.extend('links', egw.MODULE_GLOBAL, function() {
this.value = ''; this.value = '';
}); });
// need to load common translations for app-names // need to load common translations for app-names
this.includeJS([this.webserverUrl+'/phpgwapi/lang.php?app=common&lang='+this.preference('lang')], function(){ this.langRequire(window, [{app: 'common', lang: this.preference('lang')}], function(){
select.append(jQuery(document.createElement('option')).attr('value', '').text(self.lang('Add')+' ...')); select.append(jQuery(document.createElement('option')).attr('value', '').text(self.lang('Add')+' ...'));
var apps = self.link_app_list('add'); var apps = self.link_app_list('add');
for(var app in apps) for(var app in apps)

View File

@ -30,23 +30,15 @@ $GLOBALS['egw_info'] = array(
include '../header.inc.php'; include '../header.inc.php';
// use an etag with app, lang and a hash over the creation-times of all lang-files // use an etag with app, lang and a hash over the creation-times of all lang-files
if (!in_array($_GET['app'], translation::$instance_specific_translations)) $etag = '"'.$_GET['app'].'-'.$_GET['lang'].'-'.translation::etag($_GET['app'], $_GET['lang']).'"';
{
$etag = '"'.$_GET['app'].'-'.$_GET['lang'].'-'.md5(serialize($GLOBALS['egw_info']['server']['lang_ctimes'])).'"'; // tell browser/caches to cache for one day, we change url on real modifications
} $expires = 864000; // 10days
else
{
translation::add_app($_GET['app'], $_GET['lang']);
if (!count(translation::$lang_arr))
{
translation::add_app($_GET['app'], 'en');
}
$etag = '"'.$_GET['app'].'-'.$_GET['lang'].'-'.md5(serialize(translation::$lang_arr));
}
// headers to allow caching of one month // headers to allow caching of one month
Header('Content-Type: text/javascript; charset=utf-8'); Header('Content-Type: text/javascript; charset=utf-8');
Header('Cache-Control: public, no-transform'); Header('Cache-Control: public, no-transform, max-age='.$expires);
header('Expires: ' . gmdate('D, d M Y H:i:s', time()+$expires) . ' GMT');
Header('Pragma: cache'); Header('Pragma: cache');
Header('ETag: '.$etag); Header('ETag: '.$etag);
@ -57,13 +49,10 @@ if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == $
common::egw_exit(); common::egw_exit();
} }
if (!in_array($_GET['app'], translation::$instance_specific_translations)) translation::add_app($_GET['app'], $_GET['lang']);
if (!count(translation::$lang_arr))
{ {
translation::add_app($_GET['app'], $_GET['lang']); translation::add_app($_GET['app'], 'en');
if (!count(translation::$lang_arr))
{
translation::add_app($_GET['app'], 'en');
}
} }
$content = 'egw.set_lang_arr("'.$_GET['app'].'", '.json_encode(translation::$lang_arr).');'; $content = 'egw.set_lang_arr("'.$_GET['app'].'", '.json_encode(translation::$lang_arr).');';