Projet

Général

Profil

Paste
Télécharger (11,2 ko) Statistiques
| Branche: | Révision:

root / drupal7 / modules / field / field.multilingual.inc @ 6d8023f2

1
<?php
2

    
3
/**
4
 * @file
5
 * Functions implementing Field API multilingual support.
6
 */
7

    
8
/**
9
 * @defgroup field_language Field Language API
10
 * @{
11
 * Handling of multilingual fields.
12
 *
13
 * Fields natively implement multilingual support, and all fields use the
14
 * following structure:
15
 * @code
16
 * $entity->{$field_name}[$langcode][$delta][$column_name]
17
 * @endcode
18
 * Every field can hold a single or multiple value for each language belonging
19
 * to the available languages set:
20
 * - For untranslatable fields this set only contains LANGUAGE_NONE.
21
 * - For translatable fields this set can contain any language code. By default
22
 *   it is the list returned by field_content_languages(), which contains all
23
 *   installed languages with the addition of LANGUAGE_NONE. This default can be
24
 *   altered by modules implementing hook_field_available_languages_alter().
25
 *
26
 * The available languages for a particular field are returned by
27
 * field_available_languages(). Whether a field is translatable is determined by
28
 * calling field_is_translatable(), which checks the $field['translatable']
29
 * property returned by field_info_field(), and whether there is at least one
30
 * translation handler available for the field. A translation handler is a
31
 * module registering itself via hook_entity_info() to handle field
32
 * translations.
33
 *
34
 * By default, _field_invoke() and _field_invoke_multiple() are processing a
35
 * field in all available languages, unless they are given a language
36
 * suggestion. Based on that suggestion, _field_language_suggestion() determines
37
 * the languages to act on.
38
 *
39
 * Most field_attach_*() functions act on all available languages, except for
40
 * the following:
41
 * - field_attach_form() only takes a single language code, specifying which
42
 *   language the field values will be submitted in.
43
 * - field_attach_view() requires the language the entity will be displayed in.
44
 *   Since it is unknown whether a field translation exists for the requested
45
 *   language, the translation handler is responsible for performing one of the
46
 *   following actions:
47
 *   - Ignore missing translations, i.e. do not show any field values for the
48
 *     requested language. For example, see locale_field_language_alter().
49
 *   - Provide a value in a different language as fallback. By default, the
50
 *     fallback logic is applied separately to each field to ensure that there
51
 *     is a value for each field to display.
52
 *   The field language fallback logic relies on the global language fallback
53
 *   configuration. Therefore, the displayed field values can be in the
54
 *   requested language, but may be different if no values for the requested
55
 *   language are available. The default language fallback rules inspect all the
56
 *   enabled languages ordered by their weight. This behavior can be altered or
57
 *   even disabled by modules implementing hook_field_language_alter(), making
58
 *   it possible to choose the first approach. The display language for each
59
 *   field is returned by field_language().
60
 *
61
 * See @link field Field API @endlink for information about the other parts of
62
 * the Field API.
63
 */
64

    
65
/**
66
 * Implements hook_multilingual_settings_changed().
67
 */
68
function field_multilingual_settings_changed() {
69
  field_info_cache_clear();
70
}
71

    
72
/**
73
 * Collects the available languages for the given entity type and field.
74
 *
75
 * If the given field has language support enabled, an array of available
76
 * languages will be returned, otherwise only LANGUAGE_NONE will be returned.
77
 * Since the default value for a 'translatable' entity property is FALSE, we
78
 * ensure that only entities that are able to handle translations actually get
79
 * translatable fields.
80
 *
81
 * @param $entity_type
82
 *   The type of the entity the field is attached to, e.g. 'node' or 'user'.
83
 * @param $field
84
 *   A field structure.
85
 *
86
 * @return
87
 *   An array of valid language codes.
88
 */
