diff --git a/feeds.info b/feeds.info
index 0ce45e0..d51d76a 100644
--- a/feeds.info
+++ b/feeds.info
@@ -36,6 +36,7 @@ files[] = tests/feeds_mapper_date.test
files[] = tests/feeds_mapper_date_multiple.test
files[] = tests/feeds_mapper_field.test
files[] = tests/feeds_mapper_file.test
+files[] = tests/feeds_mapper_multilingual_fields.test
files[] = tests/feeds_mapper_path.test
files[] = tests/feeds_mapper_profile.test
files[] = tests/feeds_mapper.test
diff --git a/feeds.module b/feeds.module
index cba702d..b9cd6cf 100644
--- a/feeds.module
+++ b/feeds.module
@@ -896,6 +896,77 @@ function feeds_item_info_save($entity, $entity_id) {
}
/**
+ * Returns the language summary text for use in a mapper target summary_callback
+ *
+ * @param array $mapping
+ * Associative array of the mapping settings.
+ * @param array $target
+ * Array of target settings, as defined by the processor or
+ * hook_feeds_processor_targets_alter().
+ * @param array $form
+ * The whole mapping form.
+ * @param array $form_state
+ * The form state of the mapping form.
+ *
+ * @return string
+ * Returns, as a string that may contain HTML, the summary to display while
+ * the full form isn't visible.
+ * If the return value is empty, no summary and no option to view the form
+ * will be displayed.
+ */
+function feeds_mapper_summary_language($mapping, $target, $form, $form_state) {
+ if (module_exists('locale')) {
+ list($field_name) = explode(':', $mapping['target']);
+ $info = field_info_field($field_name);
+ if ($info['translatable']) {
+ $language_options = array(LANGUAGE_NONE => t('All languages')) + locale_language_list('name');
+ if (empty($mapping['language'])) {
+ return t('Language: @search', array('@search' => $language_options[LANGUAGE_NONE]));
+ }
+ return t('Language: @search', array('@search' => $language_options[$mapping['language']]));
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Returns tha language form for use in a mapper target form_callback
+ *
+ * @param array $mapping
+ * Associative array of the mapping settings.
+ * @param array $target
+ * Array of target settings, as defined by the processor or
+ * hook_feeds_processor_targets_alter().
+ * @param array $form
+ * The whole mapping form.
+ * @param array $form_state
+ * The form state of the mapping form.
+ *
+ * @return string
+ * Returns, as a string that may contain HTML, the summary to display while
+ * the full form isn't visible.
+ * If the return value is empty, no summary and no option to view the form
+ * will be displayed.
+ */
+function feeds_mapper_form_language($mapping, $target, $form, $form_state) {
+ $form = array();
+ if (module_exists('locale')) {
+ list($field_name) = explode(':', $mapping['target']);
+ $info = field_info_field($field_name);
+ if ($info['translatable']) {
+ $language_options = array(LANGUAGE_NONE => t('All languages')) + locale_language_list('name');
+ $form['language'] = array(
+ '#type' => 'select',
+ '#title' => t('Language'),
+ '#options' => $language_options,
+ '#default_value' => !empty($mapping['language']) ? $mapping['language'] : LANGUAGE_NONE,
+ );
+ }
+ }
+ return $form;
+}
+
+/**
* @}
*/
diff --git a/mappers/file.inc b/mappers/file.inc
index e9cbc26..3e015c9 100644
--- a/mappers/file.inc
+++ b/mappers/file.inc
@@ -21,6 +21,8 @@ function file_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
'callback' => 'file_feeds_set_target',
'description' => t('The URI of the @label field.', array('@label' => $instance['label'])),
'real_target' => $name,
+ 'summary_callback' => 'feeds_mapper_summary_language',
+ 'form_callback' => 'feeds_mapper_form_language',
);
if ($info['type'] == 'image') {
@@ -29,12 +31,16 @@ function file_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
'callback' => 'file_feeds_set_target',
'description' => t('The alt tag of the @label field.', array('@label' => $instance['label'])),
'real_target' => $name,
+ 'summary_callback' => 'feeds_mapper_summary_language',
+ 'form_callback' => 'feeds_mapper_form_language',
);
$targets[$name . ':title'] = array(
'name' => t('@label: Title', array('@label' => $instance['label'])),
'callback' => 'file_feeds_set_target',
'description' => t('The title of the @label field.', array('@label' => $instance['label'])),
'real_target' => $name,
+ 'summary_callback' => 'feeds_mapper_summary_language',
+ 'form_callback' => 'feeds_mapper_form_language',
);
}
}
@@ -48,11 +54,14 @@ function file_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
* user has decided to map to and $value contains the value of the feed item
* element the user has picked as a source.
*/
-function file_feeds_set_target($source, $entity, $target, array $values) {
+function file_feeds_set_target($source, $entity, $target, array $values, $mapping = array()) {
// Add default of uri for backwards compatibility.
list($field_name, $sub_field) = explode(':', $target . ':uri');
$info = field_info_field($field_name);
+ // Set the language of the field depending on the mapping configuration.
+ $langcode = isset($mapping['language']) ? $mapping['language'] : LANGUAGE_NONE;
+
if ($sub_field == 'uri') {
foreach ($values as $k => $v) {
@@ -84,30 +93,30 @@ function file_feeds_set_target($source, $entity, $target, array $values) {
}
// Populate entity.
- $field = isset($entity->$field_name) ? $entity->$field_name : array(LANGUAGE_NONE => array());
+ $field = isset($entity->$field_name) ? $entity->$field_name : array($langcode => 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[$langcode][$delta])) {
+ $field[$langcode][$delta] = array();
}
switch ($sub_field) {
case 'alt':
case 'title':
- $field[LANGUAGE_NONE][$delta][$sub_field] = $v;
+ $field[$langcode][$delta][$sub_field] = $v;
break;
case 'uri':
if ($v) {
try {
$file = $v->getFile($destination);
- $field[LANGUAGE_NONE][$delta] += (array) $file;
+ $field[$langcode][$delta] += (array) $file;
// @todo: Figure out how to properly populate this field.
- $field[LANGUAGE_NONE][$delta]['display'] = 1;
+ $field[$langcode][$delta]['display'] = 1;
}
catch (Exception $e) {
watchdog_exception('Feeds', $e, nl2br(check_plain($e)));
diff --git a/mappers/link.inc b/mappers/link.inc
index 90b5268..54254a1 100644
--- a/mappers/link.inc
+++ b/mappers/link.inc
@@ -20,6 +20,8 @@ function link_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
'callback' => 'link_feeds_set_target',
'description' => t('The @label field of the entity.', array('@label' => $instance['label'])),
'real_target' => $name,
+ 'summary_callback' => 'feeds_mapper_summary_language',
+ 'form_callback' => 'feeds_mapper_form_language',
);
}
if (array_key_exists('title', $info['columns'])) {
@@ -28,6 +30,8 @@ function link_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
'callback' => 'link_feeds_set_target',
'description' => t('The @label field of the entity.', array('@label' => $instance['label'])),
'real_target' => $name,
+ 'summary_callback' => 'feeds_mapper_summary_language',
+ 'form_callback' => 'feeds_mapper_form_language',
);
}
}
@@ -41,19 +45,22 @@ function link_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
* user has decided to map to and $value contains the value of the feed item
* element the user has picked as a source.
*/
-function link_feeds_set_target($source, $entity, $target, array $values) {
+function link_feeds_set_target($source, $entity, $target, array $values, $mapping = array()) {
list($field_name, $column) = explode(':', $target);
$field = isset($entity->$field_name) ? $entity->$field_name : array('und' => array());
$delta = 0;
+ // Set the language of the field depending on the mapping configuration.
+ $langcode = isset($mapping['language']) ? $mapping['language'] : LANGUAGE_NONE;
+
foreach ($values as $value) {
if (is_object($value) && ($value instanceof FeedsElement)) {
$value = $value->getValue();
}
if (is_scalar($value)) {
- $field['und'][$delta][$column] = (string) $value;
+ $field[$langcode][$delta][$column] = (string) $value;
}
$delta++;
}
diff --git a/mappers/number.inc b/mappers/number.inc
index 338d569..7ed7e72 100644
--- a/mappers/number.inc
+++ b/mappers/number.inc
@@ -27,6 +27,8 @@ function number_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_n
'name' => check_plain($instance['label']),
'callback' => 'number_feeds_set_target',
'description' => t('The @label field of the entity.', array('@label' => $instance['label'])),
+ 'summary_callback' => 'feeds_mapper_summary_language',
+ 'form_callback' => 'feeds_mapper_form_language',
);
}
}
@@ -37,9 +39,17 @@ function number_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_n
*
* Ensure that $value is a numeric to avoid database errors.
*/
-function number_feeds_set_target($source, $entity, $target, array $values) {
+function number_feeds_set_target($source, $entity, $target, array $values, $mapping = array()) {
+ // Set the language of the field depending on the mapping configuration.
+ $langcode = isset($mapping['language']) ? $mapping['language'] : LANGUAGE_NONE;
+
// Iterate over all values.
- $field = isset($entity->$target) ? $entity->$target : array('und' => array());
+ $field = isset($entity->$target) ? $entity->$target : array($langcode => array());
+
+ // If it's a new language we need to add it to the field
+ if (!isset($field[$langcode])) {
+ $field[$langcode] = array();
+ }
foreach ($values as $value) {
@@ -48,7 +58,7 @@ function number_feeds_set_target($source, $entity, $target, array $values) {
}
if (is_numeric($value)) {
- $field['und'][] = array('value' => $value);
+ $field[$langcode][] = array('value' => $value);
}
}
diff --git a/mappers/taxonomy.inc b/mappers/taxonomy.inc
index 088a558..d513381 100644
--- a/mappers/taxonomy.inc
+++ b/mappers/taxonomy.inc
@@ -87,7 +87,10 @@ function taxonomy_feeds_set_target($source, $entity, $target, array $terms, $map
$mapping += array(
'term_search' => FEEDS_TAXONOMY_SEARCH_TERM_NAME,
'autocreate' => FALSE,
+ 'language' => LANGUAGE_NONE,
);
+ // Grab the language for convenience
+ $langcode = $mapping['language'];
$info = field_info_field($target);
@@ -110,10 +113,15 @@ function taxonomy_feeds_set_target($source, $entity, $target, array $terms, $map
->range(0, 1);
- $field = isset($entity->$target) ? $entity->$target : array('und' => array());
+ $field = isset($entity->$target) ? $entity->$target : array($langcode => array());
+
+ // If it's a new language we need to add it to the field
+ if (!isset($field[$langcode])) {
+ $field[$langcode] = array();
+ }
// Allow for multiple mappings to the same target.
- $delta = count($field['und']);
+ $delta = count($field[$langcode]);
// Iterate over all values.
foreach ($terms as $term) {
@@ -166,7 +174,7 @@ function taxonomy_feeds_set_target($source, $entity, $target, array $terms, $map
}
if ($tid && isset($cache['allowed_values'][$target][$tid])) {
- $field['und'][] = array('tid' => $tid);
+ $field[$langcode][] = array('tid' => $tid);
$delta++;
}
}
@@ -257,11 +265,21 @@ function taxonomy_feeds_term_lookup_term_by_guid($guid) {
* will be displayed.
*/
function taxonomy_feeds_summary_callback($mapping, $target, $form, $form_state) {
+ $output = '';
$options = _taxonomy_feeds_form_callback_options();
if (empty($mapping['term_search'])) {
- return t('Search taxonomy terms by: @search', array('@search' => $options[FEEDS_TAXONOMY_SEARCH_TERM_NAME]));
+ $output = t('Search taxonomy terms by: @search', array('@search' => $options[FEEDS_TAXONOMY_SEARCH_TERM_NAME]));
+ }
+ else {
+ $output = t('Search taxonomy terms by: @search', array('@search' => $options[$mapping['term_search']]));
+ }
+ if ($language_summary = feeds_mapper_summary_language($mapping, $target, $form, $form_state)) {
+ $output .= '
' . $language_summary;
}
- return t('Search taxonomy terms by: @search', array('@search' => $options[$mapping['term_search']]));
+ if (!empty($mapping['autocreate'])) {
+ $output .= '
' . t('Autocreate Terms: Yes');
+ }
+ return $output;
}
/**
@@ -272,7 +290,8 @@ function taxonomy_feeds_summary_callback($mapping, $target, $form, $form_state)
* be populated with the form values.
*/
function taxonomy_feeds_form_callback($mapping, $target, $form, $form_state) {
- return array(
+ $return = feeds_mapper_form_language($mapping, $target, $form, $form_state);
+ $return += array(
'term_search' => array(
'#type' => 'select',
'#title' => t('Search taxonomy terms by'),
@@ -291,6 +310,8 @@ function taxonomy_feeds_form_callback($mapping, $target, $form, $form_state) {
),
),
);
+
+ return $return;
}
/**
diff --git a/mappers/text.inc b/mappers/text.inc
index 5646753..face4be 100644
--- a/mappers/text.inc
+++ b/mappers/text.inc
@@ -25,6 +25,8 @@ function text_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
'name' => check_plain($instance['label']),
'callback' => 'text_feeds_set_target',
'description' => t('The @label field of the entity.', array('@label' => $instance['label'])),
+ 'summary_callback' => 'feeds_mapper_summary_language',
+ 'form_callback' => 'feeds_mapper_form_language',
);
}
}
@@ -33,12 +35,20 @@ function text_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
/**
* Callback for mapping text fields.
*/
-function text_feeds_set_target($source, $entity, $target, array $values) {
+function text_feeds_set_target($source, $entity, $target, array $values, $mapping = array()) {
if (isset($source->importer->processor->config['input_format'])) {
$format = $source->importer->processor->config['input_format'];
}
- $field = isset($entity->$target) ? $entity->$target : array('und' => array());
+ // Set the language of the field depending on the mapping configuration.
+ $langcode = isset($mapping['language']) ? $mapping['language'] : LANGUAGE_NONE;
+
+ $field = isset($entity->$target) ? $entity->$target : array($langcode => array());
+
+ // If it's a new language we need to add it to the field
+ if (!isset($field[$langcode])) {
+ $field[$langcode] = array();
+ }
// Iterate over all values.
foreach ($values as $value) {
@@ -53,7 +63,7 @@ function text_feeds_set_target($source, $entity, $target, array $values) {
$value['format'] = $format;
}
- $field['und'][] = $value;
+ $field[$langcode][] = $value;
}
}
diff --git a/plugins/FeedsEntityProcessor.inc b/plugins/FeedsEntityProcessor.inc
index 833800f..725753a 100644
--- a/plugins/FeedsEntityProcessor.inc
+++ b/plugins/FeedsEntityProcessor.inc
@@ -135,6 +135,7 @@ class FeedsEntityProcessor extends FeedsProcessor {
'skip_hash_check' => FALSE,
'bundle' => NULL,
'values' => array(),
+ 'language' => LANGUAGE_NONE,
);
}
diff --git a/plugins/FeedsNodeProcessor.inc b/plugins/FeedsNodeProcessor.inc
index 8b63c53..d490c3c 100644
--- a/plugins/FeedsNodeProcessor.inc
+++ b/plugins/FeedsNodeProcessor.inc
@@ -34,7 +34,6 @@ class FeedsNodeProcessor extends FeedsProcessor {
$node->type = $this->bundle();
$node->changed = REQUEST_TIME;
$node->created = REQUEST_TIME;
- $node->language = LANGUAGE_NONE;
$node->is_new = TRUE;
node_object_prepare($node);
// Populate properties that are set by node_object_prepare().
diff --git a/plugins/FeedsProcessor.inc b/plugins/FeedsProcessor.inc
index 6666276..306dc37 100755
--- a/plugins/FeedsProcessor.inc
+++ b/plugins/FeedsProcessor.inc
@@ -14,6 +14,9 @@ define('FEEDS_UPDATE_EXISTING', 2);
// processors.
define('FEEDS_PROCESS_LIMIT', 50);
+// Default Language trigger
+define('FEEDS_LANGUAGE_DEFAULT', 'xx_');
+
/**
* Thrown if a validation fails.
*/
@@ -77,6 +80,23 @@ abstract class FeedsProcessor extends FeedsPlugin {
}
/**
+ * Provides a list of language options for use in select lists.
+ *
+ * @return array
+ * A keyed array of langcode => language.
+ */
+ public function languageOptions() {
+ $options = array(
+ FEEDS_LANGUAGE_DEFAULT => t('Default Language'),
+ LANGUAGE_NONE => t('Language neutral'),
+ );
+ foreach (language_list() as $langcode => $language) {
+ $options[$langcode] = $language->name;
+ }
+ return $options;
+ }
+
+ /**
* Create a new entity.
*
* @param $source
@@ -216,11 +236,16 @@ abstract class FeedsProcessor extends FeedsPlugin {
// Build a new entity.
else {
$entity = $this->newEntity($source);
+ // Set the language if it wasn't set specifically by a processor
+ if (!isset($entity->language)) {
+ $entity->language = $this->getConfigLanguage();
+ }
$this->newItemInfo($entity, $source->feed_nid, $hash);
}
// Set property and field values.
$this->map($source, $parser_result, $entity);
+ $this->processEntityTitleReplacements($entity);
$this->entityValidate($entity);
// Allow modules to alter the entity before saving.
@@ -236,6 +261,7 @@ abstract class FeedsProcessor extends FeedsPlugin {
// This will throw an exception on failure.
$this->entitySaveAccess($entity);
+ $this->processTranslations($entity);
$this->entitySave($entity);
// Allow modules to perform operations using the saved entity data.
@@ -609,6 +635,7 @@ abstract class FeedsProcessor extends FeedsPlugin {
'input_format' => NULL,
'skip_hash_check' => FALSE,
'bundle' => $bundle,
+ 'language' => LANGUAGE_NONE,
);
}
@@ -635,6 +662,14 @@ abstract class FeedsProcessor extends FeedsPlugin {
);
}
+ $form['language'] = array(
+ '#type' => 'select',
+ '#options' => $this->languageOptions(),
+ '#title' => t('Language'),
+ '#required' => TRUE,
+ '#default_value' => $this->config['language'],
+ );
+
$tokens = array('@entities' => strtolower($info['label plural']));
$form['update_existing'] = array(
@@ -732,6 +767,101 @@ abstract class FeedsProcessor extends FeedsPlugin {
}
/**
+ * Returns the configured language for the processor
+ *
+ * @return
+ * The language code configured for the processor
+ */
+ public function getConfigLanguage() {
+ return ($this->config['language'] == FEEDS_LANGUAGE_DEFAULT) ? language_default('language') : $this->config['language'];
+ }
+
+ /**
+ * Returns the language for the entity.
+ *
+ * @param string $entity
+ * The entity for which to get the language.
+ *
+ * @return
+ * The language code for the entity, or the language code that's configured
+ * for the processor if the entity doesn't have any language support.
+ */
+ public function getEntityLanguage($entity) {
+ $language = entity_language($this->entityType(), $entity);
+ return $language ? $language : $this->getConfigLanguage();
+ }
+
+ /**
+ * Process entity properties that have been replaced with the title module
+ *
+ * @param object $entity
+ * The entity to check for replaced properties
+ */
+ public function processEntityTitleReplacements(&$entity) {
+ if (module_exists('title')) {
+ // Get the possible replacements for this entity type
+ if ($replacements = title_field_replacement_info($this->entityType())) {
+ // Loop through replacements
+ foreach ($replacements as $legacy_field => $field_info) {
+ // Populate legacy field with value from the field of the language
+ // for the entity.
+ $language = $this->getEntityLanguage($entity);
+ if (!empty($entity->{$field_info['field']['field_name']}[$language]) && empty($entity->{$legacy_field})) {
+ $entity->{$legacy_field} = $entity->{$field_info['field']['field_name']}[$language][0]['value'];
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Add translations to an entity for each mapped language
+ *
+ * @param object $entity
+ * The entity to add translations to
+ */
+ public function processTranslations(&$entity) {
+ // Add translations (if the entity_translation module exists) provided at
+ // least one field has a translation
+ if (module_exists('entity_translation')) {
+ $handler = entity_translation_get_handler($this->entityType(), $entity);
+ $languages = array();
+ $default_langcode = $this->getEntityLanguage($entity);
+
+ // Init the translations if there's not translation data yet
+ if (empty($entity->translations->data)) {
+ $handler->initTranslations();
+ }
+
+ // Loop through the mappings
+ foreach ($this->getMappings() as $mapping) {
+ if (!empty($mapping['language']) && $mapping['language'] != LANGUAGE_NONE && $mapping['language'] != $default_langcode && empty($entity->translations->data[$mapping['language']])) {
+ list($field_name) = explode(':', $mapping['target']);
+
+ // If this field's language has items we create a translation for it
+ if (!empty($entity->{$field_name}[$mapping['language']])) {
+ $translation = array(
+ 'translate' => 0,
+ 'status' => 1,
+ 'language' => $mapping['language'],
+ 'source' => $default_langcode,
+ );
+ $handler->setTranslation($translation, $entity);
+ }
+ }
+ }
+
+ // Loop through every language for the site, and remove translations for
+ // the one that hasn't got any values.
+ foreach (language_list() as $language) {
+ if (!isset($entity->translations->data[$language->language])) {
+ $handler->removeTranslation($language->language);
+ }
+ }
+ }
+ }
+
+ /**
* Retrieve the target entity's existing id if available. Otherwise return 0.
*
* @ingroup mappingapi
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..61cd016
--- /dev/null
+++ b/tests/feeds_mapper_multilingual_fields.test
@@ -0,0 +1,261 @@
+content mapper (with field translation
+ * provided by the entity_translation module)
+ */
+class FeedsMapperMultilingualFieldsTestCase extends FeedsMapperTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Mapper: Multilingual Fields',
+ 'description' => 'Test Feeds Multilingual support.',
+ 'group' => 'Feeds',
+ 'dependencies' => array('entity_translation'),
+ );
+ }
+
+ function setUp() {
+
+ // Modules
+ $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);
+
+ // Configure Multilingual
+ $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(
+ array(
+ 'source' => 'guid',
+ 'target' => 'guid',
+ 'unique' => TRUE,
+ ),
+ array(
+ 'source' => 'title',
+ 'target' => 'title',
+ ),
+ array(
+ 'source' => 'body',
+ 'target' => 'body',
+ 'language' => 'en',
+ ),
+ array(
+ 'source' => 'body_fr',
+ 'target' => 'body',
+ 'language' => 'fr',
+ ),
+ array(
+ 'source' => 'number',
+ 'target' => 'field_number',
+ 'language' => 'en',
+ ),
+ array(
+ 'source' => 'number_fr',
+ 'target' => 'field_number',
+ 'language' => 'fr',
+ ),
+ array(
+ 'source' => 'link',
+ 'target' => 'field_link:url',
+ 'language' => 'en',
+ ),
+ array(
+ 'source' => 'link_fr',
+ 'target' => 'field_link:url',
+ 'language' => 'fr',
+ ),
+ array(
+ 'source' => 'image',
+ 'target' => 'field_image:uri',
+ 'language' => 'en',
+ ),
+ array(
+ 'source' => 'image_fr',
+ 'target' => 'field_image:uri',
+ 'language' => 'fr',
+ ),
+ array(
+ 'source' => 'category',
+ 'target' => 'field_category',
+ 'language' => 'en',
+ 'autocreate' => TRUE,
+ ),
+ array(
+ 'source' => 'category_fr',
+ 'target' => 'field_category',
+ 'language' => 'fr',
+ 'autocreate' => TRUE,
+ ),
+ )
+ );
+ }
+
+ /**
+ * Tests multilingual mappings to translatable fields (entity translation)
+ */
+ public function testMultilingualFieldMappings() {
+
+ // Run Import
+ // Import CSV file.
+ $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual.csv');
+ $this->assertText('Created 1 node');
+
+ // Check english field values
+ $this->drupalGet('en/node/1/edit');
+ $this->assertFieldByName("body[en][0][value]", 'This is the body', t('Found english form field for body with the expected value.'));
+ $this->assertFieldByName("field_number[en][0][value]", 1000, t('Found english form field for number with the expected value.'));
+ $this->assertFieldByName("field_link[en][0][url]", 'http://google.ca', t('Found english form field for link with the expected value.'));
+ $this->assertText("foosball.jpeg", t('Found english form field for image with the expected value.'));
+ $this->assertOptionSelected('edit-field-category-en', 1, t('Found english form field for category with the expected value'));
+
+ //
+ // Check French Field Values
+ $this->drupalGet('fr/node/1/edit');
+ $this->assertFieldByName("body[fr][0][value]", 'Ceci est la corps', t('Found french form field for body with the expected value.'));
+ $this->assertFieldByName("field_number[fr][0][value]", 2000, t('Found french form field for number with the expected value.'));
+ $this->assertFieldByName("field_link[fr][0][url]", 'http://google.fr', t('Found french form field for link with the expected value.'));
+ $this->assertText("la fayette.jpeg", t('Found french form field for image with the expected value.'));
+ $this->assertOptionSelected('edit-field-category-fr', 2, t('Found french form field for category with the 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, 'Add language');
+ $this->assertText('The language French has been created and can now be used.');
+
+ // Configure English Path Prefix
+ $edit = array(
+ 'prefix' => 'en',
+ );
+ $this->drupalPost('admin/config/regional/language/edit/en', $edit, 'Save language');
+ // Configure French Path Prefix
+ $edit = array(
+ 'prefix' => 'fr',
+ );
+ $this->drupalPost('admin/config/regional/language/edit/fr', $edit, 'Save language');
+
+ // Configure Language Detection
+ $edit = array(
+ 'language[enabled][locale-url]' => 1,
+ 'language[weight][locale-url]' => -10,
+ 'language[weight][locale-browser]' => -9,
+ 'language[weight][locale-session]' => -8,
+ 'language[weight][locale-user]' => -7,
+ 'language[weight][language-default]' => -6,
+ 'language_content[enabled][locale-url]' => 1,
+ 'language_content[weight][locale-url]' => -10,
+ 'language_content[weight][locale-browser]' => -9,
+ 'language_content[weight][locale-session]' => -8,
+ 'language_content[weight][locale-user]' => -7,
+ 'language_content[enabled][locale-interface]' => 1,
+ 'language_content[weight][locale-interface]' => -6,
+ 'language_content[weight][language-default]' => -5,
+ );
+ $this->drupalPost('admin/config/regional/language/configure', $edit, 'Save settings');
+
+ // 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_tests.info b/tests/feeds_tests.info
index 0e1d123..f135070 100644
--- a/tests/feeds_tests.info
+++ b/tests/feeds_tests.info
@@ -4,4 +4,5 @@ package = Testing
version = VERSION
core = 7.x
test_dependencies[] = entity
+test_dependencies[] = entity_translation
hidden = TRUE