Index: modules/field/field.install =================================================================== RCS file: /cvs/drupal/drupal/modules/field/field.install,v retrieving revision 1.3 diff -u -r1.3 field.install --- modules/field/field.install 11 Feb 2009 04:45:57 -0000 1.3 +++ modules/field/field.install 11 Feb 2009 23:08:36 -0000 @@ -53,6 +53,12 @@ 'not null' => TRUE, 'default' => 0, ), + 'translatable' => array( + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + ), 'active' => array( 'type' => 'int', 'size' => 'tiny', Index: modules/field/field.crud.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/field/field.crud.inc,v retrieving revision 1.4 diff -u -r1.4 field.crud.inc --- modules/field/field.crud.inc 10 Feb 2009 03:16:14 -0000 1.4 +++ modules/field/field.crud.inc 11 Feb 2009 23:08:36 -0000 @@ -48,6 +48,8 @@ * - cardinality (integer) * The number of values the field can hold. Legal values are any * positive integer or FIELD_CARDINALITY_UNLIMITED. + * - translatable (integer) + * Whether the field is translatable * - locked (integer) * TODO: undefined. * - module (string, read-only) @@ -195,6 +197,7 @@ $field += array( 'cardinality' => 1, + 'translatable' => 0, 'locked' => FALSE, 'settings' => array(), ); Index: modules/field/field.module =================================================================== RCS file: /cvs/drupal/drupal/modules/field/field.module,v retrieving revision 1.4 diff -u -r1.4 field.module --- modules/field/field.module 10 Feb 2009 03:16:14 -0000 1.4 +++ modules/field/field.module 11 Feb 2009 23:08:36 -0000 @@ -597,4 +597,4 @@ /** * @} End of "defgroup field" - */ \ No newline at end of file + */ Index: modules/locale/locale.module =================================================================== RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v retrieving revision 1.237 diff -u -r1.237 locale.module --- modules/locale/locale.module 5 Feb 2009 00:32:46 -0000 1.237 +++ modules/locale/locale.module 11 Feb 2009 23:08:37 -0000 @@ -601,6 +601,56 @@ } /** + * Implementation of hook_field_attach_load(). + * + * For multilingual fields, populate the value for each + * $object->field_name[$delta] with the best match for the current language + * or the site default. Since hook_field_attach_load() is not persistently + * cached, we can add language specific information here in the knowledge + * it will only affect the curent request. Field rendering and formatting is + * agnostic to whether a field is multilingual or not, however we leave the + * #languages array in situ to allow other modules to access it if necessary. + */ +function locale_field_attach_load($obj_type, $object) { + global $language; + + // Only operate on translatable fields. + $fields = array(); + list(, , $bundle) = field_attach_extract_ids($obj_type, $object); + $instances = field_info_instances($bundle); + foreach ($instances as $instance) { + $field = field_info_field($instance['field_name']); + if (!empty($field['translatable'])) { + $fields[] = $instance['field_name']; + } + } + if (empty($fields)) { + return; + } + + $default = language_default(); + foreach ($fields as $field_name) { + foreach ($object->$field_name as $delta => $item) { + $best_fit = array(); + // Use current language, if available. + if (isset($item['#languages'][$language->language])) { + $best_fit = $item['#languages'][$language->language]; + } + // Use default language, if available. + elseif (isset($item['#languages'][$default->language])) { + $best_fit = $item['#languages'][$default->language]; + } + // Use language neutral values, if available. + elseif (isset($item['#languages'][''])) { + $best_fit = $item['#languages']['']; + } + + $object->{$field_name}[$delta] = array_merge($item, $best_fit); + } + } +} + +/** * Theme locale translation filter selector. * * @ingroup themeable Index: modules/field/modules/field_sql_storage/field_sql_storage.module =================================================================== RCS file: /cvs/drupal/drupal/modules/field/modules/field_sql_storage/field_sql_storage.module,v retrieving revision 1.4 diff -u -r1.4 field_sql_storage.module --- modules/field/modules/field_sql_storage/field_sql_storage.module 10 Feb 2009 03:16:14 -0000 1.4 +++ modules/field/modules/field_sql_storage/field_sql_storage.module 11 Feb 2009 23:08:37 -0000 @@ -128,9 +128,17 @@ 'not null' => TRUE, 'description' => 'The sequence number for this data item, used for multi-value fields', ), + 'language' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The language for this data item.', + ), ), - 'primary key' => array('etid', 'entity_id', 'deleted', 'delta'), - // TODO : index on 'bundle' + 'primary key' => array('etid', 'entity_id', 'deleted', 'delta', 'language'), + // TODO : index on 'bundle'. + // TODO : consider an integer field for 'language'. ); // Add field columns. @@ -144,7 +152,7 @@ $revision = $current; $revision['description'] = 'Revision archive storage for field ' . $field['field_name']; $revision['revision_id']['description'] = 'The entity revision id this data is attached to'; - $revision['primary key'] = array('etid', 'revision_id', 'deleted', 'delta'); + $revision['primary key'] = array('etid', 'revision_id', 'deleted', 'delta', 'language'); return array( _field_sql_storage_tablename($field['field_name']) => $current, @@ -212,7 +220,7 @@ ->execute(); foreach ($results as $row) { - if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$field_name] < $field['cardinality']) { + if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || !empty($field['translatable']) || $delta_count[$row->entity_id][$field_name] < $field['cardinality']) { $item = array(); // For each column declared by the field, populate the item // from the prefixed database column. @@ -220,8 +228,17 @@ $item[$column] = $row->{_field_sql_storage_columnname($field_name, $column)}; } - // Add the item to the field values for the entity. - $additions[$row->entity_id][$field_name][] = $item; + // For translatable fields, put the multilingual values for each delta + // into a '#languages' property. This information can be safely cached + // in the field and object caches. + if ($field['translatable']) { + $item['language'] = empty($row->language) ? '' : $row->language; + $additions[$row->entity_id][$field_name][$row->delta]['#languages'][$item['language']] = $item; + } + else { + // Add the item to the field values for the entity. + $additions[$row->entity_id][$field_name][] = $item; + } $delta_count[$row->entity_id][$field_name]++; } } @@ -256,7 +273,7 @@ if ($object->$field_name) { // Prepare the multi-insert query. - $columns = array('etid', 'entity_id', 'revision_id', 'bundle', 'delta'); + $columns = array('etid', 'entity_id', 'revision_id', 'bundle', 'delta', 'language'); foreach ($field['columns'] as $column => $attributes) { $columns[] = _field_sql_storage_columnname($field_name, $column); } @@ -273,6 +290,7 @@ 'revision_id' => $vid, 'bundle' => $bundle, 'delta' => $delta, + 'language' => !empty($item->language) ? $item->language : '', ); foreach ($field['columns'] as $column => $attributes) { $record[_field_sql_storage_columnname($field_name, $column)] = isset($item[$column]) ? $item[$column] : NULL; @@ -282,7 +300,7 @@ $revision_query->values($record); } - if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field['cardinality']) { + if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && empty($field['translatable']) && ++$delta_count == $field['cardinality']) { break; } } @@ -385,4 +403,4 @@ ->condition('bundle', $bundle_old) ->execute(); } -} \ No newline at end of file +}