89
function field_available_languages($entity_type, $field) {
90
  static $drupal_static_fast;
91
  if (!isset($drupal_static_fast)) {
92
    $drupal_static_fast['field_languages'] = &drupal_static(__FUNCTION__);
93
  }
94
  $field_languages = &$drupal_static_fast['field_languages'];
95
  $field_name = $field['field_name'];
96

    
97
  if (!isset($field_languages[$entity_type][$field_name])) {
98
    // If the field has language support enabled we retrieve an (alterable) list
99
    // of enabled languages, otherwise we return just LANGUAGE_NONE.
100
    if (field_is_translatable($entity_type, $field)) {
101
      $languages = field_content_languages();
102
      // Let other modules alter the available languages.
103
      $context = array('entity_type' => $entity_type, 'field' => $field);
104
      drupal_alter('field_available_languages', $languages, $context);
105
      $field_languages[$entity_type][$field_name] = $languages;
106
    }
107
    else {
108
      $field_languages[$entity_type][$field_name] = array(LANGUAGE_NONE);
109
    }
110
  }
111

    
112
  return $field_languages[$entity_type][$field_name];
113
}
114

    
115
/**
116
 * Process the given language suggestion based on the available languages.
117
 *
118
 * If a non-empty language suggestion is provided it must appear among the
119
 * available languages, otherwise it will be ignored.
120
 *
121
 * @param $available_languages
122
 *   An array of valid language codes.
123
 * @param $language_suggestion
124
 *   A language code or an array of language codes keyed by field name.
125
 * @param $field_name
126
 *   The name of the field being processed.
127
 *
128
 * @return
129
 *   An array of valid language codes.
130
 */
131
function _field_language_suggestion($available_languages, $language_suggestion, $field_name) {
132
  // Handle possible language suggestions.
133
  if (!empty($language_suggestion)) {
134
    // We might have an array of language suggestions keyed by field name.
135
    if (is_array($language_suggestion) && isset($language_suggestion[$field_name])) {
136
      $language_suggestion = $language_suggestion[$field_name];
137
    }
138

    
139
    // If we have a language suggestion and the suggested language is available,
140
    // we return only it.
141
    if (in_array($language_suggestion, $available_languages)) {
142
      $available_languages = array($language_suggestion);
143
    }
144
  }
145

    
146
  return $available_languages;
147
}
148

    
149
/**
150
 * Returns available content languages.
151
 *
152
 * The languages that may be associated to fields include LANGUAGE_NONE.
153
 *
154
 * @return
155
 *   An array of language codes.
156
 */
157
function field_content_languages() {
158
  return array_keys(language_list() + array(LANGUAGE_NONE => NULL));
159
}
160

    
161
/**
162
 * Checks whether a field has language support.
163
 *
164
 * A field has language support enabled if its 'translatable' property is set to
165
 * TRUE, and its entity type has at least one translation handler registered.
166
 *
167
 * @param $entity_type
168
 *   The type of the entity the field is attached to.
169
 * @param $field
170
 *   A field data structure.
171
 *
172
 * @return
173
 *   TRUE if the field can be translated.
174
 */
175
function field_is_translatable($entity_type, $field) {
176
  return $field['translatable'] && field_has_translation_handler($entity_type);
177
}
178

    
179
/**
180
 * Checks if a module is registered as a translation handler for a given entity.
181
 *
182
 * If no handler is passed, simply check if there is any translation handler
183
 * enabled for the given entity type.
184
 *
185
 * @param $entity_type
186
 *   The type of the entity whose fields are to be translated.
187
 * @param $handler
188
 *   (optional) The name of the handler to be checked. Defaults to NULL.
189
 *
190
 * @return
191
 *   TRUE, if the given handler is allowed to manage field translations. If no
192
 *   handler is passed, TRUE means there is at least one registered translation
193
 *   handler.
194
 */
