? views (copy).module
? views-locale-api.module
? views-localization.patch
Index: views.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/views.module,v
retrieving revision 1.324
diff -u -p -r1.324 views.module
--- views.module 8 Jan 2009 20:01:00 -0000 1.324
+++ views.module 16 Jan 2009 19:27:48 -0000
@@ -1144,4 +1144,220 @@ function views_views_exportables($op = '
function views_microtime() {
list($usec, $sec) = explode(' ', microtime());
return (float)$sec + (float)$usec;
-}
\ No newline at end of file
+}
+
+/**
+ * Process a string for translation.
+ *
+ * @param $string
+ * The string to be handled.
+ * @param $keys
+ * An array of keys to identify the string. Generally constructed from
+ * view name, display_id, and a property, e.g., 'header'.
+ * @param $op
+ * Operation. Valid values are:
+ * - 'get': retrieve an existing translation
+ * - 'save': save a source string
+ * - 'delete': delete a source string (and any translations).
+ */
+function views_localize_string($string, $keys, $op) {
+ $handlers = views_localization_handlers('callbacks');
+ $handler = views_localization_handler();
+ $callback = $handlers[$handler][$op];
+ if (empty($callback)) {
+ return $string;
+ }
+ elseif ($handler == 'core') {
+ return $callback($string);
+ }
+ else {
+ return $callback($string, $keys, $op);
+ }
+}
+
+/**
+ * Load an existing translation.
+ *
+ * @param $string
+ * The string to be translated.
+ * @param $keys
+ * An array of keys to identify the string. Generally constructed from
+ * view name, display_id, and a property, e.g., 'header'.
+ */
+function views_get_localized_string($string, $keys) {
+ return views_localize_string($string, $keys, 'get');
+}
+
+/**
+ * Save a string for translation.
+ *
+ * @param $string
+ * The string to be saved.
+ * @param $keys
+ * An array of keys to identify the string. Generally constructed from
+ * view name, display_id, and a property, e.g., 'header'.
+ */
+function views_save_localized_string($string, $keys) {
+ views_localize_string($string, $keys, 'save');
+}
+
+/**
+ * Delete an existing translation.
+ *
+ * @param $string
+ * The string to be deleted.
+ * @param $keys
+ * An array of keys to identify the string. Generally constructed from
+ * view name, display_id, and a property, e.g., 'header'.
+ */
+function views_delete_localized_string($string, $keys) {
+ views_localize_string($string, $keys, 'delete');
+}
+
+/**
+ * Return an array of available handlers for localization.
+ *
+ * Modules may implement hook_localization_handlers_alter() to alter the
+ * available handlers.
+ *
+ * @param $key
+ * A key to use for the returned values. Valid keys are 'title' for
+ * handler titles and 'callbacks' for handler callback functions.
+ * If null, a nested array with these two keys is returned.
+ *
+ * @return
+ * An array of handlers with the following keys:
+ * - 'title': the title of the handler, suitable for display in a form radios
+ * element.
+ * - 'callbacks': an array of function name callbacks with the following keys:
+ * - 'get': retrieve an existing translation
+ * - 'save': save a string for translation
+ * - 'delete': delete a source string (and any translations)
+ */
+function views_localization_handlers($key = NULL) {
+ static $handlers = array();
+
+ if (empty($handlers)) {
+ $handlers['none'] = array(
+ 'title' => t('None: do not pass admin strings for translation.'),
+ 'callbacks' => array(
+ // A FALSE callback will be skipped and the original string returned
+ // unmodified.
+ 'get' => FALSE,
+ 'save' => FALSE,
+ 'delete' => FALSE,
+ ),
+ );
+ $handlers['core'] = array(
+ 'title' => t("Drupal core t() function: not recommended, as it doesn't support updates to existing strings."),
+ 'callback' => array(
+ 'get' => 't',
+ 'save' => 't',
+ // Delete not supported.
+ 'delete' => FALSE,
+ ),
+ );
+ if (module_exists('i18nstrings')) {
+ $handlers['i18nstrings'] = array(
+ 'title' => t('String translation: Use the string translation module. Strings will be added to the Views group in the Translate interface page.', array('!path' => url('admin/build/translate/search'))),
+ 'callbacks' => array(
+ 'get' => 'views_localization_tt',
+ 'save' => 'views_localization_tt',
+ 'delete' => 'views_localization_remove_string',
+ ),
+ );
+ }
+ else {
+ $handlers['core']['title'] .= ' ' . t('If you need to translate Views labels into other languages, consider installing the Internationalization package\'s Strings translation module.', array('!path' => url('http://drupal.org/project/i18n', array('absolute' => TRUE))));
+ }
+
+ // Allow other modules to add or change handlers.
+ drupal_alter('localization_handlers', $handlers);
+ }
+
+ if ($key) {
+ $return = array();
+ foreach ($handlers as $handler => $data) {
+ $return[$handler] = $data[$key];
+ }
+ return $return;
+ }
+ return $handlers;
+}
+
+/**
+ * Localization callback. Wrapper for i18nstrings tt() function.
+ *
+ * @param $string
+ * The string to be translated.
+ * @param $keys
+ * An array of keys to identify the string. Generally constructed from
+ * view name, display_id, and a property, e.g., 'header'.
+ * @param $update
+ * Boolean, whether to register an update.
+ */
+function views_localization_tt($string, $keys, $op) {
+ // Prevent an error if i18nstrings has been disabled.
+ if (!module_exists('i18nstrings')) {
+ return $string;
+ }
+ $location = implode(':', $keys);
+ switch ($op) {
+ case 'save':
+ tt('views:' . $location, $string, NULL, TRUE);
+ return;
+ case 'get':
+ return tt('views:' . $location, $string);
+ }
+}
+
+/**
+ * Localization callback. Wrapper for i18nstrings i18nstrings_remove_string()
+ * function.
+ *
+ * @param $string
+ * The string to be translated.
+ * @param $keys
+ * An array of keys to identify the string. Generally constructed from
+ * view name, display_id, and a property, e.g., 'header'.
+ * @param $update
+ * Boolean, whether to register an update.
+ */
+function views_localization_remove_string($string, $keys) {
+ // Prevent an error if i18nstrings has been disabled.
+ if (!module_exists('i18nstrings')) {
+ return;
+ }
+ $location = implode(':', $keys);
+ return i18nstrings_remove_string('views:' . $location, $string, NULL, $update);
+}
+
+/**
+ * Helper function to return the localization handler for Views.
+ *
+ * @return
+ * String, the localization handler to be used by Views.
+ *
+ * @todo: switch default to 'none'? Not done yet to avoid breaking existing
+ * translations in Views 2 6.x installs.
+ */
+function views_localization_handler() {
+ // Default to i18nstrings if it exists, otherwise to 'core'.
+ return variable_get('views_localization_handler', module_exists('i18nstrings') ? 'i18nstrings' : 'core');
+}
+
+/**
+ * Implementation of hook_locale().
+ *
+ * @todo: implement i18nstrings 'refresh' op?
+ */
+function views_locale($op = 'groups') {
+ // i18nstrings uses the locale system.
+ if (views_localization_handler() == 'i18nstrings') {
+ switch ($op) {
+ case 'groups':
+ return array('views' => t('Views'));
+ }
+ }
+}
+
Index: views_ui.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/views_ui.module,v
retrieving revision 1.108
diff -u -p -r1.108 views_ui.module
--- views_ui.module 3 Dec 2008 02:39:45 -0000 1.108
+++ views_ui.module 16 Jan 2009 19:27:49 -0000
@@ -233,6 +233,10 @@ function views_ui_cache_load($name) {
// Check to see if someone else is already editing this view.
global $user;
$view->locked = db_fetch_object(db_query("SELECT s.uid, v.updated FROM {views_object_cache} v INNER JOIN {sessions} s ON v.sid = s.sid WHERE s.sid != '%s' and v.name = '%s' and v.obj = 'view' ORDER BY v.updated ASC", session_id(), $view->name));
+ // Set a flag to indicate that this view is being edited.
+ // This flag will be used e.g. to determine whether strings
+ // should be localized.
+ $view->editing = TRUE;
}
}
Index: includes/admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/includes/admin.inc,v
retrieving revision 1.150
diff -u -p -r1.150 admin.inc
--- includes/admin.inc 7 Jan 2009 21:52:00 -0000 1.150
+++ includes/admin.inc 16 Jan 2009 19:27:56 -0000
@@ -2725,6 +2725,16 @@ function views_ui_admin_tools() {
'#default_value' => variable_get('views_no_javascript', FALSE),
);
+ if (module_exists('locale')) {
+ $form['views_localization_handler'] = array(
+ '#type' => 'radios',
+ '#title' => t('Localization handler'),
+ '#description' => t("Select a handler for translation of Views data like header, footer, and empty text."),
+ '#options' => views_localization_handlers('title'),
+ '#default_value' => views_localization_handler(),
+ );
+ }
+
$regions = system_region_list(variable_get('theme_default', 'garland'));
$form['views_devel_region'] = array(
Index: includes/base.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/includes/base.inc,v
retrieving revision 1.2
diff -u -p -r1.2 base.inc
--- includes/base.inc 6 Jun 2008 19:29:03 -0000 1.2
+++ includes/base.inc 16 Jan 2009 19:27:56 -0000
@@ -76,7 +76,7 @@ class views_object {
* Unpack options over our existing defaults, drilling down into arrays
* so that defaults don't get totally blown away.
*/
- function unpack_options(&$storage, $options, $definition = NULL) {
+ function unpack_options(&$storage, $options, $definition = NULL, $localization_keys = array()) {
if (!is_array($options)) {
return;
}
@@ -93,8 +93,19 @@ class views_object {
$this->unpack_options($storage[$key], $value, isset($definition[$key]) ? $definition[$key] : array());
}
- else if (!empty($definition[$key]['translatable']) && !empty($value)) {
- $storage[$key] = t($value);
+ // Don't localize strings during editing. When editing, we need to work with
+ // the original data, not the translated version.
+ else if (!$this->view->editing && !empty($definition[$key]['translatable']) && !empty($value)) {
+ // If the view is normal or overridden, use admin string translation.
+ if (isset($this->view->type) && in_array($this->view->type, array('Normal', 'Overridden'))) {
+ // The $keys array is built from the view name, any localization keys
+ // sent in, and the name of the property being processed.
+ $storage[$key] = views_get_localized_string($value, array_merge(array($this->view->name), $localization_keys, array($key)));
+ }
+ // Otherwise, use t().
+ else {
+ $storage[$key] = t($value);
+ }
}
else {
$storage[$key] = $value;
Index: includes/view.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/includes/view.inc,v
retrieving revision 1.146
diff -u -p -r1.146 view.inc
--- includes/view.inc 8 Jan 2009 00:29:54 -0000 1.146
+++ includes/view.inc 16 Jan 2009 19:28:00 -0000
@@ -23,6 +23,7 @@ class view extends views_db_object {
// State variables
var $built = FALSE;
var $executed = FALSE;
+ var $editing = FALSE;
var $args = array();
var $build_info = array();
@@ -1303,6 +1304,9 @@ class view extends views_db_object {
$this->_save_rows($key);
}
+ // Save data for translation.
+ $this->save_locale_strings();
+
cache_clear_all('views_urls', 'cache_views');
cache_clear_all(); // clear the page cache as well.
}
@@ -1328,6 +1332,8 @@ class view extends views_db_object {
return;
}
+ $this->delete_locale_strings();
+
db_query("DELETE FROM {views_view} WHERE vid = %d", $this->vid);
// Delete from all of our subtables as well.
foreach ($this->db_objects() as $key) {
@@ -1504,6 +1510,76 @@ class view extends views_db_object {
return $errors ? $errors : TRUE;
}
+
+ /**
+ * Send strings for localization.
+ */
+ function save_locale_strings() {
+ $this->process_locale_strings('save');
+ }
+
+ /**
+ * Delete localized strings.
+ */
+ function delete_locale_strings() {
+ $this->process_locale_strings('delete');
+ }
+
+ /**
+ * Process strings for localization or deletion.
+ */
+ function process_locale_strings($op) {
+ if ($this->display && is_array($this->display)) {
+ foreach ($this->display as $display_id => $display) {
+ $translatable = array();
+ // Special handling for display title.
+ if (isset($display->display_title)) {
+ $translatable['display_title'] = $display->display_title;
+ }
+ $this->unpack_translatable($translatable, $display_id, $display->display_options);
+ foreach ($translatable as $property => $string) {
+ switch ($op) {
+ case 'delete':
+ views_delete_localized_string($string, array($this->name, $display_id, $property));
+ break;
+ case 'save':
+ views_save_localized_string($string, array($this->name, $display_id, $property));
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Unpack translatable properties and their values.
+ */
+ function unpack_translatable(&$translatable, $display_id, $options, $definition = NULL) {
+
+ if (!is_array($options)) {
+ return;
+ }
+
+ // Ensure we have displays with handlers.
+ $this->init_display();
+
+ if (!isset($definition)) {
+ $definition = $this->display[$display_id]->handler->option_definition();
+ }
+
+ foreach ($options as $key => $value) {
+ if (is_array($value)) {
+ $this->unpack_translatable($translatable, $display_id, $value, isset($definition[$key]) ? $definition[$key] : array());
+ }
+ else if (!empty($definition[$key]['translatable']) && !empty($value)) {
+ // If the view is normal or overridden, use admin string translation.
+ // Otherwise t() will handle it.
+ if (isset($this->type) && in_array($this->type, array('Normal', 'Overridden'))) {
+ $translatable[$key] = $value;
+ }
+ }
+ }
+ }
}
/**
Index: plugins/views_plugin_display.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/plugins/views_plugin_display.inc,v
retrieving revision 1.18
diff -u -p -r1.18 views_plugin_display.inc
--- plugins/views_plugin_display.inc 7 Jan 2009 23:31:13 -0000 1.18
+++ plugins/views_plugin_display.inc 16 Jan 2009 19:28:05 -0000
@@ -40,7 +40,9 @@ class views_plugin_display extends views
unset($options['defaults']);
}
- $this->unpack_options($this->options, $options);
+ // Last argument is an array of keys to be used in identifying
+ // strings for translation.
+ $this->unpack_options($this->options, $options, NULL, array($display->id));
}
function destroy() {