| 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 |
|