While writing the security component for Views Bulk Operations, I needed to create a permission for the execution of each action declared in the system. This would allow the admin to decide which user groups would be able to execute which actions.
In Drupal, permissions are stored as strings. To make a string for each action, that the admin would understand, I decided to use the format "execute [action label] ([action callback])". The label is a human-friendly name while the callback is the name of the action's function. The problem occurred when the action label was translated to another language, or overridden using a module like String Overrides: the permission string no longer looked the same, therefore losing the admin's setting! Not good.
My solution was brute-force: reverse-translate the action label back into its original formulation. It took some digging into Drupal internals, which is always fun to do. Here's the result:
/** * Reverse translation: find English string given translated string. * WARNING: Will not work for strings with params. */ function rt($string) { global $language; $langcode = $language->language; // 1. Lookup custom strings. static $custom_strings; if (!isset($custom_strings[$langcode])) { $custom_strings[$langcode] = variable_get('locale_custom_strings_'. $langcode, array()); } if ($source = array_search($string, $custom_strings[$langcode])) { return $source; } // 2. Lookup locale translations. if (!function_exists('locale') || $langcode == 'en') return $string; if (variable_get('locale_cache_strings', 1) == 1) { // Cache is on: this string is in the static cache for sure since we have its translated version. $locale_t = locale(); if (isset($locale_t[$langcode]) && ($source = array_search($string, $locale_t[$langcode], TRUE))) { return $source; } else { return $string; } } else { // Cache is off: look it up in the database. $source = db_result(db_query("SELECT s.source FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE t.translation = '%s' AND s.textgroup = 'default'", $langcode, $string)); return $source ? $source : $string; } }
As warned, this will not work for strings with % parameters. I don't know what to do in those cases, but as far as action labels are concerned, this shouldn't be a common occurrence. Otherwise, I tested this function with many scenarios and it seems to be working!



Comments
Drupal 7
hopefully it won't be an issue in Drupal 7, with the new hook_permission
Not a good idea...
That's not a good idea, because translation is not a bijection: different source strings can potentially result in the same translated text.
I'm not sure I understand the original issue, but don't you have a unique key available that would be more stable then the action label?
You're right, it's not 100%
You're right, it's not 100% fool-proof.
But because permission strings are their own keys, there wasn't another option, AFAICT. As mentioned by the other poster, hook_permission should solve this issue in D7.
Post new comment