node module, for instance, has:

function node_fieldable_info() {
  $return = array(
    'node' => array(
      'name' => t('Node'),
      ...
    ),
  );
  return $return;
}

This is wrong, since those informations are (persistently) cached. The cached info will contain the string localized in the language for the page that triggered the cache refresh.

I'm not sure what's the core pattern to make those strings translatable, though.

Affected hooks:
hook_fieldable_info()
hook_field_info()
hook_field_widget_info()
hook_field_formatter_info()
hook_field_build_modes() - although that information is currently not persistently cached, it might be when #502522: Allow drupal_alter() on the various Field API declarative hooks gets in and this hook can be merged with hook_fieldable_info().

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

yched’s picture

tagging

yched’s picture

Title: t()in Field API info hooks » translated strings in cached _info() hooks
Component: field system » other
Status: Active » Needs review
FileSize
2.63 KB

This is a more general problem. It affects field API, but also the recently committed Imagecache API.
Note that aggregator, actions, and the current state of #113614: Add centralized token/placeholder substitution to core also have t()s in their _info() hooks, but those don't get persistently cached.

FWIW, CCK D6 and apparently hook_views_data() in Views D6 are also affected - just to point that it's a quite common pattern. Not sure of the best way to solve this.

Attached patch fixes field and imagecache info by splitting cached data per language.

webchick’s picture

subscribing for now.

Berdir’s picture

menu does solve it with the title callback. I think a solution is to move it up to somewhere where it does not get cached, and use non-translated strings in those _info hooks.

fago’s picture

Moving out the t() calls would be a way to go, but the translations template extractor won't find the strings any more. Currently it has extra detects hook_menu, but we could try to solve that in a more generic way instead.

fago’s picture

Note: The recently introduced hook_entity_info() is also affected of this problem.

Frando’s picture

We could add a do-nothing function around the strings that just makes the translation extractor find it, and then translate at display time by passing the variable into t().

So in the _info hooks you'd have

