... or somewhere else where $language hasn't been set yet.
I've noticed this on in Drupal 5 but I'm pretty sure it still exists in Drupal 7.
When a module calls the t() function when $locale hasn't been set yet (like in a define()), the locale cache gets rebuilt every page request. This can have a huge performance impact on a site with a lot of translated labels.
The function locale
now does something like:
function locale($string = NULL, $langcode = NULL, $reset = FALSE) {
global $language;
static $locale_t;
if ($reset) {
// Reset in-memory cache.
$locale_t = NULL;
}
if (!isset($string)) {
// Return all cached strings if no string was specified
return $locale_t;
}
$langcode = isset($langcode) ? $langcode : $language->language;
// Store database cached translations in a static var.
if (!isset($locale_t[$langcode])) {
I think it would be safer to check if $language is set in that latest if
:
<code>
function locale($string = NULL, $langcode = NULL, $reset = FALSE) {
global $language;
static $locale_t;
if ($reset) {
// Reset in-memory cache.
$locale_t = NULL;
}
if (!isset($string)) {
// Return all cached strings if no string was specified
return $locale_t;
}
$langcode = isset($langcode) ? $langcode : $language->language;
// Store database cached translations in a static var.
if (!isset($locale_t[$langcode]) && isset($language)) {
Okay, I admit every module should take care of calling t() only when locale is initialized, but this way we can make this a bit safer. Only the buggy t() call gets not translated and all the rest is translated well.
Comment | File | Size | Author |
---|---|---|---|
#27 | locale-cache-rebuild-320686-27.patch | 976 bytes | cburschka |
#24 | locale-cache-rebuild-320686-24.patch | 971 bytes | cburschka |
#23 | locale-cache-rebuild-320686-23.patch | 878 bytes | cburschka |
#5 | 320686-global-t.patch | 816 bytes | davyvdb |
Comments
Comment #1
davyvdb CreditAttribution: davyvdb commentedBTW. You can find an example of this at http://drupal.org/node/320682.
This was a bug which was VERY hard to find.
Comment #2
Damien Tournoud CreditAttribution: Damien Tournoud commentedWell, the true answer is: *don't use t() in a global context*. Gabor lists this as one of the most common mistakes in his cheat sheet.
Requalifying as a documentation problem, the document of t() should be extended to include that in bold.
Comment #3
davyvdb CreditAttribution: davyvdb commentedWhy not put the extra check there? It solves the performance issue gracefully.
Comment #4
alexanderpas CreditAttribution: alexanderpas commentedcan we catch this with the coder module?
Comment #5
davyvdb CreditAttribution: davyvdb commentedTo be honest. The impact on performance is so big, we need to do both imho. There are so many contributed modules available and if some novice users downloads them, he'll never notice this issue.
Comment #6
davyvdb CreditAttribution: davyvdb commentedTagging
Comment #7
jhodgdonIf that is the patch, this is not a documentation issue.
Comment #8
cburschkaTitle should reflect that as well. Is this accurate?
Comment #9
davyvdb CreditAttribution: davyvdb commentedYes sir!
Comment #10
mgifford+1
Patch applies nicely.
Don't see any need to rebuild locale cache when $language is not set
Comment #11
cburschkaThis gets a +1 from me too. The change in the logic makes sense and the code change is clean and simple. Tests are passing as well, so I dare RTBC this.
Even though this could be seen as baby-sitting broken code, I don't think it is. Sanity checks are quite normal, and as this one prevents a pretty nasty slow-down, it's a good idea.
Comment #12
Damien Tournoud CreditAttribution: Damien Tournoud commentedThe check needs to be on $langcode, not $language.
I suggest to make this check on is own, and return in this case.
Comment #13
davyvdb CreditAttribution: davyvdb commentedIt's definitely on $language. That's not initialized yet. It's not a check on input parameters.
Comment #15
alexanderpas CreditAttribution: alexanderpas commentedComment #16
alexanderpas CreditAttribution: alexanderpas commentedhead broke -- resetting status
Comment #18
cburschkaLast test is over a month old. Otherwise, this is probably RTBC.
Comment #21
cburschkaI cannot reproduce the fatal error on DatabaseTaggingTestCase. Let's have another go, then investigate if it happens again.
Comment #22
catchThis is passing now, must have been broken test bot. I don't see any reason not to add the extra check here, IMO this doesn't fall into "dont' babysit broken code" - it makes sense in itself.
However can we get a one-line comment which explains what we're doing and why?
Comment #23
cburschkaHere's a comment.
Comment #24
cburschkaOn second thought, that comment is silly. This one is hopefully a bit better.
Comment #25
catchVery nice.
Comment #26
Dries CreditAttribution: Dries commentedInstead of 'var', let's use 'variable'. Should be quick re-roll.
Comment #27
cburschkaDone, and patched.
Comment #28
catchYep.
Comment #29
webchickCommitted to HEAD!