diff --git a/i18n_block/i18n_block.module b/i18n_block/i18n_block.module index 949f935..62d8a7f 100644 --- a/i18n_block/i18n_block.module +++ b/i18n_block/i18n_block.module @@ -10,6 +10,92 @@ */ /** + * Implements hook_menu(). + * + * Add translate tab to blocks. + */ +function i18n_block_menu() { + $items['admin/structure/block/manage/%/%/translate'] = array( + 'title' => 'Translate', + 'access callback' => 'i18n_block_translate_tab_access', + 'access arguments' => array(4, 5), + 'page callback' => 'i18n_block_translate_tab_page', + 'page arguments' => array(4, 5), + 'type' => MENU_LOCAL_TASK, + 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE, + 'weight' => 10, + ); + $items['admin/structure/block/manage/%/%/translate/%language'] = array( + 'title' => 'Translate', + 'access callback' => 'i18n_block_translate_tab_access', + 'access arguments' => array(4, 5), + 'page callback' => 'i18n_block_translate_tab_page', + 'page arguments' => array(4, 5, 7), + 'type' => MENU_CALLBACK, + 'weight' => 10, + ); + return $items; +} + +/** + * Implement hook_menu_alter(). + * + * Reorganize block tabs so that they make sense. + */ +function i18n_block_menu_alter(&$items) { + // Give the configure tab a short name and make it display. + $items['admin/structure/block/manage/%/%/configure']['weight'] = -100; + $items['admin/structure/block/manage/%/%/configure']['title'] = 'Configure'; + $items['admin/structure/block/manage/%/%/configure']['context'] = MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE; + // Hide the delete tab. Not sure why this was even set a local task then + // set to not show in any context... + $items['admin/structure/block/manage/%/%/delete']['type'] = MENU_CALLBACK; +} + +/** + * Menu access callback function. + * + * Only let blocks translated which are configured to be translatable. + */ +function i18n_block_translate_tab_access($module, $delta) { + $block = block_load($module, $delta); + return user_access('translate interface') && isset($block) && ($block->i18n_mode == I18N_MODE_LOCALIZE); +} + +/** + * Build a translation page for the given block. + */ +function i18n_block_translate_tab_page($module, $delta, $language = NULL) { + $block = block_load($module, $delta); + $form_meta = array( + '#page_title' => t('Translate block'), + '#item_title_key' => array('blocks', $block->module, $block->delta, 'title'), + '#item_title_default' => $block->title, + '#edit' => 'admin/structure/block/manage/' . $block->module . '/' . $block->delta . '/configure', + '#translate' => 'admin/structure/block/manage/' . $block->module . '/' . $block->delta . '/translate/', + '#items' => array(), + ); + if (!empty($block->title) && $block->title != '') { + $form_meta['#items'][] = array( + '#title' => t('Block title'), + '#string_key' => array('blocks', $block->module, $block->delta, 'title'), + '#default_value' => $block->title, + ); + } + if ($block->module == 'block') { + $custom_block = (object) block_custom_block_get($block->delta); + if (!empty($custom_block->body)) { + $form_meta['#items'][] = array( + '#title' => t('Block body'), + '#string_key' => array('blocks', $block->module, $block->delta, 'body'), + '#default_value' => $custom_block->body + ); + } + } + return i18n_string_translate_page($form_meta, $language); +} + +/** * Implements hook_block_list_alter(). * * Translate localizable blocks. diff --git a/i18n_string/i18n_string.inc b/i18n_string/i18n_string.inc index d2729ce..a09a60a 100644 --- a/i18n_string/i18n_string.inc +++ b/i18n_string/i18n_string.inc @@ -581,7 +581,10 @@ class i18n_string_default { * Update string translation. */ function update_translation($context, $langcode, $translation) { - if ($source = $this->get_source($context, $translation)) { + $i18nstring = (object) array( + 'context' => implode(':', $context), + ); + if ($source = $this->get_source($i18nstring)) { $source->language = $langcode; $source->translation = $translation; $this->save_translation($source); @@ -770,5 +773,3 @@ function i18n_string_save_translation($translation) { } return $count; } - - diff --git a/i18n_string/i18n_string.module b/i18n_string/i18n_string.module index 93c8aad..9a0901c 100644 --- a/i18n_string/i18n_string.module +++ b/i18n_string/i18n_string.module @@ -174,9 +174,8 @@ function i18n_string_form_locale_translate_edit_form_alter(&$form, &$form_state) $form['translations'][$langcode]['#disabled'] = $disabled; } $form['translations']['format_help'] = array( - '#type' => 'item', - '#title' => t('Text format: @name', array('@name' => $format->name)), - '#value' => theme('filter_tips', _filter_tips($context->format, FALSE)) + '#type' => 'markup', + '#markup' => '
' . t('Text format: @name', array('@name' => $format->name)) . '
' . theme('filter_tips', array('tips' => _filter_tips($context->format, FALSE))), ); $form['submit']['#disabled'] = $disabled; } @@ -691,3 +690,162 @@ function i18n_string_object_update($type, $object) { return i18n_string_textgroup($info['string translation']['textgroup'])->update_object($type, $object); } } \ No newline at end of file + +/** + * Generic translation interface for i18n_strings objects. + */ +function i18n_string_translate_page($form_meta, $langcode = NULL) { + $form_meta += array( + '#item_title_header' => t('Title'), + ); + + if (empty($langcode)) { + drupal_set_title($form_meta['#page_title']); + return i18n_string_translate_page_overview($form_meta); + } + else { + $languages = language_list(); + drupal_set_title(t('Translate to @language', array('@language' => $languages[$langcode]->name))); + return drupal_get_form('i18n_string_translate_page_form', $form_meta, $langcode); + } +} + +/** + * Provide a core translation module like overview page for this object. + */ +function i18n_string_translate_page_overview($form_meta) { + include_once DRUPAL_ROOT . '/includes/language.inc'; + + $header = array(t('Language'), $form_meta['#item_title_header'], t('Status'), t('Operations')); + $default_language = language_default(); + $rows = array(); + + foreach (language_list() as $langcode => $language) { + if ($langcode == $default_language->language) { + $rows[] = array( + $language->name . ' ' . t('(source)'), + $form_meta['#item_title_default'], + t('original'), + l(t('edit'), $form_meta['#edit']), + ); + } + else { + // Try to figure out if this item has any of its properties translated. + $translated = FALSE; + foreach($form_meta['#items'] as $item) { + $str = i18n_string($item['#string_key'], $item['#default_value'], array('langcode' => $langcode, 'sanitize' => FALSE)); + if ($str != $item['#default_value']) { + $translated = TRUE; + break; + } + } + // Translate the item that was requested to be displayed as title. + $item_title = i18n_string($form_meta['#item_title_key'], $form_meta['#item_title_default'], array('langcode' => $langcode)); + $rows[] = array( + $language->name, + $item_title, + $translated ? t('translated') : t('not translated'), + l(t('translate'), $form_meta['#translate'] . $langcode), + ); + } + } + + $build['i18n_string_translation_overview'] = array( + '#theme' => 'table', + '#header' => $header, + '#rows' => $rows, + ); + + return $build; +} + +/** + * Form builder callback for in-place string translation. + */ +function i18n_string_translate_page_form($form, &$form_state, $form_meta, $langcode) { + $formats = filter_formats(); + $form['langcode'] = array( + '#type' => 'value', + '#value' => $langcode, + ); + $form['strings'] = array( + // Use a tree, so we can access the values easily. + '#tree' => TRUE, + ); + foreach ($form_meta['#items'] as $item) { + list($textgroup, $context) = i18n_string_context($item['#string_key']); + $source = db_select('i18n_string', 'i18ns') + ->fields('i18ns') + ->condition('textgroup', $textgroup) + ->condition('context', implode(':', $context)) + ->execute() + ->fetchObject(); + if ($source) { + $disabled = FALSE; + $description = ''; + if ($source->format) { + $format = $formats[$source->format]; + $disabled = !filter_access($format); + if ($disabled) { + $description = t('This string uses the %name text format. You are not allowed to translate or edit texts with this format.', array('%name' => $format->name)); + } + else { + $description = '
' . t('Text format: @name', array('@name' => $format->name)) . '
' . theme('filter_tips', array('tips' => _filter_tips($source->format, FALSE))); + } + } + } + $default_value = i18n_string($item['#string_key'], $item['#default_value'], array('langcode' => $langcode, 'sanitize' => FALSE)); + $form['strings'][implode(':', $item['#string_key'])] = array( + '#title' => $item['#title'], + '#type' => 'textarea', + '#default_value' => $default_value, + '#disabled' => $disabled, + '#description' => $description, + '#i18n_string_format' => !empty($source) ? $source->format : 0, + '#rows' => min(ceil(str_word_count($default_value) / 12), 10), + ); + } + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Save translations'), + ); + $form['#validate'] = array( + 'i18n_string_translate_page_form_validate' + ); + return $form; +} + +/** + * Validation submission callback for in-place string translation. + */ +function i18n_string_translate_page_form_validate($form, &$form_state) { + foreach($form_state['values']['strings'] as $key => $value) { + // We don't need to validate disabled form fields because those are already + // validated by the FormAPI. + if (empty($form['strings'][$key]['#i18n_string_format'])) { + i18n_string_validate_submission("strings][$key", $value); + } + } +} + +/** + * Form submission callback for in-place string translation. + */ +function i18n_string_translate_page_form_submit($form, &$form_state) { + foreach($form_state['values']['strings'] as $key => $value) { + list($textgroup, $context) = i18n_string_context(explode(':', $key)); + i18n_string_textgroup($textgroup)->update_translation($context, $form_state['values']['langcode'], $value); + } + drupal_set_message(t('Translations saved.')); +} + +/** + * String submission validation callback. + */ +function i18n_string_validate_submission($formkey, $value) { + // Validation based on locale_translate_edit_form_validate. + if (!locale_string_is_safe($value)) { + form_set_error($formkey, t('The submitted string contains disallowed HTML: %string', array('%string' => $value))); + watchdog('locale', 'Attempted submission of a translation string with disallowed HTML: %string', array('%string' => $value), WATCHDOG_WARNING); + } +}