/[drupal]/contributions/modules/translatable/translatable.module
ViewVC logotype

Contents of /contributions/modules/translatable/translatable.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.8 - (show annotations) (download) (as text)
Fri Nov 14 01:11:34 2008 UTC (12 months, 1 week ago) by sun
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +108 -51 lines
File MIME type: text/x-php
#334057 by smk-ka: Code clean-up.
1 <?php
2 // $Id: translatable.module,v 1.7 2008/09/12 17:01:11 smk Exp $
3
4 /**
5 * @file
6 * Core functions for #translatable support.
7 *
8 * @see README.txt
9 */
10
11 // Include database functions.
12 require_once drupal_get_path('module', 'translatable') .'/translatable.database.inc';
13 // Include custom drupal_get_form() implementation for Drupal 5 which allows to
14 // merge in translations.
15 require_once drupal_get_path('module', 'translatable') .'/includes/form.inc';
16 // Include menu translation functions.
17 require_once drupal_get_path('module', 'translatable') .'/includes/menu.inc';
18
19 // Load module components.
20 require_once drupal_get_path('module', 'translatable') .'/translatable.block.inc';
21 require_once drupal_get_path('module', 'translatable') .'/translatable.node.inc';
22 require_once drupal_get_path('module', 'translatable') .'/translatable.object.inc';
23 require_once drupal_get_path('module', 'translatable') .'/translatable.page-translations.inc';
24 require_once drupal_get_path('module', 'translatable') .'/includes/language.inc';
25
26 // Enable built-in support for certain contrib modules.
27 if (module_exists('views')) {
28 include_once 'contrib/views.inc';
29 }
30 if (module_exists('category')) {
31 include_once 'contrib/category.inc';
32 }
33
34 /**
35 * Implementation of hook_perm().
36 */
37 function translatable_perm() {
38 return array('access translatable');
39 }
40
41 /**
42 * Implementation of hook_menu() for adding translatable menu items.
43 *
44 * Translates also all user menu items.
45 */
46 function translatable_menu($may_cache) {
47 $items = array();
48
49 // Change locale based on methods configured in Translatable settings.
50 translatable_change_uilocale();
51
52 if ($may_cache) {
53 $items = array_merge(translatable_node_menu($may_cache), translatable_object_menu($may_cache));
54 $items[] = array(
55 'path' => 'admin/settings/translatable',
56 'title' => t('Translatable'),
57 'description' => t('Configure multilingual support'),
58 'callback' => 'drupal_get_form',
59 'callback arguments' => 'translatable_settings_form',
60 'access' => user_access('administer site configuration'),
61 'type' => MENU_NORMAL_ITEM,
62 );
63 }
64 else {
65 $items = array_merge(translatable_node_menu($may_cache), translatable_object_menu($may_cache));
66 // @todo Turn this into a cacheable item.
67 $items[] = array(
68 'path' => 'switchuilocale',
69 'callback' => 'translatable_set_locale',
70 'callback arguments' => array(arg(1), TRUE),
71 'access' => TRUE,
72 'type' => MENU_CALLBACK,
73 );
74 $items[] = array(
75 'path' => 'switchadminlocale',
76 'callback' => 'translatable_set_adminlocale',
77 'access' => user_access('access translatable'),
78 'type' => MENU_CALLBACK,
79 );
80 }
81
82 return $items;
83 }
84
85 /**
86 * Translatable module settings form.
87 */
88 function translatable_settings_form() {
89 translatable_language_negotiation_settings($form);
90
91 $form['content_types'] = array(
92 '#type' => 'fieldset',
93 '#title' => t('Translation support'),
94 );
95 $form['content_types']['translatable_content_types'] = array(
96 '#type' => 'checkboxes',
97 '#title' => t('Translatable content types'),
98 '#default_value' => translatable_content_type_enabled(),
99 '#options' => node_get_types('names'),
100 '#description' => t('Only enabled content types can be translated.'),
101 );
102
103 $form['translation'] = array(
104 '#type' => 'fieldset',
105 '#title' => t('Translation options'),
106 );
107 $form['translation']['translatable_default_content_any'] = array(
108 '#type' => 'checkbox',
109 '#title' => t("Create new contents in 'Any language'"),
110 '#default_value' => variable_get('translatable_default_content_any', FALSE),
111 '#description' => t('If this is enabled, the option "Any" is always pre-selected for new contents. If this is disabled, the current locale is pre-selected.'),
112 );
113
114 return system_settings_form($form);
115 }
116
117 /**
118 * Inject translation languages into translation language block.
119 *
120 * This is a tricky one:
121 * To conditionally display a block to select the translation language, we
122 * only generate the selection list on translation forms and inject it to
123 * our block by invoking hook_block('view') afterwards.
124 *
125 * @param string $form_id
126 * The id of the form the block is based on.
127 * @param array $form
128 * The form the block is based on.
129 *
130 * @see translatable_block(), translatablenode_form_alter(), translatablevariable_form_alter()
131 */
132 function translatable_adminlocale_formselect($form_id, $form) {
133 static $languages;
134
135 if (!isset($languages) && !empty($form)) {
136 drupal_add_js(drupal_get_path('module', 'translatable') .'/jquery.block.js');
137 $languages = theme('translatable_languages', 'translation', $form);
138 }
139 return $languages;
140 }
141
142 /**
143 * Implementation of hook_form_alter().
144 *
145 * Provides proxy functionality for our module components.
146 */
147 function translatable_form_alter($form_id, &$form) {
148 translatable_node_form_alter($form_id, $form);
149 translatable_object_form_alter($form_id, $form);
150 }
151
152 /**
153 * Implementation of hook_user().
154 */
155 function translatable_user($op, &$edit, &$account, $category = NULL) {
156 global $user;
157
158 switch ($op) {
159 case 'after_update':
160 case 'login':
161 // Switch language after logging in or updating the user account.
162 if ($user->uid == $account->uid) {
163 $languages = translatable_available_languages();
164 if (isset($languages[$account->language])) {
165 translatable_set_locale($account->language);
166 }
167 }
168 break;
169
170 case 'load':
171 // Apply default setting for switch_adminlocale if not defined.
172 if (empty($account->switch_adminlocale)) {
173 $account->switch_adminlocale = 0;
174 }
175 break;
176
177 case 'form':
178 $languages = translatable_available_languages();
179 if (count($languages) < 2 || !user_access('access translatable') || $category != 'account') {
180 return;
181 }
182 $form['locale']['switch_adminlocale'] = array(
183 '#type' => 'radios',
184 '#title' => t('Translation language'),
185 '#options' => array(t('Always equivalent to interface language'), t('Separate translation language')),
186 '#default_value' => $account->switch_adminlocale,
187 '#weight' => 1,
188 '#description' => t('Please choose, whether the translation language should always match the interface language or if it should be kept separated, when switching one of both languages.'),
189 );
190 return $form;
191 }
192 }
193
194 /**
195 * Check whether a specific content type is translation-enabled, or return
196 * a list of translation-enabled content types.
197 *
198 * @param $type
199 * Content type to check, can be omitted.
200 *
201 * @return
202 * Either a boolean result, or an array of enabled content types.
203 */
204 function translatable_content_type_enabled($type = NULL) {
205 static $enabled_types;
206 if (!isset($enabled_types)) {
207 $enabled_types = variable_get('translatable_content_types', drupal_map_assoc(array('page', 'story')));
208 }
209 return isset($type) ? !empty($enabled_types[$type]) : $enabled_types;
210 }
211
212 /**
213 * Returns a list of translatable fields for a given form id.
214 *
215 * @param array $form
216 * The form to search for #translatable fields.
217 */
218 function translatable_get_translatable_fields($form) {
219 $fields = array();
220 if (is_string($form)) {
221 $args = func_get_args();
222 $form = call_user_func_array('translatable_retrieve_form', $args);
223 }
224 return _translatable_get_translatable_fields($fields, $form);
225 }
226
227 function _translatable_get_translatable_fields(&$fields, $element) {
228 foreach (element_children($element) as $key) {
229 $item = &$element[$key];
230
231 // Catch all fields that are not explicitly set to FALSE.
232 if (!isset($item['#translatable']) || $item['#translatable'] !== FALSE) {
233 // Check whether this item is basically translatable.
234 if (_translatable_is_translatable_field($item)) {
235 // If #parents is set, the last element will hold the form value after
236 // submit, otherwise use the element's key.
237 $field = isset($item['#parents']) ? end($item['#parents']) : $key;
238 $fields[$field] = $field;
239 }
240 }
241 if ($item['#translatable'] !== FALSE && element_children($item)) {
242 _translatable_get_translatable_fields($fields, $item);
243 }
244 }
245 return $fields;
246 }
247
248 function _translatable_is_translatable_field($element) {
249 return isset($element['#type']) && !in_array($element['#type'], array('fieldset', 'button', 'form', 'hidden', 'markup', 'item', 'submit', 'value', 'token'));
250 }
251
252 /**
253 * Filter out untranslatable elements of a given form.
254 *
255 * @param &$form
256 * The form tree whose untranslatable fields will be filtered out.
257 * @param $parent_form
258 * The parent form tree to synchronize the form with.
259 */
260 function translatable_filter_form(&$form, $parent_form) {
261 _translatable_filter_form($form, $parent_form, $form);
262 }
263
264 /**
265 * Filter out untranslatable elements of a given form.
266 *
267 * If #translatable is set and TRUE, we copy the default value from the parent
268 * form and allow translation.
269 * If set to FALSE, we copy the default value from the parent form and make
270 * the field inaccessible.
271 * If #translatable is not set at all, we leave a field as is. For new node
272 * forms, this means that default values for new nodes are applied.
273 *
274 * @param &$form
275 * The form tree whose untranslatable fields will be filtered out; parsed
276 * recursively.
277 * @param $parent_form
278 * The parent form tree to synchronize $form with. This is either an empty
279 * form for new nodes, or the source form for existing nodes and generic
280 * translation objects.
281 * @param &$form
282 * Equals first parameter (form tree), but holds always the complete form;
283 * needed to define untranslatable fields and check whether the form is built
284 * to create a new translation (#is_new).
285 * @param $parents
286 * An array of parent form item keys we have recursed into.
287 * @param $submit_parents
288 * An array of form item keys that build up the parents of a form item in the
289 * resulting $form_values array (@see form_builder()).
290 *
291 * @return
292 * Whether to hide the parent element after returning from recursion.
293 */
294 function _translatable_filter_form(&$element, $parent_form, &$form, $parents = array(), $submit_parents = array()) {
295 $hide_parent = TRUE;
296
297 foreach(element_children($element) as $key) {
298 $item = &$element[$key];
299
300 // To access each form item in both forms, we need all parents of an item.
301 // @see translatable_get_form_value(), translatable_set_form_value()
302 $keys = $parents;
303 $keys[] = $key;
304
305 // Handle #tree property for untranslatable fields.
306 if (isset($item['#tree']) && $item['#tree']) {
307 // Start a new parents tree for $form_values.
308 $submit_keys = array($key);
309 }
310 else if (!empty($submit_parents)) {
311 // Append to an existing parents tree for $form_values.
312 $submit_keys = $submit_parents;
313 $submit_keys[] = $key;
314 }
315 else {
316 // No parent item had #tree assigned; store only current key.
317 $submit_keys = array($key);
318 }
319
320 // Check #translatable property.
321 if (isset($item['#translatable'])) {
322 if ($item['#translatable']) {
323 $hide_field = FALSE;
324 $hide_parent = FALSE;
325 }
326 else {
327 $hide_field = TRUE;
328 // Mark untranslatable fields for synchronization in our submit callback.
329 $form['#untranslatable'][] = $submit_keys;
330 }
331 // If #translatable is TRUE or FALSE, we need to sync all contents.
332 // Synchronize field _after_ checking #translatable property;
333 // otherwise we would overwrite the property.
334 if (isset($form['#is_new']) || $item['#translatable'] === FALSE) {
335 translatable_set_form_value($form, $keys, translatable_get_form_value($parent_form, $keys));
336 }
337 }
338 else {
339 $item['#translatable'] = '';
340 $hide_field = FALSE;
341 $hide_parent = FALSE;
342 }
343
344 // Display source content for translatable fields.
345 if (!$hide_field && $item['#translatable'] !== FALSE && _translatable_is_translatable_field($item) && $key != 'translatable_node_any') {
346 $prefix = '';
347 if (in_array($item['#type'], array('select', 'radios', 'checkboxes'))) {
348 $default = translatable_get_form_value($parent_form, $keys, '#default_value');
349 $keys[] = '#options';
350 if (is_array($default)) {
351 $prefix = array();
352 foreach ($default as $option_value) {
353 $prefix[] = translatable_get_form_value($parent_form, $keys, $option_value);
354 }
355 $prefix = implode(', ', $prefix);
356 }
357 else {
358 $prefix = translatable_get_form_value($parent_form, $keys, $default);
359 }
360 }
361 else if ($item['#type'] == 'checkbox') {
362 $prefix = translatable_get_form_value($parent_form, $keys, '#default_value') ? t('Enabled') : t('Disabled');
363 }
364 else if ($item['#type'] == 'radio') {
365 $keys[] = translatable_get_form_value($parent_form, $keys, '#default_value');
366 $prefix = translatable_get_form_value($parent_form, $keys, '#title');
367 }
368 else {
369 $prefix = translatable_get_form_value($parent_form, $keys, '#default_value');
370 }
371 if ($prefix) {
372 if (!isset($item['#prefix'])) {
373 $item['#prefix'] = '';
374 }
375 $item['#prefix'] .= '<div class="form-item translatable-source"><label>'. t('Source') .':</label>'. filter_xss_admin($prefix) .'</div>';
376 }
377 }
378
379 // Process child elements of current element
380 if (!$hide_field) {
381 $has_children = element_children($item);
382 if ($has_children) {
383 $element_parents = $parents;
384 $element_parents[] = $key;
385 $element_submit_keys = $submit_keys;
386 if (!_translatable_filter_form($item, $parent_form, $form, $element_parents, $element_submit_keys)) {
387 // Do not hide this field if a child needs to be displayed.
388 $hide_field = FALSE;
389 $hide_parent = FALSE;
390 }
391 }
392 }
393
394 // Ensure this form element is not a required (in terms of FAPI functionality)
395 if ($hide_field && _translatable_is_hideable_field($item)) {
396 $item['#access'] = FALSE;
397 }
398 }
399
400 return $hide_parent;
401 }
402
403 /**
404 * Retrieve a form item or property of a form item.
405 *
406 * @param array $form
407 * The form to recurse into.
408 * @param array $keys
409 * An array of parent keys of the form item to retrieve, including the item
410 * itself. This works similar to FAPI's #parents property and form_set_value()
411 * function.
412 * @param string $property
413 * An optional form item property to retrieve.
414 *
415 * @return
416 * A form item or a form item property.
417 *
418 * @see translatable_set_form_value(), _translatable_filter_form()
419 */
420 function translatable_get_form_value($form, $keys, $property = NULL) {
421 $parent = array_shift($keys);
422 if (empty($keys)) {
423 if (isset($property)) {
424 return isset($form[$parent][$property]) ? $form[$parent][$property] : NULL;
425 }
426 else {
427 return $form[$parent];
428 }
429 }
430 else {
431 return isset($form[$parent]) ? translatable_get_form_value($form[$parent], $keys, $property) : NULL;
432 }
433 }
434
435 /**
436 * Replace a form item or form item property with a given value.
437 *
438 * @param array $form
439 * The form to recurse into.
440 * @param array $keys
441 * An array of parent keys of a form item, including the form item itself,
442 * optionally including a form item property.
443 * @param $value
444 * A value to assign.
445 *
446 * @return
447 * Nothing. $form is altered by reference.
448 *
449 * @see translatable_get_form_value()
450 */
451 function translatable_set_form_value(&$form, $keys, $value) {
452 $parent = array_shift($keys);
453 if (empty($keys)) {
454 $form[$parent] = $value;
455 }
456 else {
457 if (!isset($form[$parent])) {
458 $form[$parent] = array();
459 }
460 translatable_set_form_value($form[$parent], $keys, $value);
461 }
462 }
463
464 /**
465 * Reset all untranslatable form values to their original values.
466 *
467 * @todo This is painful in Drupal 5, so we might leave it as is.
468 */
469 function translatable_filter_form_submit($form_id, &$form_values, $form) {
470 // foreach (element_children($untranslatable) as $element) {
471 // form_set_value($untranslatable[$element], $untranslatable[$element]['#value']);
472 // }
473 }
474
475 /**
476 * Determine whether a untranslatable field should be hidden.
477 *
478 * @param $element
479 * A form element.
480 */
481 function _translatable_is_hideable_field($element) {
482 if (isset($element['#type'])) {
483 // If #type is set, ensure that this element is not required by FAPI.
484 if (!in_array($element['#type'], array('button', 'form', 'hidden', 'item', 'submit', 'value', 'token'))) {
485 return TRUE;
486 }
487 else {
488 return FALSE;
489 }
490 }
491 // If no #type is set, assume it's hideable.
492 return TRUE;
493 }
494
495 /**
496 * Recursively replace field values with translated values.
497 *
498 * Used for translation objects only.
499 *
500 * @param &$form
501 * The form tree to process.
502 * @param $items
503 * The field translations as returned by translatable_find().
504 *
505 * @see translatable_find(), translatable.object.inc
506 */
507 function translatable_translate_form_values(&$form, $items) {
508 if ($items) {
509 $fields = array();
510 foreach ($items as $item) {
511 $fields[$item['object_field']] = $item['translation'];
512 }
513 _translatable_translate_form_values($form, $fields);
514 }
515 }
516
517 function _translatable_translate_form_values(&$form, $fields) {
518 foreach(element_children($form) as $key) {
519 $item = &$form[$key];
520 // If #parents is set, it overrides $key as the element's form value name.
521 $field = isset($item['#parents']) ? end($item['#parents']) : $key;
522 if (isset($fields[$field]) && _translatable_is_translatable_field($item)) {
523 $item['#default_value'] = $fields[$field];
524 }
525 _translatable_translate_form_values($item, $fields);
526 }
527 }
528
529 /**
530 * Get the key to use for cache system by adding current locale.
531 *
532 * @param $key
533 * The original key.
534 *
535 * @return
536 * The key for cache.
537 *
538 * @todo Unused.
539 */
540 function cache_key($key = NULL) {
541 if ($key == NULL) {
542 return NULL;
543 }
544 if (!$key) {
545 return $key;
546 }
547 $key = $key .'-'. translatable_get_locale() .'-'. translatable_get_enabled_locales(false);
548 return $key;
549 }
550
551 /**
552 * Translate an object.
553 *
554 * @param $object_name
555 * The object name (typically the name of the database table).
556 * @param $object_key
557 * The object key (typically the id of the database record).
558 * @param $object
559 * The object to translate.
560 *
561 * @return
562 * The translated object.
563 * @see translatable_get_object_definition(), translatable.database.inc
564 */
565 function tobject($object_name, $object_key, $object) {
566 $items = translatable_find('translation', "object_name='$object_name' AND object_key='$object_key' AND locale='". translatable_get_locale() ."'");
567
568 foreach ($items as $key => $item) {
569 if (!empty($item['translation'])) {
570 $object_field = $item['object_field'];
571 $object->$object_field = $item['translation'];
572 }
573 }
574 return $object;
575 }
576
577 // Rewrite of some core functions
578
579 /**
580 * Translate a string and substitute the arguments.
581 *
582 * @param $string
583 * The string to translate.
584 * @param $args
585 * Array of additional arguments to substitute.
586 * @param $locale
587 * The locale to use for the translation.
588 *
589 * @return
590 * The translated string.
591 */
592 function translatable_t($string, $args = 0, $locale = '') {
593 if ($locale == '') {
594 $locale = $GLOBALS['locale'];
595 }
596
597 if ($locale != 'en') {
598 $string = translatable_locale($string, $locale);
599 }
600
601 if (!$args) {
602 return $string;
603 }
604 else {
605 return strtr($string, $args);
606 }
607 }
608
609 /**
610 * Translate a string.
611 *
612 * @param string $string
613 * A string to translate.
614 * @param string $locale
615 * A locale to use for the translation.
616 *
617 * @return
618 * The translated string.
619 */
620 function translatable_locale($string, $locale) {
621 static $locale_t;
622
623 // Store database cached translations in a static var.
624 $cache = cache_get("locale:$locale");
625
626 if ($cache == 0) {
627 locale_refresh_cache();
628 $cache = cache_get("locale:$locale");
629 }
630 $locale_t = unserialize($cache->data);
631
632 if (isset($locale_t[$string])) {
633 // We have the translation cached (if it is TRUE, then there is no
634 // translation, so there is no point in checking the database).
635 $string = ($locale_t[$string] === TRUE ? $string : $locale_t[$string]);
636 }
637 else {
638 // We do not have this translation cached, so get it from the DB.
639 $result = db_query("SELECT s.lid, t.translation FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid WHERE s.source = '%s' AND t.locale = '%s'", $string, $locale);
640 if ($trans = db_fetch_object($result)) {
641 // Translation found
642 if (!empty($trans->translation)) {
643 $locale_t[$string] = $trans->translation;
644 $string = $trans->translation;
645 }
646 }
647 else {
648 // Either we have no such source string, or no translation
649 $result = db_query("SELECT lid, source FROM {locales_source} WHERE source = '%s'", $string);
650 if ($obj = db_fetch_object($result)) {
651 // We have no such translation
652 if ($locale) {
653 db_query("INSERT INTO {locales_target} (lid, locale, translation) VALUES (%d, '%s', '')", $obj->lid, $locale);
654 }
655 }
656 else {
657 // We have no such source string
658 db_query("INSERT INTO {locales_source} (location, source) VALUES ('%s', '%s')", request_uri(), $string);
659 if ($locale) {
660 $lid = db_fetch_object(db_query("SELECT lid FROM {locales_source} WHERE source = '%s'", $string));
661 db_query("INSERT INTO {locales_target} (lid, locale, translation) VALUES (%d, '%s', '')", $lid->lid, $locale);
662 }
663 }
664 // Clear locale cache in DB
665 cache_clear_all("locale:$locale");
666 }
667 }
668
669 return $string;
670 }
671
672 /**
673 * Provides generic db_rewrite_sql support for third party support modules.
674 *
675 * Invokes hook_translatable_rewrite_sql() for all activated support modules,
676 * and expects a boolean result whether the current query should be rewritten
677 * using the current $primary_table and $primary_field values.
678 *
679 * @see db_rewrite_sql(), category_translatable_rewrite_sql()
680 */
681 function translatable_db_rewrite_sql($query, $primary_table, $primary_field, $args = array()) {
682 $sql = array();
683
684 $applytranslatable = ($primary_table == 'n') && !preg_match('/'. $primary_table .'\.nid\s*=\s*\'?(%d|\d+)\'?/', $query);
685
686 if (module_exists('views')) {
687 $applytranslatable = $applytranslatable || ($primary_table == 'node');
688 // Don't rewrite if the view filters by language on its own.
689 if ($applytranslatable && preg_match('/\bnode_translatable\b/', $query)) {
690 $applytranslatable = FALSE;
691 }
692 }
693
694 foreach (module_implements('translatable_rewrite_sql') as $external) {
695 $function = $external .'_translatable_rewrite_sql';
696 if ($function($query, $primary_table, $primary_field, $args)) {
697 $applytranslatable = TRUE;
698 }
699 }
700
701 if ($applytranslatable) {
702 // Validate that the content type is enabled for translation.
703 if (preg_match('/'. $primary_table .'\.type\s*=\s*\'([^\']+)\'/', $query, $matches)) {
704 // @todo Missing ! here?
705 if (translatable_content_type_enabled($matches[1])) {
706 $applytranslatable = FALSE;
707 }
708 }
709 }
710
711 if ($applytranslatable) {
712 // When adding or editing a node we use the current locale.
713 // @doc Why? And what about the translation page (node/%/edit/translation)?
714 if (arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit')) {
715 $locales = "'". translatable_get_adminlocale() ."'";
716 }
717 else {
718 $locales = translatable_get_enabled_locales();
719 }
720 $sql['join'] = 'LEFT JOIN {node_translatable} translatable ON translatable.nid = '. $primary_table .'.'. $primary_field;
721 $sql['where'] = 'translatable.language IN ('. $locales .') OR translatable.any = 1';
722 }
723
724 return $sql;
725 }
726
727 /**
728 * Create the HTML for a language flag.
729 *
730 * @param $locale
731 * The ISO locale of the flag.
732 * @param $language
733 * The language name, used for alt and title.
734 * @param $block
735 * The name of the block in which the flag is displayed.
736 *
737 * @return
738 * HTML for a flag in the given language.
739 */
740 function theme_translatable_flag($locale, $language, $block = 'ui') {
741 $path = variable_get('translatable_block_'. $block .'_flagspath', drupal_get_path('module', 'translatable') .'/flags/*.png');
742 $src = str_replace('*', $locale, $path);
743 $attribs = array('class' => 'translatable-flag');
744 return theme('image', $src, $language, $language, $attribs);
745 }
746

  ViewVC Help
Powered by ViewVC 1.1.2