*/ /** * Translates the component properties that are translatable. * * These are found in under 'translated_strings' in the 'extra' array of the * component, which is build when the component is inserted / updated, or * when all webform strings are updated from * admin/config/regional/translate/i18n_string. * * @param array $element * The FAPI renderable array of the component instance. * @param array $component * The component. */ function _webform_localization_translate_component(&$element, $component) { if (isset($component['extra']['translated_strings']) && is_array($component['extra']['translated_strings'])) { foreach ($component['extra']['translated_strings'] as $name) { $name_list = explode(':', $name); $current_element = &$element; if (strpos($name_list[3], '[') !== FALSE) { // The property is deeper in the renderable array, we must extract the // the place where it is. list ($children, $property) = explode(']#', $name_list[3]); // Remove the '[' from the begining of the string. $children = drupal_substr($children, 1); $children_array = explode('][', $children); foreach ($children_array as $child) { if (isset($current_element[$child])) { $current_element = &$current_element[$child]; } else { continue; } } } else { // Remove the '#' from the begining of the property, for consistency. $property = drupal_substr($name_list[3], 1); } if (strpos($property, '-') !== FALSE) { // If property is array, we extract the key from the property. list ($property, $key) = explode('-', $property); if (isset($current_element['#' . $property][$key])) { $current_element['#' . $property][$key] = i18n_string($name, $current_element['#' . $property][$key], array('sanitize' => FALSE)); } } else { // If we are dealing with option groups. if (isset($name_list[4]) && strpos($name_list[4], '/-') !== FALSE) { $option_group = str_replace('/-', '', $name_list[4]); // If it's a element. if (isset($name_list[5])) { $current_element['#' . $property][$option_group][$name_list[5]] = i18n_string($name, $current_element['#' . $property][$option_group][$name_list[5]]); } else { // If it's a option group we translate the key. $translated_option_group = i18n_string($name, $option_group); if ($translated_option_group != $option_group) { _webform_localization_array_key_replace($current_element['#' . $property], $option_group, $translated_option_group); } } } else { // Else we can treat the property as string. if (isset($current_element['#' . $property])) { if ($property == 'markup' && $current_element['#type'] == 'markup') { $current_element['#' . $property] = i18n_string($name, $current_element['#' . $property], array('format' => $current_element['#format'])); } elseif ($property == 'description') { $current_element['#' . $property] = i18n_string($name, $current_element['#' . $property], array('format' => I18N_STRING_FILTER_XSS)); } else { $current_element['#' . $property] = i18n_string($name, $current_element['#' . $property]); } } } } } } } /** * Translates the analysis component properties that are translatable. * * These are found in under 'translated_strings' in the 'extra' array of the * component, which is build when the component is inserted / updated, or * when all webform strings are updated from * admin/config/regional/translate/i18n_string. * * @param array $data * The data array of component results. * @param array $component * The component. */ function _webform_localization_translate_analysis_component(&$data, &$component) { if (!isset($component['extra']['translated_strings']) || !is_array($component['extra']['translated_strings'])) { return; } // Attempt to translate select options. if ($component['type'] == 'select') { $item_key_lookup = _webform_localization_string_to_key($component['extra']['items']); } // Attempt to translate grid options / questions. if ($component['type'] == 'grid') { $options_key_lookup = _webform_localization_string_to_key($component['extra']['options']); $questions_key_lookup = _webform_localization_string_to_key($component['extra']['questions']); } foreach ($component['extra']['translated_strings'] as $name) { $name_list = explode(':', $name); // Translate component name from title property. if ($name_list[3] == '#title') { $component['name'] = i18n_string($name, $component['name']); continue; } // Translate options for select elements. if ($component['type'] == 'select' && strpos($name_list[3], '-') !== FALSE) { list (, $key) = explode('-', $name_list[3]); if (isset($item_key_lookup[$key])) { foreach ($data['table_rows'] as $index => $row) { if ($row[0] == $item_key_lookup[$key]) { $data['table_rows'][$index][0] = i18n_string($name, $row[0]); } } } } // Translate options / questions for grid elements. if ($component['type'] == 'grid' && $name_list[3] !== '#title') { list (, $key) = explode('-', $name_list[3]); if (strpos($name_list[3], 'grid_options')) { if (isset($options_key_lookup[$key])) { foreach ($data['table_header'] as $index => $row) { if ($row == $options_key_lookup[$key]) { $data['table_header'][$index] = i18n_string($name, $row); } } } } if (strpos($name_list[3], 'grid_questions')) { if (isset($questions_key_lookup[$key])) { foreach ($data['table_rows'] as $index => $row) { if (trim($row[0]) == trim($questions_key_lookup[$key])) { $data['table_rows'][$index][0] = i18n_string($name, $row[0]); } } } } } } } /** * Update / create translation source for all the translatable poperties. * * @param array $component * A webform component. */ function webform_localization_component_update_translation_strings(&$component) { // Fill in the the default values for the missing properties. module_load_include('inc', 'webform', 'includes/webform.components'); webform_component_defaults($component); // Render the 'render' FAPI array for the component. $element = webform_component_invoke($component['type'], 'render', $component, NULL, 'html'); // Parse the renderable array to find the translatable properties and // update / create translation source for them. $component['extra']['translated_strings'] = _webform_localization_component_translation_parse($element, $component); // Render the 'display' FAPI array for the component. $element = webform_component_invoke($component['type'], 'display', $component, NULL, 'html'); // Parse the renderable array to find the translatable properties and // update / create translation source for them. $component['extra']['translated_strings'] = array_merge($component['extra']['translated_strings'], array_diff(_webform_localization_component_translation_parse($element, $component), $component['extra']['translated_strings'])); } /** * Parse a component renderable array to find the translatable properties. * * Create / update or remove translation source for translatable properties * of a webform component. * * @param array $element * The renderable array to be parsed. * @param array $component * The component which was rendered. * @return * An array of translatabled webform properties. * */ function _webform_localization_component_translation_parse($element, $component) { $translated_properies = array(); if (!isset($element['#parents'])) { $element['#parents'] = array(); } if (isset($element['#translatable']) && is_array($element['#translatable'])) { foreach ($element['#translatable'] as $key) { if (isset($element['#' . $key]) && $element['#' . $key] != '') { if (isset($element['#parents']) && count($element['#parents'])) { $property = '[' . implode('][', $element['#parents']) . ']#' . $key; } else { $property = '#' . $key; } if (is_array($element['#' . $key])) { // If the translatable property is an array, we translate the // children. foreach ($element['#' . $key] as $elem_key => $elem_value) { // If the child if an array, we translate the elements. if (is_array($elem_value)) { foreach ($elem_value as $k => $v) { $name = webform_localization_i18n_string_name($component['nid'], $component['cid'], $property, '/-' . $elem_key . '/-', $k); $translated_properies[] = $name; i18n_string($name, $v, array('update' => TRUE)); } $name = webform_localization_i18n_string_name($component['nid'], $component['cid'], $property, '/-' . $elem_key . '/-'); $translated_properies[] = $name; i18n_string($name, $elem_key, array('update' => TRUE)); } else { // If the child is not an array. $name = webform_localization_i18n_string_name($component['nid'], $component['cid'], $property . '-' . $elem_key); $translated_properies[] = $name; i18n_string($name, $elem_value, array('update' => TRUE)); } } } else { /** * If the translatable property is not an array, * it can be treated as a string. */ $name = webform_localization_i18n_string_name($component['nid'], $component['cid'], $property); $translated_properies[] = $name; i18n_string($name, $element['#' . $key], array('update' => TRUE)); } } } } // Recursevly call the function on the children, after adding the children // name to its #parents array. foreach (element_children($element) as $child) { $element[$child]['#parents'] = $element['#parents']; $element[$child]['#parents'][] = $child; // Add the translated propertied to the list. $translated_properies = array_merge( $translated_properies, _webform_localization_component_translation_parse($element[$child], $component) ); } return $translated_properies; } /** * Utility function to create i18n string name. * * Additional arguments can be passed to add more depth to context * * @param int $node_identifier * webform nid * * @return string * i18n string name grouped by nid or uuid if module is available */ function webform_localization_i18n_string_name($node_identifier) { if (module_exists('uuid')) { $node_identifier = current(entity_get_uuid_by_id('node', array($node_identifier))); } $name = array('webform', $node_identifier); $args = func_get_args(); // Remove $node_identifier from args array_shift($args); foreach ($args as $arg) { $name[] = $arg; } return implode(':', $name); } /** * Delete translation source for all the translatable poperties * * Process components matching webforms configuration. */ function webform_localization_delete_all_strings() { $query = db_select('webform_component', 'wc'); $query->fields('wc'); $query->condition('wl.expose_strings', 0, '='); $query->innerJoin('webform_localization', 'wl', 'wc.nid = wl.nid'); $components = $query->execute()->fetchAllAssoc('cid'); foreach ($components as $component) { $component = (array) $component; $component['extra'] = unserialize($component['extra']); webform_localization_component_delete_translation_strings($component); $component['extra'] = serialize($component['extra']); drupal_write_record('webform_component', $component, array('nid', 'cid')); } } /** * Remove translation source for all the translatable poperties. * * @param array $component * A webform component array. */ function webform_localization_component_delete_translation_strings($component) { if (isset($component['extra']['translated_strings'])) { foreach ($component['extra']['translated_strings'] as $name) { i18n_string_remove($name); } } } /** * Update / create translation source for general webform poperties. * * @param array $properties * The form_state values that have been saved. */ function webform_localization_update_translation_strings($properties) { if (!empty($properties['confirmation']['value'])) { $name = webform_localization_i18n_string_name($properties['nid'], 'confirmation'); i18n_string($name, $properties['confirmation']['value'], array('update' => TRUE)); } if (!empty($properties['submit_text'])) { $name = webform_localization_i18n_string_name($properties['nid'], 'submit_text'); i18n_string($name, $properties['submit_text'], array('update' => TRUE)); } // Allow to translate the redirect url if it's not set to none or the // default confirmation page. if (!in_array($properties['redirect_url'], array('', ''))) { $name = webform_localization_i18n_string_name($properties['nid'], 'redirect_url'); i18n_string($name, $properties['redirect_url'], array('update' => TRUE)); } } /** * Translate general webform properties. * * @param $node * A node object. */ function webform_localization_translate_strings(&$node, $update = FALSE) { $option = array('update' => $update, 'sanitize' => FALSE); $name = webform_localization_i18n_string_name($node->webform['nid'], 'confirmation'); $node->webform['confirmation'] = i18n_string( $name, $node->webform['confirmation'], $option); $name = webform_localization_i18n_string_name($node->webform['nid'], 'submit_text'); $node->webform['submit_text'] = i18n_string( $name, $node->webform['submit_text'], $option); // Allow to translate the redirect url if it's not set to none or the // default confirmation page. if (!in_array($node->webform['redirect_url'], array('', ''))) { $name = webform_localization_i18n_string_name($node->webform['nid'], 'redirect_url'); $node->webform['redirect_url'] = i18n_string($name, $node->webform['redirect_url'], $option); } } /** * Update / create translation source for webform email poperties. * * @param array $properties * The form_state values that have been saved. */ function webform_localization_emails_update_translation_string($properties) { $nid = $properties['node']->webform['nid']; $eid = $properties['eid']; if (!empty($properties['subject_custom'])) { $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'subject_custom'); i18n_string($name, $properties['subject_custom'], array('update' => TRUE)); } // Allow to translate the mail recipients if not based on a component. if (!empty($properties['email']) && !is_numeric($properties['email'])) { $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'email'); i18n_string($name, $properties['email'], array('update' => TRUE)); } if (!empty($properties['from_name_custom'])) { $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'from_name_custom'); i18n_string($name, $properties['from_name_custom'], array('update' => TRUE)); } if (!empty($properties['template'])) { $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'template'); i18n_string($name, $properties['template'], array('update' => TRUE)); } } /** * Update / create translation source for webform email poperties. * * @param $emails * An array of webform emails. * @param $nid * The node Id of the webform. */ function webform_localization_emails_translation_string_refresh($emails, $nid) { foreach ($emails as $email) { $eid = $email['eid']; if (!empty($email['subject']) && $email['subject'] != 'default') { $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'subject_custom'); i18n_string($name, $email['subject'], array('update' => TRUE)); } // Allow to translate the mail recipients if not based on a component. if (!empty($email['email']) && !is_numeric($email['email'])) { $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'email'); i18n_string($name, $email['email'], array('update' => TRUE)); } if (!empty($email['from_name']) && $email['from_name'] != 'default') { $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'from_name_custom'); i18n_string($name, $email['from_name'], array('update' => TRUE)); } if (!empty($email['template']) && $email['template'] != 'default') { $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'template'); i18n_string($name, $email['template'], array('update' => TRUE)); } } } /** * Translate webform email poperties. * * @param $node * A node object. */ function webform_localization_email_translate_strings(&$node) { $nid = $node->webform['nid']; foreach ($node->webform['emails'] as $eid => &$email) { if (!empty($email['subject']) && $email['subject'] != 'default') { $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'subject_custom'); $email['subject'] = i18n_string($name, $email['subject']); } // Allow to translate the mail recipients if not based on a component. if (!empty($email['email']) && !is_numeric($email['email'])) { $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'email'); $email['email'] = i18n_string($name, $email['email']); } if (!empty($email['from_name']) && $email['from_name'] != 'default') { $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'from_name_custom'); $email['from_name'] = i18n_string($name, $email['from_name']); } if (!empty($email['template']) && $email['template'] != 'default') { $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'template'); $email['template'] = i18n_string($name, $email['template']); } } } /** * Remove translation source for webform email poperties. * * @param $eid * A webform email Id. * @param $nid * A node Id. */ function webform_localization_emails_delete_translation_string($eid, $nid) { $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'subject_custom'); i18n_string_remove($name); $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'from_name_custom'); i18n_string_remove($name); $name = webform_localization_i18n_string_name($nid, 'email', $eid, 'template'); i18n_string_remove($name); } /** * Translate general webform poperties. * * @param $node * A node object. */ function webform_localization_delete_translate_strings($node) { $name = webform_localization_i18n_string_name($node->webform['nid'], 'confirmation'); i18n_string_remove($name); $name = webform_localization_i18n_string_name($node->webform['nid'], 'submit_text'); i18n_string_remove($name); foreach ($node->webform['emails'] as $eid => $value) { webform_localization_emails_delete_translation_string($eid, $node->nid); } } /** * Update i18n string contexts if uuid module is enabled/disabled. * */ function webform_localization_uuid_update_strings($disabling_uuid = FALSE) { module_load_install('i18n_string'); $old_ids = db_query('SELECT distinct type FROM {i18n_string} WHERE textgroup = :webform', array( ':webform' => 'webform' ))->fetchCol(); variable_set('webform_localization_using_uuid', !$disabling_uuid); if (empty($old_ids)) { return; } if (!$disabling_uuid) { $old_context_ids = entity_get_uuid_by_id('node', array($old_ids)); } else { // entity_get_id_by_uuid() do not work properly on hook_disable. $old_context_ids = webform_localization_get_id_by_uuid('node', array($old_ids)); } foreach ($old_context_ids as $old_id => $new_id) { $old_context = 'webform:' . $old_id . ':*'; $new_context = 'webform:' . $new_id . ':*'; i18n_string_install_update_context($old_context, $new_context); } } /** * Helper function that retrieves entity IDs by their UUIDs. * * * @param $entity_type * The entity type we should be dealing with. * @param $uuids * An array of UUIDs for which we should find their entity IDs. If $revision * is TRUE this should be revision UUIDs instead. * @return * Array of entity IDs keyed by their UUIDs. If $revision is TRUE revision * IDs and UUIDs are returned instead. */ function webform_localization_get_id_by_uuid($entity_type, $uuids) { if (empty($uuids)) { return array(); } $info = entity_get_info($entity_type); $table = $info['base table']; $id_key = $info['entity keys']['id']; // The uuid key is not available at hook_disable. $core_info = uuid_get_core_entity_info(); $uuid_key = $core_info['node']['entity keys']['uuid']; // Get all UUIDs in one query. return db_select($table, 't') ->fields('t', array($uuid_key, $id_key)) ->condition($uuid_key, array_values($uuids), 'IN') ->execute() ->fetchAllKeyed(); } /** * Helper function to replace an array key and its content. * * @param $array * Array To process. * @param $old_key * Array key to be replaced. * @param $new_key * The new array key. * */ function _webform_localization_array_key_replace(&$array, $old_key, $new_key) { $keys = array_keys($array); $values = array_values($array); foreach ($keys as $k => $v) { if ($v == $old_key) { $keys[$k] = $new_key; } } $array = array_combine($keys, $values); } /** * Helper function to convert select / grid strings to array. * * @param $string_array * Array To process. * */ function _webform_localization_string_to_key($string_array) { $key_array = array(); $items = explode("\n", trim($string_array)); foreach ($items as $item) { $item_data = explode('|', $item); $key_array[$item_data[0]] = $item_data[1]; } return $key_array; }