diff --git a/feeds.info b/feeds.info
index 11934e0..04d3b69 100644
--- a/feeds.info
+++ b/feeds.info
@@ -38,6 +38,7 @@ files[] = tests/feeds_mapper_field.test
files[] = tests/feeds_mapper_file.test
files[] = tests/feeds_mapper_hooks.test
files[] = tests/feeds_mapper_link.test
+files[] = tests/feeds_mapper_multilingual_fields.test
files[] = tests/feeds_mapper_path.test
files[] = tests/feeds_mapper_profile.test
files[] = tests/feeds_mapper_unique.test
diff --git a/mappers/date.inc b/mappers/date.inc
index d5ea81f..c75f125 100644
--- a/mappers/date.inc
+++ b/mappers/date.inc
@@ -37,7 +37,7 @@ function date_feeds_processor_targets($entity_type, $bundle_name) {
/**
* Callback for setting date values.
*/
-function date_feeds_set_target(FeedsSource $source, $entity, $target, array $values) {
+function date_feeds_set_target(FeedsSource $source, $entity, $target, array $values, array $mapping) {
list($field_name, $sub_field) = explode(':', $target, 2);
$delta = 0;
@@ -56,7 +56,7 @@ function date_feeds_set_target(FeedsSource $source, $entity, $target, array $val
}
}
- $value->buildDateField($entity, $field_name, $delta);
+ $value->buildDateField($entity, $field_name, $delta, $mapping['language']);
$delta++;
}
}
diff --git a/mappers/entity_translation.inc b/mappers/entity_translation.inc
new file mode 100644
index 0000000..2ea5abc
--- /dev/null
+++ b/mappers/entity_translation.inc
@@ -0,0 +1,82 @@
+feeds_item->entity_type;
+
+ // Check that it's a real entity type, and translation is enabled.
+ if (!entity_get_info($entity_type) || !entity_translation_enabled($entity_type, $entity)) {
+ return;
+ }
+
+ if (!$handler = entity_translation_get_handler($entity_type, $entity)) {
+ return;
+ }
+
+ list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+
+ $languages_seen = array();
+
+ foreach (field_info_instances($entity_type, $bundle) as $instance) {
+ $field_name = $instance['field_name'];
+
+ // No values in this field, skip it.
+ if (empty($entity->$field_name)) {
+ continue;
+ }
+
+ // Not translatable.
+ if (($info = field_info_field($field_name)) && !$info['translatable']) {
+ continue;
+ }
+
+ // Init the translation handler.
+ if (empty($handler->getTranslations()->original)) {
+ $handler->initTranslations();
+ }
+
+ // Avoid invalid user configuration. Entity translation does this when
+ // loading the translation overview page.
+ if (count($entity->$field_name) === 1 && key($entity->$field_name) === LANGUAGE_NONE) {
+ $entity->{$field_name}[$handler->getLanguage()] = $entity->{$field_name}[LANGUAGE_NONE];
+ $entity->{$field_name}[LANGUAGE_NONE] = array();
+ }
+
+ // Look for languages we haven't created a translation for yet.
+ foreach (array_diff_key($entity->$field_name, $languages_seen) as $language => $v) {
+ if ($language === LANGUAGE_NONE) {
+ continue;
+ }
+
+ $languages_seen[$language] = TRUE;
+
+ if ($language === $handler->getLanguage()) {
+ continue;
+ }
+
+ $translation = array(
+ 'translate' => 0,
+ 'status' => 1,
+ 'language' => $language,
+ 'source' => $handler->getLanguage(),
+ );
+
+ $handler->setTranslation($translation, $entity);
+ }
+ }
+
+ // Loop through every language for the site, and remove translations for the
+ // ones that don't have any values.
+ foreach (language_list() as $language) {
+ if (!isset($languages_seen[$language->language])) {
+ $handler->removeTranslation($language->language);
+ }
+ }
+}
diff --git a/mappers/file.inc b/mappers/file.inc
index d46c319..07349f2 100644
--- a/mappers/file.inc
+++ b/mappers/file.inc
@@ -54,7 +54,9 @@ function file_feeds_processor_targets($entity_type, $bundle_name) {
/**
* Callback for mapping file fields.
*/
-function file_feeds_set_target(FeedsSource $source, $entity, $target, array $values) {
+function file_feeds_set_target(FeedsSource $source, $entity, $target, array $values, array $mapping) {
+ $language = $mapping['language'];
+
// Add default of uri for backwards compatibility.
list($field_name, $sub_field) = explode(':', $target . ':uri');
$info = field_info_field($field_name);
@@ -90,22 +92,22 @@ function file_feeds_set_target(FeedsSource $source, $entity, $target, array $val
}
// Populate entity.
- $field = isset($entity->$field_name) ? $entity->$field_name : array(LANGUAGE_NONE => array());
+ $field = isset($entity->$field_name) ? $entity->$field_name : array($language => array());
$delta = 0;
foreach ($values as $v) {
if ($info['cardinality'] == $delta) {
break;
}
- if (!isset($field[LANGUAGE_NONE][$delta])) {
- $field[LANGUAGE_NONE][$delta] = array();
+ if (!isset($field[$language][$delta])) {
+ $field[$language][$delta] = array();
}
switch ($sub_field) {
case 'alt':
case 'title':
case 'description':
- $field[LANGUAGE_NONE][$delta][$sub_field] = $v;
+ $field[$language][$delta][$sub_field] = $v;
break;
case 'uri':
@@ -113,9 +115,9 @@ function file_feeds_set_target(FeedsSource $source, $entity, $target, array $val
try {
$v->setAllowedExtensions($instance_info['settings']['file_extensions']);
$file = $v->getFile($destination);
- $field[LANGUAGE_NONE][$delta] += (array) $file;
+ $field[$language][$delta] += (array) $file;
// @todo: Figure out how to properly populate this field.
- $field[LANGUAGE_NONE][$delta]['display'] = 1;
+ $field[$language][$delta]['display'] = 1;
}
catch (Exception $e) {
watchdog('feeds', check_plain($e->getMessage()));
diff --git a/mappers/link.inc b/mappers/link.inc
index e9c3632..1dc19dc 100644
--- a/mappers/link.inc
+++ b/mappers/link.inc
@@ -39,10 +39,12 @@ function link_feeds_processor_targets($entity_type, $bundle_name) {
/**
* Callback for mapping link fields.
*/
-function link_feeds_set_target(FeedsSource $source, $entity, $target, array $values) {
+function link_feeds_set_target(FeedsSource $source, $entity, $target, array $values, array $mapping) {
+ $language = $mapping['language'];
+
list($field_name, $column) = explode(':', $target);
- $field = isset($entity->$field_name) ? $entity->$field_name : array('und' => array());
+ $field = isset($entity->$field_name) ? $entity->$field_name : array($language => array());
$delta = 0;
foreach ($values as $value) {
@@ -51,7 +53,7 @@ function link_feeds_set_target(FeedsSource $source, $entity, $target, array $val
}
if (is_scalar($value)) {
- $field['und'][$delta][$column] = (string) $value;
+ $field[$language][$delta][$column] = (string) $value;
}
$delta++;
}
diff --git a/mappers/list.inc b/mappers/list.inc
index 8c5dc36..6a30829 100644
--- a/mappers/list.inc
+++ b/mappers/list.inc
@@ -49,8 +49,10 @@ function list_feeds_processor_targets($entity_type, $bundle_name) {
/**
* Callback for setting list_boolean fields.
*/
-function list_feeds_set_boolean_target(FeedsSource $source, $entity, $target, array $values) {
- $field = isset($entity->$target) ? $entity->$target : array(LANGUAGE_NONE => array());
+function list_feeds_set_boolean_target(FeedsSource $source, $entity, $target, array $values, array $mapping) {
+ $language = $mapping['language'];
+
+ $field = isset($entity->$target) ? $entity->$target : array($language => array());
foreach ($values as $value) {
@@ -58,7 +60,7 @@ function list_feeds_set_boolean_target(FeedsSource $source, $entity, $target, ar
$value = $value->getValue();
}
- $field[LANGUAGE_NONE][] = array('value' => (int) (bool) $value);
+ $field[$language][] = array('value' => (int) (bool) $value);
}
$entity->$target = $field;
diff --git a/mappers/locale.inc b/mappers/locale.inc
new file mode 100644
index 0000000..4d18dcc
--- /dev/null
+++ b/mappers/locale.inc
@@ -0,0 +1,90 @@
+processor->entityType();
+ $translatable = _locale_feeds_target_is_translatable($entity_type, $mapping['target']);
+
+ $mapping += array('field_language' => LANGUAGE_NONE);
+
+ // This is an invalid configuration that can come from disabling
+ // entity_translation.
+ $error = $mapping['field_language'] !== LANGUAGE_NONE && !$translatable;
+
+ // Nothing to see here.
+ if (!$error && !$translatable) {
+ return;
+ }
+
+ if ($error) {
+ return t('Language: @error', array('@error' => t('Error')));
+ }
+
+ $language_options = array(LANGUAGE_NONE => t('Language neutral')) + locale_language_list('name');
+
+ return t('Language: %lang', array('%lang' => $language_options[$mapping['field_language']]));
+}
+
+function locale_feeds_form_callback(array $mapping, array $target, array $form, array $form_state) {
+ $form = array();
+
+ $entity_type = $form_state['build_info']['args'][0]->processor->entityType();
+
+ $translatable = _locale_feeds_target_is_translatable($entity_type, $mapping['target']);
+ $mapping += array('field_language' => LANGUAGE_NONE);
+
+ // This is an invalid configuration that can come from disabling
+ // entity_translation.
+ $error = $mapping['field_language'] !== LANGUAGE_NONE && !$translatable;
+
+ // Nothing to see here.
+ if (!$error && !$translatable) {
+ return $form;
+ }
+
+ $language_options = array(LANGUAGE_NONE => t('Language neutral'));
+
+ if (!$error) {
+ $language_options += locale_language_list('name');
+ }
+
+ $form['field_language'] = array(
+ '#type' => 'select',
+ '#title' => t('Language'),
+ '#options' => $language_options,
+ '#default_value' => $mapping['field_language'],
+ );
+
+ return $form;
+}
+
+function _locale_feeds_target_is_translatable($entity_type, $target) {
+ list($field_name) = explode(':', $target, 2);
+
+ $info = field_info_field($field_name);
+
+ return !empty($info) && field_is_translatable($entity_type, $info);
+}
diff --git a/mappers/number.inc b/mappers/number.inc
index 7f9a0d8..406b4f8 100644
--- a/mappers/number.inc
+++ b/mappers/number.inc
@@ -34,9 +34,11 @@ function number_feeds_processor_targets($entity_type, $bundle_name) {
/**
* Callback for mapping number fields.
*/
-function number_feeds_set_target(FeedsSource $source, $entity, $target, array $values) {
+function number_feeds_set_target(FeedsSource $source, $entity, $target, array $values, array $mapping) {
+ $language = $mapping['language'];
+
// Iterate over all values.
- $field = isset($entity->$target) ? $entity->$target : array('und' => array());
+ $field = isset($entity->$target) ? $entity->$target : array($language => array());
foreach ($values as $value) {
@@ -45,7 +47,7 @@ function number_feeds_set_target(FeedsSource $source, $entity, $target, array $v
}
if (is_numeric($value)) {
- $field['und'][] = array('value' => $value);
+ $field[$language][] = array('value' => $value);
}
}
diff --git a/mappers/taxonomy.inc b/mappers/taxonomy.inc
index 6fbdec6..6fbe3e6 100644
--- a/mappers/taxonomy.inc
+++ b/mappers/taxonomy.inc
@@ -85,6 +85,8 @@ function taxonomy_feeds_processor_targets($entity_type, $bundle_name) {
* Callback for mapping taxonomy terms.
*/
function taxonomy_feeds_set_target(FeedsSource $source, $entity, $target, array $terms, array $mapping) {
+ $language = $mapping['language'];
+
// Add in default values.
$mapping += array(
'term_search' => FEEDS_TAXONOMY_SEARCH_TERM_NAME,
@@ -118,10 +120,14 @@ function taxonomy_feeds_set_target(FeedsSource $source, $entity, $target, array
->range(0, 1);
- $field = isset($entity->$target) ? $entity->$target : array('und' => array());
+ $field = isset($entity->$target) ? $entity->$target : array($language => array());
+
+ if (!isset($field[$language])) {
+ $field[$language] = array();
+ }
// Allow for multiple mappings to the same target.
- $delta = count($field['und']);
+ $delta = count($field[$language]);
// Iterate over all values.
foreach ($terms as $term) {
@@ -181,7 +187,7 @@ function taxonomy_feeds_set_target(FeedsSource $source, $entity, $target, array
}
if ($tid && isset($cache['allowed_values'][$target][$tid])) {
- $field['und'][] = array('tid' => $tid);
+ $field[$language][] = array('tid' => $tid);
$delta++;
}
}
diff --git a/mappers/text.inc b/mappers/text.inc
index aa9c2e1..1cf76bf 100644
--- a/mappers/text.inc
+++ b/mappers/text.inc
@@ -49,6 +49,8 @@ function text_feeds_processor_targets($entity_type, $bundle_name) {
* Callback for mapping text fields.
*/
function text_feeds_set_target(FeedsSource $source, $entity, $target, array $values, array $mapping) {
+ $language = $mapping['language'];
+
list($field_name, $column) = explode(':', $target . ':value');
if ($column === 'value' && isset($source->importer->processor->config['input_format'])) {
@@ -59,7 +61,7 @@ function text_feeds_set_target(FeedsSource $source, $entity, $target, array $val
);
}
- $field = isset($entity->$field_name) ? $entity->$field_name : array('und' => array());
+ $field = isset($entity->$field_name) ? $entity->$field_name : array($language => array());
// Iterate over all values.
$delta = 0;
@@ -71,10 +73,10 @@ function text_feeds_set_target(FeedsSource $source, $entity, $target, array $val
if (is_scalar($value) && strlen($value)) {
- $field['und'][$delta][$column] = (string) $value;
+ $field[$language][$delta][$column] = (string) $value;
if (isset($mapping['format'])) {
- $field['und'][$delta]['format'] = $mapping['format'];
+ $field[$language][$delta]['format'] = $mapping['format'];
}
}
diff --git a/plugins/FeedsNodeProcessor.inc b/plugins/FeedsNodeProcessor.inc
index 2cfdf30..d04d546 100644
--- a/plugins/FeedsNodeProcessor.inc
+++ b/plugins/FeedsNodeProcessor.inc
@@ -40,7 +40,7 @@ class FeedsNodeProcessor extends FeedsProcessor {
$node->type = $this->bundle();
$node->changed = REQUEST_TIME;
$node->created = REQUEST_TIME;
- $node->language = LANGUAGE_NONE;
+ $node->language = $this->config['language'];
$node->is_new = TRUE;
node_object_prepare($node);
// Populate properties that are set by node_object_prepare().
diff --git a/plugins/FeedsParser.inc b/plugins/FeedsParser.inc
index 8b430c0..7e86e9e 100644
--- a/plugins/FeedsParser.inc
+++ b/plugins/FeedsParser.inc
@@ -548,13 +548,13 @@ class FeedsDateTimeElement extends FeedsElement {
* Helper method for buildDateField(). Build a FeedsDateTimeElement object
* from a standard formatted node.
*/
- protected static function readDateField($entity, $field_name, $delta = 0) {
+ protected static function readDateField($entity, $field_name, $delta = 0, $language = LANGUAGE_NONE) {
$ret = new FeedsDateTimeElement();
- if (isset($entity->{$field_name}['und'][$delta]['date']) && $entity->{$field_name}['und'][$delta]['date'] instanceof FeedsDateTime) {
- $ret->start = $entity->{$field_name}['und'][$delta]['date'];
+ if (isset($entity->{$field_name}[$language][$delta]['date']) && $entity->{$field_name}[$language][$delta]['date'] instanceof FeedsDateTime) {
+ $ret->start = $entity->{$field_name}[$language][$delta]['date'];
}
- if (isset($entity->{$field_name}['und'][$delta]['date2']) && $entity->{$field_name}['und'][$delta]['date2'] instanceof FeedsDateTime) {
- $ret->end = $entity->{$field_name}['und'][$delta]['date2'];
+ if (isset($entity->{$field_name}[$language][$delta]['date2']) && $entity->{$field_name}[$language][$delta]['date2'] instanceof FeedsDateTime) {
+ $ret->end = $entity->{$field_name}[$language][$delta]['date2'];
}
return $ret;
}
@@ -569,10 +569,10 @@ class FeedsDateTimeElement extends FeedsElement {
* @param int $delta
* The delta in the field.
*/
- public function buildDateField($entity, $field_name, $delta = 0) {
+ public function buildDateField($entity, $field_name, $delta = 0, $language = LANGUAGE_NONE) {
$info = field_info_field($field_name);
- $oldfield = FeedsDateTimeElement::readDateField($entity, $field_name, $delta);
+ $oldfield = FeedsDateTimeElement::readDateField($entity, $field_name, $delta, $language);
// Merge with any preexisting objects on the field; we take precedence.
$oldfield = $this->merge($oldfield);
$use_start = $oldfield->start;
@@ -605,27 +605,27 @@ class FeedsDateTimeElement extends FeedsElement {
$db_tz = new DateTimeZone($db_tz);
if (!isset($entity->{$field_name})) {
- $entity->{$field_name} = array('und' => array());
+ $entity->{$field_name} = array($language => array());
}
if ($use_start) {
- $entity->{$field_name}['und'][$delta]['timezone'] = $use_start->getTimezone()->getName();
- $entity->{$field_name}['und'][$delta]['offset'] = $use_start->getOffset();
+ $entity->{$field_name}[$language][$delta]['timezone'] = $use_start->getTimezone()->getName();
+ $entity->{$field_name}[$language][$delta]['offset'] = $use_start->getOffset();
$use_start->setTimezone($db_tz);
- $entity->{$field_name}['und'][$delta]['date'] = $use_start;
+ $entity->{$field_name}[$language][$delta]['date'] = $use_start;
/**
* @todo the date_type_format line could be simplified based upon a patch
* DO issue #259308 could affect this, follow up on at some point.
* Without this, all granularity info is lost.
* $use_start->format(date_type_format($field['type'], $use_start->granularity));
*/
- $entity->{$field_name}['und'][$delta]['value'] = $use_start->format(date_type_format($info['type']));
+ $entity->{$field_name}[$language][$delta]['value'] = $use_start->format(date_type_format($info['type']));
}
if ($use_end) {
// Don't ever use end to set timezone (for now)
- $entity->{$field_name}['und'][$delta]['offset2'] = $use_end->getOffset();
+ $entity->{$field_name}[$language][$delta]['offset2'] = $use_end->getOffset();
$use_end->setTimezone($db_tz);
- $entity->{$field_name}['und'][$delta]['date2'] = $use_end;
- $entity->{$field_name}['und'][$delta]['value2'] = $use_end->format(date_type_format($info['type']));
+ $entity->{$field_name}[$language][$delta]['date2'] = $use_end;
+ $entity->{$field_name}[$language][$delta]['value2'] = $use_end->format(date_type_format($info['type']));
}
}
}
diff --git a/plugins/FeedsProcessor.inc b/plugins/FeedsProcessor.inc
index ab0df88..662f595 100644
--- a/plugins/FeedsProcessor.inc
+++ b/plugins/FeedsProcessor.inc
@@ -719,10 +719,15 @@ abstract class FeedsProcessor extends FeedsPlugin {
if (isset($targets[$target]['preprocess_callbacks'])) {
foreach ($targets[$target]['preprocess_callbacks'] as $callback) {
- call_user_func_array($callback, array($source, $target_item, $target, &$mapping));
+ call_user_func_array($callback, array($source, $target_item, $targets[$target], &$mapping));
}
}
+ // Ensure there's always a language set.
+ if (empty($mapping['language'])) {
+ $mapping['language'] = LANGUAGE_NONE;
+ }
+
// Map the source element's value to the target.
// If the mapping specifies a callback method, use the callback instead of
// setTargetElement().
@@ -765,6 +770,7 @@ abstract class FeedsProcessor extends FeedsPlugin {
'input_format' => NULL,
'skip_hash_check' => FALSE,
'bundle' => $bundle,
+ 'language' => LANGUAGE_NONE,
);
}
@@ -791,6 +797,16 @@ abstract class FeedsProcessor extends FeedsPlugin {
);
}
+ if (module_exists('locale') && !empty($info['entity keys']['language'])) {
+ $form['language'] = array(
+ '#type' => 'select',
+ '#options' => array(LANGUAGE_NONE => t('Language neutral')) + locale_language_list('name'),
+ '#title' => t('Language'),
+ '#required' => TRUE,
+ '#default_value' => $this->config['language'],
+ );
+ }
+
$tokens = array('@entities' => strtolower($info['label plural']));
$form['update_existing'] = array(
diff --git a/tests/feeds/multilingual.csv b/tests/feeds/multilingual.csv
new file mode 100644
index 0000000..902dec7
--- /dev/null
+++ b/tests/feeds/multilingual.csv
@@ -0,0 +1,2 @@
+"guid","title","title_fr","body","body_fr","link","link_fr","number","number_fr","image","image_fr","category","category_fr"
+1,"Testing Multilingual Feeds 1","Teste Feeds Multilingue 1","This is the body","Ceci est la corps","http://google.ca","http://google.fr",1000,2000,"public://images/foosball.jpeg","public://images/la fayette.jpeg","News","Nouvelles"
diff --git a/tests/feeds_mapper_multilingual_fields.test b/tests/feeds_mapper_multilingual_fields.test
new file mode 100644
index 0000000..3620c31
--- /dev/null
+++ b/tests/feeds_mapper_multilingual_fields.test
@@ -0,0 +1,223 @@
+ 'Mapper: Multilingual fields',
+ 'description' => 'Tests Feeds multilingual support.',
+ 'group' => 'Feeds',
+ 'dependencies' => array('entity_translation'),
+ );
+ }
+
+ public function setUp() {
+ $modules = array(
+ 'locale',
+ 'entity_translation',
+ 'link',
+ 'number',
+ );
+
+ $permissions = array(
+ 'administer entity translation',
+ 'translate any entity',
+ 'administer languages',
+ );
+
+ parent::setUp($modules, $permissions);
+
+ // Add Categories vocabulary.
+ $edit = array(
+ 'name' => 'Categories',
+ 'machine_name' => 'categories',
+ );
+ $this->drupalPost('admin/structure/taxonomy/add', $edit, 'Save');
+
+ // Create content type.
+ $typename = $this->createContentType(array(),
+ array(
+ 'number' => 'number_integer',
+ 'link' => 'link_field',
+ 'image' => 'image',
+ )
+ );
+
+ // Create term reference field.
+ $field = array(
+ 'field_name' => 'field_category',
+ 'type' => 'taxonomy_term_reference',
+ 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+ 'settings' => array(
+ 'allowed_values' => array(
+ array(
+ 'vocabulary' => 'categories',
+ 'parent' => 0,
+ ),
+ ),
+ ),
+ );
+ field_create_field($field);
+
+ // Add term reference field to article bundle.
+ $this->instance = array(
+ 'field_name' => 'field_category',
+ 'bundle' => $typename,
+ 'entity_type' => 'node',
+ 'widget' => array(
+ 'type' => 'options_select',
+ ),
+ 'display' => array(
+ 'default' => array(
+ 'type' => 'taxonomy_term_reference_link',
+ ),
+ ),
+ );
+ field_create_instance($this->instance);
+
+ $this->setupMultilingual($typename);
+
+ // Copy directory of source files, CSV file expects them in public://images.
+ $this->copyDir($this->absolutePath() . '/tests/feeds/assets', 'public://images');
+
+ // Create an importer configuration with basic mapping.
+ $this->createImporterConfiguration('Test multilingual fields import from CSV', 'node');
+ $this->setPlugin('node', 'FeedsCSVParser');
+ $this->setPlugin('node', 'FeedsFileFetcher');
+ $this->setSettings('node', NULL, array('content_type' => ''));
+ $this->setSettings('node', 'FeedsNodeProcessor', array('bundle' => $typename, 'language' => 'en'));
+ $this->addMappings('node', array(
+ 0 => array(
+ 'source' => 'guid',
+ 'target' => 'guid',
+ 'unique' => TRUE,
+ ),
+ 1 => array(
+ 'source' => 'title',
+ 'target' => 'title',
+ ),
+ 2 => array(
+ 'source' => 'body',
+ 'target' => 'body',
+ 'field_language' => 'en',
+ ),
+ 3 => array(
+ 'source' => 'body_fr',
+ 'target' => 'body',
+ 'field_language' => 'fr',
+ ),
+ 4 => array(
+ 'source' => 'number',
+ 'target' => 'field_number',
+ 'field_language' => 'en',
+ ),
+ 5 => array(
+ 'source' => 'number_fr',
+ 'target' => 'field_number',
+ 'field_language' => 'fr',
+ ),
+ 6 => array(
+ 'source' => 'link',
+ 'target' => 'field_link:url',
+ 'field_language' => 'en',
+ ),
+ 7 => array(
+ 'source' => 'link_fr',
+ 'target' => 'field_link:url',
+ 'field_language' => 'fr',
+ ),
+ 8 => array(
+ 'source' => 'image',
+ 'target' => 'field_image:uri',
+ 'field_language' => 'en',
+ ),
+ 9 => array(
+ 'source' => 'image_fr',
+ 'target' => 'field_image:uri',
+ 'field_language' => 'fr',
+ ),
+ 10 => array(
+ 'source' => 'category',
+ 'target' => 'field_category',
+ 'field_language' => 'en',
+ 'autocreate' => TRUE,
+ ),
+ 11 => array(
+ 'source' => 'category_fr',
+ 'target' => 'field_category',
+ 'field_language' => 'fr',
+ 'autocreate' => TRUE,
+ ),
+ ));
+ }
+
+ /**
+ * Tests multilingual mappings to translatable fields (entity translation)
+ */
+ public function testMultilingualFieldMappings() {
+ $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual.csv');
+ $this->assertText(t('Created 1 node'));
+
+ // @todo Figure out why this is required for the node to contain the French
+ // translation.
+ $this->drupalGet('node/1/translate');
+
+ $node = node_load(1);
+
+ $this->assertEqual('This is the body', $node->body['en'][0]['value'], 'English body field has expected value.');
+ $this->assertEqual(1000, $node->field_number['en'][0]['value'], 'English field_number field has expected value.');
+ $this->assertEqual('http://google.ca', $node->field_link['en'][0]['url'], 'English field_link field has expected value.');
+ $this->assertEqual('foosball.jpeg', $node->field_image['en'][0]['filename'], 'English field_image field has expected value.');
+ $this->assertEqual(1, $node->field_category['en'][0]['tid'], 'English field_category field has expected value.');
+
+ $this->assertEqual('Ceci est la corps', $node->body['fr'][0]['value'], 'French body field has expected value.');
+ $this->assertEqual(2000, $node->field_number['fr'][0]['value'], 'French field_number field has expected value.');
+ $this->assertEqual('http://google.fr', $node->field_link['fr'][0]['url'], 'French field_link field has expected value.');
+ $this->assertEqual('la fayette.jpeg', $node->field_image['fr'][0]['filename'], 'French field_image field has expected value.');
+ $this->assertEqual(2, $node->field_category['fr'][0]['tid'], 'French field_category field has expected value.');
+ }
+
+ /**
+ * Configures Drupal to be multilingual.
+ */
+ public function setupMultilingual($typename) {
+ // Setup Other Language (french).
+ $edit = array(
+ 'langcode' => 'fr',
+ );
+ $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+ $this->assertText(t('The language French has been created and can now be used.'));
+
+ // Enable entity field translation for content type.
+ $edit = array(
+ 'language_content_type' => 4,
+ 'entity_translation_hide_translation_links' => 1,
+ 'entity_translation_node_metadata' => 0,
+ );
+ $this->drupalPost('admin/structure/types/manage/' . $typename, $edit, t('Save content type'));
+
+ // Enable field translation on fields.
+ $edit = array(
+ 'field[translatable]' => 1,
+ );
+ $field_names = array(
+ 'body' => 'body',
+ 'field_number' => 'field_number',
+ 'field_link' => 'field_link',
+ 'field_image' => 'field_image',
+ 'field_category' => 'field_category',
+ );
+ foreach ($field_names as $field_name) {
+ $this->drupalPost("admin/structure/types/manage/{$typename}/fields/{$field_name}", $edit, t('Save settings'));
+ }
+ }
+
+}
diff --git a/tests/feeds_mapper_taxonomy.test b/tests/feeds_mapper_taxonomy.test
index 231235e..801b2d0 100644
--- a/tests/feeds_mapper_taxonomy.test
+++ b/tests/feeds_mapper_taxonomy.test
@@ -234,6 +234,7 @@ class FeedsMapperTaxonomyTestCase extends FeedsMapperTestCase {
$target = 'field_tags';
$mapping = array(
'term_search' => FEEDS_TAXONOMY_SEARCH_TERM_ID,
+ 'language' => LANGUAGE_NONE,
);
$source = FeedsSource::instance('tmp', 0);
@@ -284,6 +285,7 @@ class FeedsMapperTaxonomyTestCase extends FeedsMapperTestCase {
$target = 'field_tags';
$mapping = array(
'term_search' => FEEDS_TAXONOMY_SEARCH_TERM_GUID,
+ 'language' => LANGUAGE_NONE,
);
$source = FeedsSource::instance('tmp', 0);
diff --git a/tests/feeds_tests.info b/tests/feeds_tests.info
index df368ca..13fef97 100644
--- a/tests/feeds_tests.info
+++ b/tests/feeds_tests.info
@@ -6,4 +6,5 @@ core = 7.x
test_dependencies[] = date
test_dependencies[] = feeds_xpathparser
test_dependencies[] = link
+test_dependencies[] = entity_translation
hidden = TRUE
diff --git a/tests/feeds_tests.module b/tests/feeds_tests.module
index 1ddd2a6..a083df0 100644
--- a/tests/feeds_tests.module
+++ b/tests/feeds_tests.module
@@ -307,7 +307,7 @@ class FeedsTestsPreprocess {
*
* @see feeds_tests_feeds_processor_targets()
*/
- public static function callback(FeedsSource $source, $target_item, $target, array &$mapping) {
+ public static function callback(FeedsSource $source, $target_item, array $target, array &$mapping) {
$mapping['required_value'] = TRUE;
}