=== modified file 'sites/all/modules/webform/components/grid.inc' --- components/grid.inc 2011-05-22 20:57:28 +0000 +++ components/grid.inc 2011-05-23 15:48:16 +0000 @@ -387,6 +387,31 @@ function _webform_csv_data_grid($compone return $return; } +/** + * Implements _webform_translate_component(). + */ +function _webform_translate_grid($component, $filter = TRUE, $update = FALSE) { + if (!empty($component['value'])) { + $component['value'] = webform_tt("webform:component:{$component['cid']}:value", $component['value'], NULL, $update); + } + + //Translate options + $options = _webform_select_options_from_text($component['extra']['options'],TRUE); + foreach($options as $key => $option){ + $options[$key] = webform_tt("webform:component:{$component['cid']}:option:{$key}", $option, NULL, $update); + } + $component['extra']['options'] = _webform_select_options_to_text($options); + + //Translate questions + $questions = _webform_select_options_from_text($component['extra']['questions'],TRUE); + foreach($questions as $key => $question){ + $questions[$key] = webform_tt("webform:component:{$component['cid']}:question:{$key}", $question, NULL, $update);; + } + $component['extra']['questions'] = _webform_select_options_to_text($questions); + + return $component; +} + function theme_webform_grid($element) { $rows = array(); $header = array(array('data' => '', 'class' => 'webform-grid-question')); === modified file 'sites/all/modules/webform/components/markup.inc' --- components/markup.inc 2011-05-22 20:57:28 +0000 +++ components/markup.inc 2011-05-23 15:49:53 +0000 @@ -70,3 +70,13 @@ function _webform_render_markup($compone function _webform_display_markup($component, $value, $format = 'html') { return array(); } + +/** + * Implements _webform_translate_component(). + */ +function _webform_translate_markup($component, $filter = TRUE, $update = FALSE) { + if (!empty($component['value'])) { + $component['value'] = webform_tt("webform:component:{$component['cid']}:value", $component['value'], NULL, $update); + } + return $component; +} === modified file 'sites/all/modules/webform/components/select.inc' --- components/select.inc 2011-05-22 20:57:28 +0000 +++ components/select.inc 2011-05-23 15:48:15 +0000 @@ -253,6 +253,15 @@ function _webform_edit_validate_options( } /** + * Implements _webform_translate_component(). + */ +function _webform_translate_select($component, $filter = TRUE, $update = FALSE) { + $options = _webform_select_options($component, !$component['extra']['aslist'], $filter); + $component['extra']['options_array'] = _webform_select_options_translate($component, $options, $update); + return $component; +} + +/** * Implements _webform_render_component(). */ function _webform_render_select($component, $value = NULL, $filter = TRUE) { @@ -270,7 +279,7 @@ function _webform_render_select($compone // Convert the user-entered options list into an array. $default_value = $filter ? _webform_filter_values($component['value'], NULL, NULL, NULL, FALSE) : $component['value']; - $options = _webform_select_options($component, !$component['extra']['aslist'], $filter); + $options = empty($component['extra']['options_array']) ? _webform_select_options($component, !$component['extra']['aslist'], $filter) : $component['extra']['options_array']; if ($component['extra']['optrand']) { _webform_shuffle_options($options); @@ -791,6 +800,35 @@ function _webform_select_options($compon } /** + * TODO + */ +function _webform_select_options_translate($component, $options, $update = FALSE) { + if (!webform_tt()) { + return FALSE; + } + + $toptions = array(); + $group_index = 0; + + foreach ($options as $key => $value) { + if (is_array($value)) { + $group = $key; + $group = webform_tt("webform:component:{$component['cid']}:group:$group_index", $group, NULL, $update); + $group_index++; + + foreach ($value as $key => $value) { + $toptions[$group][$key] = webform_tt("webform:component:{$component['cid']}:option:$key", $value, NULL, $update); + } + } + else { + $toptions[$key] = webform_tt("webform:component:{$component['cid']}:option:$key", $value, NULL, $update); + } + } + + return $toptions; +} + +/** * Load Webform select option info from 3rd party modules. */ function _webform_select_options_info() { === modified file 'sites/all/modules/webform/components/textfield.inc' --- components/textfield.inc 2011-05-22 20:57:28 +0000 +++ components/textfield.inc 2011-05-23 15:50:55 +0000 @@ -117,6 +117,21 @@ function _webform_edit_textfield($compon } /** + * Implements _webform_translate_component(). + */ +function _webform_translate_textfield($component, $filter = TRUE, $update = FALSE) { + if (!empty($component['value'])) { + $component['value'] = webform_tt("webform:component:{$component['cid']}:value", $component['value'], NULL, $update); + } + foreach (array('field_prefix', 'field_suffix') as $field) { + if (!empty($component['extra'][$field])) { + $component['extra'][$field] = webform_tt("webform:component:{$component['cid']}:$field", $component['extra'][$field], NULL, $update); + } + } + return $component; +} + +/** * Implements _webform_render_component(). */ function _webform_render_textfield($component, $value = NULL, $filter = TRUE) { === modified file 'sites/all/modules/webform/includes/webform.components.inc' --- includes/webform.components.inc 2011-05-22 20:57:28 +0000 +++ includes/webform.components.inc 2011-05-22 20:58:12 +0000 @@ -626,6 +626,13 @@ function webform_component_edit_form_sub drupal_set_message(t('New component %name added.', array('%name' => $form_state['values']['name']))); } + // Create the translation sources for the component. + webform_component_translate($form_state['values'], TRUE, TRUE); + // TODO + if (webform_translation_supported_type($node)) { + webform_component_translation_sync($node, $form_state['values'], isset($cid)); + } + // Since Webform components have been updated but the node itself has not // been saved, it is necessary to explicitly clear the cache to make sure // the updated webform is visible to anonymous users. @@ -797,6 +804,34 @@ function webform_component_clone(&$node, } /** + * Translate the given component. + * TODO + */ +function webform_component_translate($component, $filter = TRUE, $update = FALSE) { + if (webform_tt()) { + $tcomponent = webform_component_invoke($component['type'], 'translate', $component, $filter, $update); + if (!isset($tcomponent)) { + $tcomponent = $component; + } + $tcomponent['name'] = webform_tt("webform:component:{$component['cid']}:name", $component['name'], NULL, $update); + if (!empty($tcomponent['extra']['description'])) { + $tcomponent['extra']['description'] = webform_tt("webform:component:{$component['cid']}:description", $component['extra']['description'], NULL, $update); + } + } + else { + $tcomponent = $component; + } + return $tcomponent; +} + +/** + * TODO + */ +function webform_component_translation_sync($node, $component, $insert = FALSE) { + webform_translation_sync($node, $component, 'webform_component', $insert); +} + +/** * Check if a component has a particular feature. * * @see hook_webform_component_info() === modified file 'sites/all/modules/webform/includes/webform.emails.inc' --- includes/webform.emails.inc 2011-05-22 20:57:28 +0000 +++ includes/webform.emails.inc 2011-05-22 20:58:12 +0000 @@ -441,7 +441,8 @@ function webform_email_edit_form_submit( $excluded = array_diff(array_keys($form_state['values']['node']->webform['components']), $included); $email['excluded_components'] = $excluded; - if (empty($form_state['values']['eid'])) { + $insert = empty($form_state['values']['eid']); + if ($insert) { drupal_set_message(t('Email settings added.')); $form_state['values']['eid'] = webform_email_insert($email); } @@ -449,11 +450,71 @@ function webform_email_edit_form_submit( drupal_set_message(t('Email settings updated.')); webform_email_update($email); } + if (webform_translation_supported_type($node)) { + // TODO: if $insert = TRUE, $email['eid'] is not set. + // This means webform_email_insert() is not guaranteed to assign equal eids to the newly + // saved e-mails, which may cause problems in the future when updating them. + webform_email_translation_sync($node, $email, $insert); + } $form_state['redirect'] = array('node/' . $form_state['values']['node']->nid . '/webform/emails'); } /** + * Synchronize e-mails across translated webforms + */ +function webform_email_translation_sync($node, $email, $insert = FALSE) { + // TODO: perhaps merge back into webform_translation_sync() + //webform_translation_sync($node, $email, 'webform_email', $insert); + $store_callback = 'webform_email'; + + if ($translations = translation_node_get_translations($node->tnid)) { + unset($translations[$node->language]); + $store_callback .= '_'. ($insert ? 'insert' : 'update'); + $count = 0; + + foreach ($translations as $langcode => $translation) { + $new_data = $email; + if (!$insert) { + // Do not bluntly overwrite language-specific texts in all translations, + // because then we can never have different texts: + $old_data = webform_email_load($email['eid'], $translation->nid); + + // $email['template'] is not language-specific if 'default'. + $old_langspec = ($old_data['template'] != 'default'); + $new_langspec = ($new_data['template'] != 'default'); + if ($old_langspec || $new_langspec) { + if ($old_langspec && !$new_langspec) { + // We're not 100% sure what the right thing is to do. Tell the user. + drupal_set_message(t("The '@lang' version of this e-mail has language specific text, which was not overwritten.", array('@lang' => $langcode))); + } + $new_data['template'] = $old_data['template']; + $new_data['format'] = $old_data['format']; + } + // subject / from_name is not language-specific if 'default' or numeric. + foreach (array('subject', 'from_name') as $field) { + $old_langspec = (!is_numeric($old_data[$field]) && $old_data[$field] != 'default'); + $new_langspec = (!is_numeric($new_data[$field]) && $new_data[$field] != 'default'); + if ($old_langspec || $new_langspec) { + if ($old_langspec && !$new_langspec) { + drupal_set_message(t("The '@lang' version of this e-mail has a language specific '@field' field, which was not overwritten.", + array('@lang' => $langcode, '@field' => $field))); + } + $new_data[$field] = $old_data[$field]; + } + } + } + + $new_data['nid'] = $translation->nid; + $store_callback($new_data); + $count++; + } + + drupal_set_message(format_plural($count, 'One webform translation has been synchronized.', 'All @count webform translations have been synchronized.')); + } +} + +/** * Form for deleting an e-mail setting. */ function webform_email_delete_form($form_state, $node, $email) { === modified file 'sites/all/modules/webform/includes/webform.pages.inc' --- includes/webform.pages.inc 2011-05-22 20:57:28 +0000 +++ includes/webform.pages.inc 2011-05-22 20:58:12 +0000 @@ -289,6 +289,22 @@ function webform_configure_form_submit($ node_save($node); + if (webform_translation_supported_type($node)) { + // Don't synchronize submit_text and confirmation; these are language specific strings. + webform_node_translation_sync($node, array( + 'redirect_url', + 'status', + 'roles', + 'block', + 'teaser', + 'allow_draft', + 'auto_save', + 'submit_limit', + 'submit_interval', + 'submit_notice', + )); + } + drupal_set_message(t('The form settings have been updated.')); } === modified file 'sites/all/modules/webform/includes/webform.report.inc' --- includes/webform.report.inc 2011-05-22 20:57:28 +0000 +++ includes/webform.report.inc 2011-05-22 20:58:12 +0000 @@ -16,6 +16,11 @@ module_load_include('inc', 'webform', 'i function webform_results_submissions($node, $user_filter, $pager_count) { global $user; + $nid = $node->nid; + if (webform_translation_supported_type($node)) { + $node = node_load($node->tnid); + } + if (isset($_GET['results']) && is_numeric($_GET['results'])) { $pager_count = $_GET['results']; } @@ -69,6 +74,11 @@ function webform_results_submissions($no $rows[] = $row; } + // Restore the original node if no submission is found. + if (empty($rows) && webform_translation_supported_type($node)) { + $node = node_load($nid); + } + $element['#theme'] = 'webform_results_submissions'; $element['#node'] = $node; $element['#submissions'] = $submissions; @@ -166,6 +176,10 @@ function template_preprocess_webform_res * Create a table containing all submitted values for a webform node. */ function webform_results_table($node, $pager_count = 0) { + if (webform_translation_supported_type($node)) { + $node = node_load($node->tnid); + } + if (isset($_GET['results']) && is_numeric($_GET['results'])) { $pager_count = $_GET['results']; } @@ -283,8 +297,8 @@ function webform_results_clear_form($for } function webform_results_clear_form_submit($form, &$form_state) { - webform_results_clear($form_state['values']['nid']); $node = node_load($form_state['values']['nid']); + webform_results_clear(webform_translation_supported_type($node) ? $node->tnid : $node->nid); $title = $node->title; $message = t('Webform %title entries cleared.', array('%title' => $title)); @@ -300,6 +314,10 @@ function webform_results_download_form(& module_load_include('inc', 'webform', 'includes/webform.export'); module_load_include('inc', 'webform', 'includes/webform.components'); + if (webform_translation_supported_type($node)) { + $node = node_load($node->tnid); + } + $form = array(); $form['node'] = array( @@ -626,6 +644,10 @@ function webform_results_download($node, * "Other" values within a select list. */ function webform_results_analysis($node, $sids = array(), $analysis_component = NULL) { + if (webform_translation_supported_type($node)) { + $node = node_load($node->tnid); + } + if (!is_array($sids)) { $sids = array(); } === modified file 'sites/all/modules/webform/webform.module' --- webform.module 2011-05-22 20:57:28 +0000 +++ webform.module 2011-05-23 15:53:18 +0000 @@ -1163,18 +1163,7 @@ function webform_node_load($node) { $result = db_query('SELECT * FROM {webform_component} WHERE nid = %d ORDER BY weight, name', $node->nid); while ($c = db_fetch_array($result)) { $component =& $additions['webform']['components'][$c['cid']]; - $component['nid'] = $node->nid; - $component['cid'] = $c['cid']; - $component['form_key'] = $c['form_key'] ? $c['form_key'] : $c['cid']; - $component['name'] = t($c['name']); - $component['type'] = $c['type']; - $component['value'] = $c['value']; - $component['extra'] = unserialize($c['extra']); - $component['mandatory'] = $c['mandatory']; - $component['pid'] = $c['pid']; - $component['weight'] = $c['weight']; - - webform_component_defaults($component); + webform_component_init($component, $c); } // Organize the components into a fieldset-based order. @@ -1188,6 +1177,24 @@ function webform_node_load($node) { } /** + * TODO + */ +function webform_component_init(&$component, $data) { + $component['nid'] = $data['nid']; + $component['cid'] = $data['cid']; + $component['form_key'] = $data['form_key'] ? $data['form_key'] : $data['cid']; + $component['name'] = $data['name']; + $component['type'] = $data['type']; + $component['value'] = $data['value']; + $component['extra'] = unserialize($data['extra']); + $component['mandatory'] = $data['mandatory']; + $component['pid'] = $data['pid']; + $component['weight'] = $data['weight']; + + webform_component_defaults($component); +} + +/** * Implements hook_link(). * Always add a "view form" link. */ @@ -1862,6 +1869,9 @@ function _webform_client_form_rule_check function _webform_client_form_add_component($node, $component, $component_value, &$parent_fieldset, &$form, $form_state, $submission, $format = 'form', $page_num = 0, $filter = TRUE) { $cid = $component['cid']; + // Translate the current component. + $component = webform_component_translate($component, $filter); + // Load with submission information if necessary. if ($format != 'form') { // This component is display only. @@ -2144,7 +2154,20 @@ function webform_client_form_submit($for return; } - $node = $form['#node']; + $node = node_load($form_state['values']['details']['nid']); + if (webform_translation_supported_type($node) && $node->tnid != $form_state['values']['details']['nid']) { + // Get webform components from the 'translation original' + // TODO: check whether that's necessary? patch #245424-128 does it this way... + $tnode = node_load($node->tnid); + // For webform_submission_send_mail(), use original node too -- but with the language specific emails. + // ATTENTION: potential problem. E-mail fields can refer to component ids, which + // are not yet guaranteed to be the same in node translations? + $tnode->webform['emails'] = $node->webform['emails']; + } + else { + $tnode = $node; + } + $sid = $form_state['values']['details']['sid'] ? (int) $form_state['values']['details']['sid'] : NULL; // Check if user is submitting as a draft. @@ -2153,12 +2176,12 @@ function webform_client_form_submit($for if (!$sid) { // Create a submission object. $submission = (object) array( - 'nid' => $node->nid, + 'nid' => $tnode->nid, 'uid' => $user->uid, 'submitted' => time(), 'remote_addr' => ip_address(), 'is_draft' => $is_draft, - 'data' => webform_submission_data($node, $form_state['values']['submitted']), + 'data' => webform_submission_data($tnode, $form_state['values']['submitted']), ); } else { @@ -2176,33 +2199,33 @@ function webform_client_form_submit($for // Save the submission to the database. if (!$sid) { // No sid was found thus insert it in the dataabase. - $form_state['values']['details']['sid'] = $sid = webform_submission_insert($node, $submission); + $form_state['values']['details']['sid'] = $sid = webform_submission_insert($tnode, $submission); $form_state['values']['details']['is_new'] = TRUE; // Set a cookie including the server's submission time. // The cookie expires in the length of the interval plus a day to compensate for different timezones. if (variable_get('webform_use_cookies', 0)) { - $cookie_name = 'webform-' . $node->nid; + $cookie_name = 'webform-' . $tnode->nid; $time = time(); - setcookie($cookie_name . '[' . $time . ']', $time, $time + $node->webform['submit_interval'] + 86400); + setcookie($cookie_name . '[' . $time . ']', $time, $time + $tnode->webform['submit_interval'] + 86400); } // Save session information about this submission for anonymous users, // allowing them to access or edit their submissions. if (!$user->uid && user_access('access own webform submissions')) { - $_SESSION['webform_submission'][$form_state['values']['details']['sid']] = $node->nid; + $_SESSION['webform_submission'][$form_state['values']['details']['sid']] = $tnode->nid; } } else { // Sid was found thus update the existing sid in the database. - webform_submission_update($node, $submission); + webform_submission_update($tnode, $submission); $form_state['values']['details']['is_new'] = FALSE; } // Check if this form is sending an email. if (!$is_draft && !$form_state['values']['details']['finished']) { - $submission = webform_get_submission($node->nid, $sid, TRUE); - webform_submission_send_mail($node, $submission); + $submission = webform_get_submission($tnode->nid, $sid, TRUE); + webform_submission_send_mail($tnode, $submission); } // Strip out empty tags added by WYSIWYG editors if needed. @@ -3387,11 +3410,48 @@ function webform_strtotime($date) { } /** + * Implements hook_locale(). + */ +function webform_locale($op = 'groups', $group = NULL) { + switch ($op) { + case 'groups': + return array('webform' => t('Webform')); + case 'info': + $info['webform']['refresh callback'] = 'webform_locale_refresh'; + $info['webform']['format'] = FALSE; + return $info; + } +} + +/** + * Refresh locale strings. + */ +function webform_locale_refresh() { + module_load_include('inc', 'webform', 'includes/webform.components'); + + $result = db_query('SELECT * FROM {webform_component}'); + while ($c = db_fetch_array($result)) { + $component = array(); + webform_component_init($component, $c); + webform_component_translate($component, TRUE, TRUE); + } + + return TRUE; +} + +/** * Wrapper function for tt() if i18nstrings enabled. */ -function webform_tt($name, $string, $langcode = NULL, $update = FALSE) { - if (function_exists('tt')) { - return tt($name, $string, $langcode, $update); +function webform_tt($name = NULL, $string = NULL, $langcode = NULL, $update = FALSE) { + $translate = function_exists('i18nstrings'); + if (empty($name)) { + return $translate; + } + elseif ($translate) { + if ($update) { + i18nstrings_update($name, $string); + } + return i18nstrings($name, $string, $langcode); } else { return $string; @@ -3399,6 +3459,54 @@ function webform_tt($name, $string, $lan } /** + * TODO + */ +function webform_translation_supported_type($node) { + // TODO: content type option + return webform_tt() && !empty($node->tnid); +} + +/** + * TODO + */ +function webform_translation_sync($node, $data, $store_callback, $insert = FALSE) { + if ($translations = translation_node_get_translations($node->tnid)) { + unset($translations[$node->language]); + $store_callback .= '_'. ($insert ? 'insert' : 'update'); + $count = 0; + + foreach ($translations as $langcode => $translation) { + $data['nid'] = $translation->nid; + $store_callback($data); + $count++; + } + + drupal_set_message(format_plural($count, 'One webform translation has been synchronized.', 'All @count webform translations have been synchronized.')); + } +} + +/** + * Synchronize configuration settings across translated webforms + */ +function webform_node_translation_sync($node, $settings) { + if ($translations = translation_node_get_translations($node->tnid)) { + unset($translations[$node->language]); + $count = 0; + + foreach ($translations as $langcode => $translation) { + $translation = node_load($translation->nid); + foreach ($settings as $setting) { + $translation->webform[$setting] = $node->webform[$setting]; + } + node_save($translation); + $count++; + } + + drupal_set_message(format_plural($count, 'One webform translation has been synchronized.', 'All @count webform translations have been synchronized.')); + } +} + +/** * Check if any available HTML mail handlers are available for Webform to use. */ function webform_email_html_capable() {