function node_entity_info() {
  $return = array(
    'node' => array(
      'name' => te('Node'),

With function te() being something like

function te($arg) {
  return $arg;
}

The template extractor would have to be extended to catch all strings in te().

And at display time you'd do

  print t($info['node']['name']);
jp.stacey’s picture

The original issue description refers to a hook (node_fieldable_info) that I think no longer exists.

Right now, _field_info_collate_types calls and caches a structured array which is the result of iterating over the following hooks:

  • hook_field_info
  • hook_widget_info
  • hook_field_formatter_info
  • hook_entity_info

I have re-rolled yched's patch above for the current versions of _field_info_collate_types and image_effect_definitions, and tested on HEAD. The language-specific caches are created and made available to the relevant user.

One complication I can think of is that calling _field_info_collate_types with $reset = TRUE clears all cached copies, but only repopulates the version corresponding to the current user's language. Shouldn't be a problem in practice?

Please test some more!

fago’s picture

Well I like the solution of Frando above - that way we could avoid having a lot of duplicated caches. Also we'd save some potentially costly cache rebuilds. However I'd prefer a notion not involving PHP execution e.g. comments like /*t*/ 'Node' /*t*/ - but that's ugly. te() is looking much better and it's easy to deal with for potx.

yched’s picture

re jp.stacey #8:

calling _field_info_collate_types with $reset = TRUE clears all cached copies, but only repopulates the version corresponding to the current user's language. Shouldn't be a problem in practice?

Nope, _field_info_collate_types(TRUE) clears cached copies and doesn't rebuild any. The will be rebuild the next time they are needed. No issues there. Thanks for the reroll !

Re frando / fago: I'm not sure many t($foo) in code is a good trade for duplicated cached info ?
I briefly talked with Gabor, he approved the duplicate cache approach.

yched’s picture

now also affect entity_get_info() / hook_entity_info().

sun’s picture

Title: translated strings in cached _info() hooks » Translated strings are cached in _info() hooks
Component: other » language system
Priority: Normal » Critical
Issue tags: -drupalconparis2009, -drupalconsprint +i18n, +i18n sprint, +D7 API clean-up

This is very critical, because this will break multilingual sites.

A commenting standard won't fly, because developers will get it wrong.

A no-op function could be considered and doesn't cost too much. However, it would have to be complemented by a different function than t() to translate those strings, because potx has to warn about usage of $variables in t().

We perhaps also want to differ between stuff that makes sense to cache per language. Menu (tree) links, for example, are cached by language now. However, caching image styles/effects per language would not make any sense.

fago’s picture

well we could also do a cacheable::t(), which returns a small wrapper object using __toString() to run t() on output. Would be pretty transparent and allow use to just cache one version, though I'm not sure whether the overhead of wrapper objects for something that simple as strings is feasible?

catch’s picture

Status: Needs review » Needs work

The te() option seems very reasonable to me.

Also the current patch contains:

+    cache_clear_all('field_info_types:', 'cache_field', TRUE);

with no language code, so even if we end up going with that (would rather not since this is a complete duplication of large arrays just for a couple of t() calls) the patch here needs work.

webchick’s picture

te() is an API change and a major DrupalWTF one at that, since t() alone is more than confusing enough, let alone more than one possible wrapper (we already have st()).

I don't quite understand why this is needed. Menus run into this same thing, and the solution is simply not to wrap titles/descriptions in t(). Can't we make the rule here?

According to #10, Gabor is on board with the patch in #8. This is also an API change to a bunch of cache_clear calls, but this affects far fewer module developers than every single _info() hook.

catch’s picture

Menus run into this same thing, and the solution is simply not to wrap titles/descriptions in t(). Can't we make the rule here?

Yes we could do this, I think it means i18n module would need to handle entities and some other info hooks separately in D7, I think that makes the most sense though.

sun’s picture

I'm not sure whether I understand #14.

In general, however, I'm not sure whether we shouldn't prefer regular t() usage everywhere (too late to change hook_menu() & co, but anyway)... saves us a couple of t() calls on every page?

+++ modules/field/field.info.inc	5 Sep 2009 09:40:50 -0000
@@ -61,16 +61,21 @@ function _field_info_cache_clear() {
+  // The informations contain already-translated strings, so we have to cache
+  // and retrieve them based on the translation language

+++ modules/image/image.module	5 Sep 2009 09:40:50 -0000
@@ -622,10 +622,16 @@ function image_style_path($style_name, $
+  // The informations contain translated strings, and are thus cached by
+  // language.

1) s/informations/information/

2) Missing period.

3) Not sure whether those comments are needed in the first place.

Powered by Dreditor.

yched’s picture

Status: Needs work » Needs review
FileSize
4.56 KB

re @catch #14:
+ cache_clear_all('field_info_types:', 'cache_field', TRUE);
Yup, when the cache is cleared, it needs to be cleared for all languages. Added a comment.

re @webchick #15:

Menus run into this same thing, and the solution is simply not to wrap titles/descriptions in t(). Can't we make the rule here ?

But menu.inc doing t($item['title']) and t($item['description']) relies on the pot extractor knowing that it needs to parse hook_menu() (and hook_perm(), apparently) and extract the strings in the correct keys.
Using the same mechanism here would mean much more special cases for potx :
hook_field_info()
hook_field_formatter_info()
hook_field_widget_info()
hook_field_storage_info()
hook_image_effect_info()
hook_entity_info()
And for each hook, it needs to know the 'translatable' keys. That's pretty tight coupling.
It also doesn't apply as a pattern for other hook_foobar_info() hooks possibly defined by contrib modules, unless poor potx tries to run behind them all.

This is also an API change to a bunch of cache_clear calls, but this affects far fewer module developers than every single _info() hook.

Not sure I get you - approach in patch #8 is no API change.

For now, rerolled patch, cleaned up the comments a little, and also included entity_get_info() in the mix, as per #11 (see node_entity_info()).

yched’s picture

fago’s picture

>And for each hook, it needs to know the 'translatable' keys. That's pretty tight coupling.

This certainly is no good way to go as there might be much more hooks that store translatable strings. In fact the same problem applies to the rules2 hooks and any other contrib that's going to cache its info data.

plach’s picture

Component: language system » locale.module

Cleaning-up the "language system" issue queue as per http://cyrve.com/criticals.

yched’s picture

Component: locale.module » base system

Recategorized. This doesn't really belong in locale.module, nor did it belong to language system to begin with.

Unless I'm mistaken, patch #18 (cache info by language separately) is currently the only way forward we have ?

sun’s picture

#18: hook_info_t-503550-18.patch queued for re-testing.

yched’s picture

#18 is green

sun’s picture

Status: Needs review » Reviewed & tested by the community

Alrighty. Looks like the only doable fix, unless we want to defer D7 to 2011.

Dries’s picture

Status: Reviewed & tested by the community » Fixed

Welcome to the wonderful world if i18n and all the complexity it introduces. ;-)

Patch looks good though. Committed to CVS HEAD.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

sun’s picture