195
function field_has_translation_handler($entity_type, $handler = NULL) {
196
  $entity_info = entity_get_info($entity_type);
197

    
198
  if (isset($handler)) {
199
    return !empty($entity_info['translation'][$handler]);
200
  }
201
  elseif (isset($entity_info['translation'])) {
202
    foreach ($entity_info['translation'] as $handler_info) {
203
      // The translation handler must use a non-empty data structure.
204
      if (!empty($handler_info)) {
205
        return TRUE;
206
      }
207
    }
208
  }
209

    
210
  return FALSE;
211
}
212

    
213
/**
214
 * Ensures that a given language code is valid.
215
 *
216
 * Checks whether the given language is one of the enabled languages. Otherwise,
217
 * it returns the current, global language; or the site's default language, if
218
 * the additional parameter $default is TRUE.
219
 *
220
 * @param $langcode
221
 *   The language code to validate.
222
 * @param $default
223
 *   Whether to return the default language code or the current language code in
224
 *   case $langcode is invalid.
225
 * @return
226
 *   A valid language code.
227
 */
228
function field_valid_language($langcode, $default = TRUE) {
229
  $enabled_languages = field_content_languages();
230
  if (in_array($langcode, $enabled_languages)) {
231
    return $langcode;
232
  }
233
  global $language_content;
234
  return $default ? language_default('language') : $language_content->language;
235
}
236

    
237
/**
238
 * Returns the display language for the fields attached to the given entity.
239
 *
240
 * The actual language for each given field is determined based on the requested
241
 * language and the actual data available in the fields themselves.
242
 * If there is no registered translation handler for the given entity type, the
243
 * display language to be used is just LANGUAGE_NONE, as no other language code
244
 * is allowed by field_available_languages().
245
 * If translation handlers are found, we let modules provide alternative display
246
 * languages for fields not having the requested language available.
247
 * Core language fallback rules are provided by locale_field_language_fallback()
248
 * which is called by locale_field_language_alter().
249
 *
250
 * @param $entity_type
251
 *   The type of $entity.
252
 * @param $entity
253
 *   The entity to be displayed.
254
 * @param $field_name
255
 *   (optional) The name of the field to be displayed. Defaults to NULL. If
256
 *   no value is specified, the display languages for every field attached to
257
 *   the given entity will be returned.
258
 * @param $langcode
259
 *   (optional) The language code $entity has to be displayed in. Defaults to
260
 *   NULL. If no value is given the current language will be used.
261
 *
262
 * @return
263
 *   A language code if a field name is specified, an array of language codes
264
 *   keyed by field name otherwise.
265
 */
266
function field_language($entity_type, $entity, $field_name = NULL, $langcode = NULL) {
267
  $display_languages = &drupal_static(__FUNCTION__, array());
268
  list($id, , $bundle) = entity_extract_ids($entity_type, $entity);
269
  $langcode = field_valid_language($langcode, FALSE);
270

    
271
  if (!isset($display_languages[$entity_type][$id][$langcode])) {
272
    $display_language = array();
273

    
274
    // By default display language is set to LANGUAGE_NONE if the field
275
    // translation is not available. It is up to translation handlers to
276
    // implement language fallback rules.
277
    foreach (field_info_instances($entity_type, $bundle) as $instance) {
278
      $display_language[$instance['field_name']] = isset($entity->{$instance['field_name']}[$langcode]) ? $langcode : LANGUAGE_NONE;
279
    }
280

    
281
    if (field_has_translation_handler($entity_type)) {
282
      $context = array(
283
        'entity_type' => $entity_type,
284
        'entity' => $entity,
285
        'language' => $langcode,
286
      );
287
      drupal_alter('field_language', $display_language, $context);
288
    }
289

    
290
    $display_languages[$entity_type][$id][$langcode] = $display_language;
291
  }
292

    
293
  $display_language = $display_languages[$entity_type][$id][$langcode];
294

    
295
  // Single-field mode.
296
  if (isset($field_name)) {
297
    return isset($display_language[$field_name]) ? $display_language[$field_name] : FALSE;
298
  }
299

    
300
  return $display_language;
301
}