Projet

Général

Profil

Paste
Télécharger (16,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / i18n / i18n_string / i18n_string.pages.inc @ 76df55b7

1
<?php
2

    
3
/**
4
 * @file
5
 * Internationalization (i18n) package - translatable strings reusable admin UI.
6
 *
7
 * @author Jose A. Reyero, 2007
8
 */
9

    
10
// Load locale libraries
11
include_once DRUPAL_ROOT . '/includes/locale.inc';
12
include_once drupal_get_path('module', 'locale') . '/locale.admin.inc';
13

    
14
/**
15
 * Generate translate page from object.
16
 *
17
 * @param string $object_type
18
 *   Obejct type as declared in hook_i18n_object_info().
19
 * @param object $object_value
20
 *   Drupal object to translate.
21
 * @param object $language
22
 *   Optional language object.
23
 */
24
function i18n_string_translate_page_object($object_type, $object_value, $language = NULL) {
25
  // For backwards compatibility, ensure parameter is a language object
26
  $language = i18n_language_object($language);
27
  $langcode = $language ? $language->language : NULL;
28
  // Get base keys for all these strings. Object key may be multiple like for blocks (module, delta)
29
  $object = i18n_object($object_type, $object_value);
30
  $strings = $object->get_strings(array('empty' => TRUE));
31

    
32
  // If no localizable strings, print message and fail gracefully.
33
  // Possibly this object comes from some other contrib module.
34
  // See http://drupal.org/node/1889878
35
  if (!$strings) {
36
    return t('This object has no strings available for translation.');
37
  }
38

    
39
  if (empty($langcode)) {
40
    drupal_set_title(t('Translate !name', array('!name' => i18n_object_info($object_type, 'title'))));
41
    return i18n_string_translate_page_overview($object, $strings);
42
  }
43
  else {
44
    drupal_set_title(t('Translate to !language', array('!language' => i18n_language_name($langcode))));
45
    return drupal_get_form('i18n_string_translate_page_form', $strings, $langcode);
46
  }
47
}
48

    
49
/**
50
 * Provide a core translation module like overview page for this object.
51
 */
52
function i18n_string_translate_page_overview($object, $strings) {
53
  $build['i18n_overview'] = drupal_get_form('i18n_string_translate_page_overview_form', $object, $strings);
54
  return $build;
55
}
56

    
57
/**
58
 * Provide a core translation module like overview page for this object.
59
 */
60
function i18n_string_translate_page_overview_form($form, &$form_state, $object, $strings) {
61
  // Set the default item key, assume it's the first.
62
  $item_title = reset($strings);
63
  $header = array(
64
    'language' => t('Language'),
65
    'title' => t('Title'),
66
    'status' => t('Status'),
67
    'operations' => t('Operations')
68
  );
69
  $source_language = variable_get_value('i18n_string_source_language');
70
  $rows = array();
71

    
72
  foreach (language_list() as $langcode => $language) {
73
    if ($langcode == $source_language) {
74
      $items = array(
75
        'language' => check_plain($language->name) . ' ' . t('(source)'),
76
        'title' => check_plain($item_title->get_string()),
77
        'status' => t('original'),
78
        'operations' => l(t('edit'), $object->get_edit_path()),
79
      );
80
    }
81
    else {
82
      // Try to figure out if this item has any of its properties translated.
83
      $translated = FALSE;
84
      foreach ($strings as $i18nstring) {
85
        if ($i18nstring->get_translation($langcode)) {
86
          $translated = TRUE;
87
          break;
88
        }
89
      }
90
      // Translate the item that was requested to be displayed as title.
91
      $items = array(
92
        'language' => check_plain($language->name),
93
        'title' => $item_title->format_translation($langcode, array('sanitize default' => TRUE)),
94
        'status' => $translated ? t('translated') : t('not translated'),
95
        'operations' => l(t('translate'), $object->get_translate_path($langcode), array('query' => drupal_get_destination())),
96
      );
97
    }
98
    foreach ($items as $key => $markup) {
99
      $rows[$langcode][$key] = $markup;
100
      //$form['#rows'][$langcode][$key]['#markup'] = $markup;
101
    }
102
  }
103
  // Build a form so it can be altered later, with all this information.
104
  $form['object'] = array('#type' => 'value', '#value' => $object);
105
  $form['source_language'] = array('#type' => 'value', '#value' => $source_language);
106
  $form['languages'] = array(
107
    '#header' => $header,
108
    '#rows' => $rows,
109
    '#theme' => 'table',
110
  );
111
  return $form;
112
}
113

    
114
/**
115
 * Form builder callback for in-place string translation.
116
 *
117
 * @param $strings
118
 *   Array of strings indexed by string name (may be indexed by group key too if $groups is present)
119
 * @param $langcode
120
 *   Language code to translate to.
121
 * @param $groups
122
 *   Optional groups to provide some string grouping. Array with group key and title pairs.
123
 */
124
function i18n_string_translate_page_form($form, &$form_state, $strings, $langcode, $groups = NULL) {
125
  $form = i18n_string_translate_page_form_base($form, $langcode);
126
  if ($groups) {
127
    // I we've got groups, string list is grouped by group key.
128
    $form['string_groups'] = array('#type' => 'value', '#value' => $strings);
129
    foreach ($groups as $key => $title) {
130
      $form['display'] = array(
131
        '#type' => 'vertical_tabs',
132
      );
133
      $form['strings'][$key] = array(
134
        '#group' => 'display',
135
        '#title' => $title,
136
        '#type' => 'fieldset',
137
      ) + i18n_string_translate_page_form_strings($strings[$key], $langcode);
138
    }
139
  }
140
  else {
141
    // We add a single group with key 'all', but no tabs.
142
    $form['string_groups'] = array('#type' => 'value', '#value' => array('all' => $strings));
143
    $form['strings']['all'] = i18n_string_translate_page_form_strings($strings, $langcode);
144
  }
145
  return $form;
146
}
147

    
148
/**
149
 * Create base form for string translation
150
 */
151
function i18n_string_translate_page_form_base($form, $langcode, $redirect = NULL) {
152
  $form['langcode'] = array(
153
    '#type' => 'value',
154
    '#value' => $langcode,
155
  );
156
  $form['submit'] = array(
157
    '#type' => 'submit',
158
    '#value' => t('Save translation'),
159
    '#weight' => 10,
160
  );
161
  if ($redirect) {
162
    $form['#redirect'] = array(
163
      $redirect,
164
    );
165
  }
166
  // Add explicit validate and submit hooks so this can be used from inside any form.
167
  $form['#submit'] = array('i18n_string_translate_page_form_submit');
168
  return $form;
169
}
170

    
171
/**
172
 * Create field elements for strings
173
 */
174
function i18n_string_translate_page_form_strings($strings, $langcode) {
175
  $formats = filter_formats();
176
  foreach ($strings as $item) {
177
    // We may have a source or not. Load it, our string may get the format from it.
178
    $source = $item->get_source();
179
    $format_id = $source ? $source->format : $item->format;
180
    $description = '';
181
    // Check permissions to translate this string, depends on format, etc..
182
    if ($message = $item->check_translate_access()) {
183
      // We'll display a disabled element with the reason it cannot be translated.
184
      $disabled = TRUE;
185
      $description = $message;
186
    }
187
    else {
188
      $disabled = FALSE;
189
      $description = '';
190
      // If we don't have a source and it can be translated, we create it.
191
      if (!$source) {
192
        // Enable messages just as a reminder these strings are not being updated properly.
193
        $status = $item->update(array('messages' => TRUE));
194
        if ($status === FALSE || $status === SAVED_DELETED) {
195
          // We don't have a source string so nothing to translate here
196
          $disabled = TRUE;
197
        }
198
        else {
199
          $source = $item->get_source();
200
        }
201
      }
202
    }
203

    
204
    $default_value = $item->format_translation($langcode, array('langcode' => $langcode, 'sanitize' => FALSE, 'debug' => FALSE));
205
    $form[$item->get_name()] = array(
206
      '#title' => $item->get_title(),
207
      '#type' => 'textarea',
208
      '#default_value' => $default_value,
209
      '#disabled' => $disabled,
210
      '#description' => $description . _i18n_string_translate_format_help($format_id),
211
      //'#i18n_string_format' => $source ? $source->format : 0,
212
      // If disabled, provide smaller textarea (that can be expanded anyway).
213
      '#rows' => $disabled ? 1 : min(ceil(str_word_count($default_value) / 12), 10),
214
      // Change the parent for disabled strings so we don't get empty values later
215
      '#parents' => array($disabled ? 'disabled_strings': 'strings', $item->get_name()),
216
    );
217
  }
218
  return $form;
219
}
220

    
221
/**
222
 * Form submission callback for in-place string translation.
223
 */
224
function i18n_string_translate_page_form_submit($form, &$form_state) {
225
  $count = $success = 0;
226
  foreach ($form_state['values']['strings'] as $name => $value) {
227
    $count++;
228
    list($textgroup, $context) = i18n_string_context(explode(':', $name));
229
    $result = i18n_string_textgroup($textgroup)->update_translation($context, $form_state['values']['langcode'], $value);
230
    $success += ($result ? 1 : 0);
231
  }
232
  if ($success) {
233
    drupal_set_message(format_plural($success, 'A translation was saved successfully.', '@count translations were saved successfully.'));
234
  }
235
  if ($error = $count - $success) {
236
    drupal_set_message(format_plural($error, 'A translation could not be saved.', '@count translations could not be saved.'), 'warning');
237
  }
238
  if (isset($form['#redirect'])) {
239
    $form_state['redirect'] = $form['#redirect'];
240
  }
241
}
242

    
243
/**
244
 * Menu callback. Saves a string translation coming as POST data.
245
 */
246
function i18n_string_l10n_client_save_string() {
247
  global $user, $language;
248

    
249
  if (user_access('use on-page translation')) {
250
    $textgroup = !empty($_POST['textgroup']) ? $_POST['textgroup'] : 'default';
251
    // Other textgroups will be handled by l10n_client module
252
    if (!i18n_string_group_info($textgroup)) {
253
      return l10n_client_save_string();
254
    }
255
    elseif (isset($_POST['source']) && isset($_POST['target']) && !empty($_POST['context']) && !empty($_POST['form_token']) && drupal_valid_token($_POST['form_token'], 'l10n_client_form')) {
256
      $name = $textgroup . ':' . $_POST['context'];
257
      if ($i18nstring = i18n_string_get_source($name)) {
258
        // Since this is not a real form, we double check access permissions here too.
259
        if ($error = $i18nstring->check_translate_access()) {
260
          $message = theme('l10n_client_message', array('message' => t('Not saved due to: !reason', array('!reason' => $error)), 'level' => WATCHDOG_WARNING));
261
        }
262
        else {
263
          $result = i18n_string_translation_update($name, $_POST['target'], $language->language, $_POST['source']);
264
          if ($result) {
265
            $message = theme('l10n_client_message', array('message' => t('Translation saved locally for user defined string.'), 'level' => WATCHDOG_INFO));
266
          }
267
          elseif ($result === FALSE) {
268
            $message = theme('l10n_client_message', array('message' => t('Not saved due to insufficient permissions.')));
269
          }
270
          else {
271
            $message = theme('l10n_client_message', array('message' => t('Not saved due to unknown reason.')));
272
          }
273
        }
274
      }
275
      else {
276
        $message = theme('l10n_client_message', array('message' => t('Not saved due to source string missing.')));
277
      }
278
    }
279
    else {
280
      $message = theme('l10n_client_message', array('message' => t('Not saved due to missing form values.')));
281
    }
282
    drupal_json_output($message);
283
    exit;
284
  }
285
}
286

    
287

    
288
/**
289
 * User interface for string editing.
290
 */
291
function i18n_string_locale_translate_edit_form($form, &$form_state, $lid) {
292
  // Fetch source string, if possible.
293
  $source = db_query('SELECT source, context, textgroup, location FROM {locales_source} WHERE lid = :lid', array(':lid' => $lid))->fetchObject();
294
  if (!$source) {
295
    drupal_set_message(t('String not found.'), 'error');
296
    drupal_goto('admin/config/regional/translate/translate');
297
  }
298

    
299
  // Add original text to the top and some values for form altering.
300
  $form['original'] = array(
301
    '#type'  => 'item',
302
    '#title' => t('Original text'),
303
    '#markup' => check_plain(wordwrap($source->source, 0)),
304
  );
305
  if (!empty($source->context)) {
306
    $form['context'] = array(
307
      '#type' => 'item',
308
      '#title' => t('Context'),
309
      '#markup' => check_plain($source->context),
310
    );
311
  }
312
  $form['lid'] = array(
313
    '#type'  => 'value',
314
    '#value' => $lid
315
  );
316
  $form['textgroup'] = array(
317
    '#type'  => 'value',
318
    '#value' => $source->textgroup,
319
  );
320
  $form['location'] = array(
321
    '#type'  => 'value',
322
    '#value' => $source->location
323
  );
324

    
325
  // Include default form controls with empty values for all languages.
326
  // This ensures that the languages are always in the same order in forms.
327
  $languages = language_list();
328

    
329
  // We don't need the default language value, that value is in $source.
330
  $omit = $source->textgroup == 'default' ? 'en' : i18n_string_source_language();
331
  unset($languages[($omit)]);
332
  $form['translations'] = array('#tree' => TRUE);
333
  // Approximate the number of rows to use in the default textarea.
334
  $rows = min(ceil(str_word_count($source->source) / 12), 10);
335
  foreach ($languages as $langcode => $language) {
336
    $form['translations'][$langcode] = array(
337
      '#type' => 'textarea',
338
      '#title' => t($language->name),
339
      '#rows' => $rows,
340
      '#default_value' => '',
341
    );
342
  }
343

    
344
  // Fetch translations and fill in default values in the form.
345
  $result = db_query("SELECT DISTINCT translation, language FROM {locales_target} WHERE lid = :lid AND language <> :omit", array(':lid' => $lid, ':omit' => $omit));
346
  foreach ($result as $translation) {
347
    $form['translations'][$translation->language]['#default_value'] = $translation->translation;
348
  }
349

    
350
  $form['actions'] = array('#type' => 'actions');
351
  $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save translations'));
352

    
353
  // Restrict filter permissions and handle validation and submission for i18n strings.
354
  if (i18n_string_group_info($source->textgroup)) {
355
    if ($i18nstring = i18n_string_get_by_lid($form['lid']['#value'])) {
356
      $form['i18n_string'] = array('#type' => 'value', '#value' => $i18nstring);
357
      if ($message = $i18nstring->check_translate_access()) {
358
        drupal_set_message($message);
359
        $disabled = TRUE;
360
      }
361
      // Add format help anyway, though the form may be disabled.
362
      $form['translations']['format_help']['#markup'] = _i18n_string_translate_format_help($i18nstring->format);
363
    }
364
    else {
365
      drupal_set_message(t('Source string not found.'), 'warning');
366
      $disabled = TRUE;
367
    }
368
    if (!empty($disabled)) {
369
      // Disable all form elements
370
      $form['submit']['#disabled'] = TRUE;
371
      foreach (element_children($form['translations']) as $langcode) {
372
        $form['translations'][$langcode]['#disabled'] = TRUE;
373
      }
374
    }
375
  }
376
  return $form;
377
}
378

    
379
/**
380
 * Process string editing form validations.
381
 *
382
 * If it is an allowed format, skip default validation, the text will be filtered later
383
 */
384
function i18n_string_locale_translate_edit_form_validate($form, &$form_state) {
385
  if (empty($form_state['values']['i18n_string'])) {
386
    // If not i18n string use regular locale validation.
387
    $copy_state = $form_state;
388
    locale_translate_edit_form_validate($form, $copy_state);
389
  }
390
}
391

    
392
/**
393
 * Process string editing form submissions.
394
 *
395
 * Mark translations as current.
396
 */
397
function i18n_string_locale_translate_edit_form_submit($form, &$form_state) {
398
  // Invoke locale submission.
399
  locale_translate_edit_form_submit($form, $form_state);
400
  $lid = $form_state['values']['lid'];
401
  if ($i18n_string_object = i18n_string_get_by_lid($lid)) {
402
    $i18n_string_object->cache_reset();
403
  }
404
  foreach ($form_state['values']['translations'] as $key => $value) {
405
    if (!empty($value)) {
406
      // An update has been made, so we assume the translation is now current.
407
      db_update('locales_target')
408
        ->fields(array('i18n_status' => I18N_STRING_STATUS_CURRENT))
409
        ->condition('lid', $lid)
410
        ->condition('language', $key)
411
        ->execute();
412
    }
413
  }
414
}
415

    
416
/**
417
 * Help for text format.
418
 */
419
function _i18n_string_translate_format_help($format_id) {
420
  $output = '';
421
  if ($format = filter_format_load($format_id)) {
422
    $title = t('Text format: @name', array('@name' => $format->name));
423
    $tips =  theme('filter_tips', array('tips' => _filter_tips($format_id, FALSE)));
424
  }
425
  elseif ($format_id == I18N_STRING_FILTER_XSS) {
426
    $title = t('Standard XSS filter.');
427
    $allowed_html = '<a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>';
428
    $tips[] = t('Allowed HTML tags: @tags', array('@tags' => $allowed_html));
429
  }
430
  elseif ($format_id == I18N_STRING_FILTER_XSS_ADMIN) {
431
    $title = t('Administration XSS filter.');
432
    $tips[] = t('It will allow most HTML tags but not scripts nor styles.');
433
  }
434
  elseif ($format_id) {
435
    $title = t('Unknown filter: @name', array('@name' => $format_id));
436
  }
437

    
438
  if (!empty($title)) {
439
    $output .= '<h5>' . $title . '</h5>';
440
  }
441
  if (!empty($tips)) {
442
    $output .= is_array($tips) ? theme('item_list', array('items' => $tips)) : $tips;
443
  }
444
  return $output;
445
}