diff --git a/feeds.info b/feeds.info
index 6e32601..eadb544 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_unique.test
diff --git a/feeds.module b/feeds.module
index 4418e9c..8becf38 100644
--- a/feeds.module
+++ b/feeds.module
@@ -905,6 +905,83 @@ function feeds_item_info_save($entity, $entity_id) {
}
/**
+ * Implements hook_feeds_processor_targets_alter().
+ */
+function locale_feeds_processor_targets_alter(array &$targets, $entity_type, $bundle_name) {
+ $language_options = feeds_mapper_options_language();
+
+ foreach ($targets as $target => $target_config) {
+ list($field_name) = explode(':', $target);
+ if (!$info = field_info_field($field_name)) {
+ continue;
+ }
+ if (!$info['translatable']) {
+ continue;
+ }
+
+ $targets[$target]['summary_callback'][] = 'feeds_mapper_locale_summary';
+ $targets[$target]['form_callback'][] = 'feeds_mapper_locale_form';
+ $targets[$target]['preprocess_callback'][] = 'feeds_mapper_locale_preprocess';
+ }
+}
+
+/**
+ * Summary callback for language configuration.
+ */
+function feeds_mapper_locale_summary(array $mapping, array $target, array $form, array &$form_state) {
+ list($field_name) = explode(':', $mapping['target']);
+ $info = field_info_field($field_name);
+
+ if ($info['translatable']) {
+ $language_options = feeds_mapper_options_language();
+ if (empty($mapping['language'])) {
+ return t('Language: @search', array('@search' => $language_options[LANGUAGE_NONE]));
+ }
+ return t('Language: @search', array('@search' => $language_options[$mapping['language']]));
+ }
+}
+
+/**
+ * Callback for language mapper configuration form.
+ */
+function feeds_mapper_locale_form(array $mapping, array $target, array $form, array &$form_state) {
+ list($field_name) = explode(':', $mapping['target']);
+ $info = field_info_field($field_name);
+ if ($info['translatable']) {
+ $form['language'] = array(
+ '#type' => 'select',
+ '#title' => t('Language'),
+ '#options' => feeds_mapper_options_language(),
+ '#default_value' => !empty($mapping['language']) ? $mapping['language'] : LANGUAGE_NONE,
+ '#description' => t('You can select a particular field language (or language nautral) or use language code saved in entity\'s language property (e.g. $node->language) you set by some mapper above.'),
+ );
+ }
+ return $form;
+}
+
+/**
+ * Callback for processing the mapping configuration.
+ */
+function feeds_mapper_locale_preprocess(FeedsSource $source, $entity, $target, array $terms, array &$mapping) {
+ // Set the language of the field depending on the mapping configuration.
+ $mapping['language'] = !empty($mapping['language']) ? $mapping['language'] : LANGUAGE_NONE;
+ $mapping['language'] = $mapping['language'] === 'from_property' ? $entity->language : $mapping['language'];
+}
+
+/**
+ * Return the options list of language options for target configuration.
+ *
+ * @return array
+ * A list of available language options.
+ */
+function feeds_mapper_options_language() {
+ return array(
+ 'from_property' => t('Inherit language'),
+ LANGUAGE_NONE => t('Language neutral'),
+ ) + locale_language_list('name');
+}
+
+/**
* @}
*/
diff --git a/feeds_ui/feeds_ui.admin.inc b/feeds_ui/feeds_ui.admin.inc
index 1ed2de3..01a7493 100644
--- a/feeds_ui/feeds_ui.admin.inc
+++ b/feeds_ui/feeds_ui.admin.inc
@@ -635,10 +635,8 @@ function feeds_ui_mapping_settings_form($form, $form_state, $i, $mapping, $targe
if ($form_state['mapping_settings_edit'] === $i) {
$settings_form = array();
// Build the form.
- if (!empty($target['form_callback'])) {
- foreach ((array) $target['form_callback'] as $callback) {
- $settings_form += call_user_func($callback, $mapping, $target, $form, $form_state);
- }
+ foreach ((array) $target['form_callback'] as $callback) {
+ $settings_form += $callback($mapping, $target, array(), $form_state);
}
// Merge in the optional unique form.
@@ -662,14 +660,12 @@ function feeds_ui_mapping_settings_form($form, $form_state, $i, $mapping, $targe
);
}
else {
- $summary = '';
// Build the summary.
- if (!empty($target['summary_callback'])) {
- foreach ((array) $target['summary_callback'] as $callback) {
- $summary[] = call_user_func($callback, $mapping, $target, $form, $form_state);
- }
- $summary = implode('
', $summary);
+ $summary = array();
+ foreach ((array) $target['summary_callback'] as $callback) {
+ $summary[] = $callback($mapping, $target, $form, $form_state);
}
+ $summary = implode('
', $summary);
// Append the optional unique summary.
if ($optional_unique_summary = feeds_ui_mapping_settings_optional_unique_summary($mapping, $target, $form, $form_state)) {
diff --git a/mappers/date.inc b/mappers/date.inc
index abb56d3..165db5a 100644
--- a/mappers/date.inc
+++ b/mappers/date.inc
@@ -35,7 +35,7 @@ function date_feeds_processor_targets($entity_type, $bundle_name) {
/**
* Callback for setting target values.
*/
-function date_feeds_set_target($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;
diff --git a/mappers/file.inc b/mappers/file.inc
index b21a0f7..3c73d38 100644
--- a/mappers/file.inc
+++ b/mappers/file.inc
@@ -42,13 +42,9 @@ function file_feeds_processor_targets($entity_type, $bundle_name) {
}
/**
- * Callback for mapping. Here is where the actual mapping happens.
- *
- * When the callback is invoked, $target contains the name of the field the
- * user has decided to map to and $value contains the value of the feed item
- * element the user has picked as a source.
+ * Callback for mapping files.
*/
-function file_feeds_set_target($source, $entity, $target, array $values) {
+function file_feeds_set_target(FeedsSource $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);
@@ -84,30 +80,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($mapping['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[$mapping['language']][$delta])) {
+ $field[$mapping['language']][$delta] = array();
}
switch ($sub_field) {
case 'alt':
case 'title':
- $field[LANGUAGE_NONE][$delta][$sub_field] = $v;
+ $field[$mapping['language']][$delta][$sub_field] = $v;
break;
case 'uri':
if ($v) {
try {
$file = $v->getFile($destination);
- $field[LANGUAGE_NONE][$delta] += (array) $file;
+ $field[$mapping['language']][$delta] += (array) $file;
// @todo: Figure out how to properly populate this field.
- $field[LANGUAGE_NONE][$delta]['display'] = 1;
+ $field[$mapping['language']][$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 9b4c011..7a64e10 100644
--- a/mappers/link.inc
+++ b/mappers/link.inc
@@ -41,10 +41,10 @@ function link_feeds_processor_targets($entity_type, $bundle_name) {
* 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(FeedsSource $source, $entity, $target, array $values, array $mapping) {
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($mapping['language'] => array());
$delta = 0;
foreach ($values as $value) {
@@ -53,7 +53,7 @@ function link_feeds_set_target($source, $entity, $target, array $values) {
}
if (is_scalar($value)) {
- $field['und'][$delta][$column] = (string) $value;
+ $field[$mapping['language']][$delta][$column] = (string) $value;
}
$delta++;
}
diff --git a/mappers/number.inc b/mappers/number.inc
index 056a285..6541aa1 100644
--- a/mappers/number.inc
+++ b/mappers/number.inc
@@ -37,9 +37,9 @@ function number_feeds_processor_targets($entity_type, $bundle_name) {
*
* 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(FeedsSource $source, $entity, $target, array $values, array $mapping) {
// Iterate over all values.
- $field = isset($entity->$target) ? $entity->$target : array('und' => array());
+ $field = isset($entity->$target) ? $entity->$target : array($mapping['language'] => array());
foreach ($values as $value) {
@@ -48,7 +48,7 @@ function number_feeds_set_target($source, $entity, $target, array $values) {
}
if (is_numeric($value)) {
- $field['und'][] = array('value' => $value);
+ $field[$mapping['language']][] = array('value' => $value);
}
}
diff --git a/mappers/taxonomy.inc b/mappers/taxonomy.inc
index a1d5fe6..5b6e5ef 100644
--- a/mappers/taxonomy.inc
+++ b/mappers/taxonomy.inc
@@ -96,7 +96,7 @@ function taxonomy_feeds_preprocess_callback(FeedsSource $source, $entity, $targe
*
* @todo Do not create new terms for non-autotag fields.
*/
-function taxonomy_feeds_set_target($source, $entity, $target, array $terms, $mapping = array()) {
+function taxonomy_feeds_set_target(FeedsSource $source, $entity, $target, array $terms, array $mapping) {
$info = field_info_field($target);
$cache = &drupal_static(__FUNCTION__);
@@ -118,10 +118,10 @@ 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($mapping['language'] => array());
// Allow for multiple mappings to the same target.
- $delta = count($field['und']);
+ $delta = count($field[$mapping['language']]);
// Iterate over all values.
foreach ($terms as $term) {
@@ -174,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[$mapping['language']][] = array('tid' => $tid);
$delta++;
}
}
diff --git a/mappers/text.inc b/mappers/text.inc
index 5696f4d..7d4c60d 100644
--- a/mappers/text.inc
+++ b/mappers/text.inc
@@ -47,7 +47,7 @@ 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 = array()) {
+function text_feeds_set_target(FeedsSource $source, $entity, $target, array $values, array $mapping) {
list($field_name, $column) = explode(':', $target . ':value');
if ($column === 'value' && isset($source->importer->processor->config['input_format'])) {
@@ -58,7 +58,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($mapping['language'] => array());
// Iterate over all values.
$delta = 0;
@@ -70,10 +70,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[$mapping['language']][$delta][$column] = (string) $value;
if (isset($mapping['format'])) {
- $field['und'][$delta]['format'] = $mapping['format'];
+ $field[$mapping['language']][$delta]['format'] = $mapping['format'];
}
}
diff --git a/plugins/FeedsProcessor.inc b/plugins/FeedsProcessor.inc
index 5dc3f36..baa59fd 100755
--- a/plugins/FeedsProcessor.inc
+++ b/plugins/FeedsProcessor.inc
@@ -80,6 +80,21 @@ 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() {
+ if (!module_exists('locale')) {
+ return array();
+ }
+ return array(
+ LANGUAGE_NONE => t('Language neutral'),
+ ) + locale_language_list('name') ;
+ }
+
+ /**
* Create a new entity.
*
* @param $source
@@ -669,11 +684,10 @@ abstract class FeedsProcessor extends FeedsPlugin {
$value = array($value);
}
- if (!empty($mapping['preprocess_callback'])) {
- foreach ($mapping['preprocess_callback'] as $preprocess) {
- $preprocess($source, $target_item, $mapping['target'], $value, $mapping);
- }
+ foreach ($mapping['preprocess_callback'] as $preprocess) {
+ $preprocess($source, $target_item, $mapping['target'], $value, $mapping);
}
+ $mapping += array('language' => $this->config['language']);
$callback($source, $target_item, $mapping['target'], $value, $mapping);
}
@@ -709,6 +723,7 @@ abstract class FeedsProcessor extends FeedsPlugin {
'input_format' => NULL,
'skip_hash_check' => FALSE,
'bundle' => $bundle,
+ 'language' => LANGUAGE_NONE,
);
}
@@ -735,6 +750,16 @@ abstract class FeedsProcessor extends FeedsPlugin {
);
}
+ if (module_exists('locale')) {
+ $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(
@@ -836,6 +861,13 @@ abstract class FeedsProcessor extends FeedsPlugin {
$type = $this->entityType();
$bundle = $this->bundle();
$targets += module_invoke_all('feeds_processor_targets', $type, $bundle);
+ foreach ($targets as $target => $info) {
+ $targets[$target] += array(
+ 'summary_callback' => array(),
+ 'form_callback' => array(),
+ 'preprocess_callback' => array(),
+ );
+ }
drupal_alter('feeds_processor_targets', $targets, $type, $bundle);
}
diff --git a/tests/feeds_tests.module b/tests/feeds_tests.module
index 5ce8961..1b22539 100644
--- a/tests/feeds_tests.module
+++ b/tests/feeds_tests.module
@@ -128,8 +128,8 @@ function feeds_tests_feeds_processor_targets($entity_type, $bundle) {
*
* @see my_module_set_target()
*/
-function feeds_tests_mapper_set_target($source, $entity, $target, $value, $mapping) {
- $entity->body['und'][0]['value'] = serialize($mapping);
+function feeds_tests_mapper_set_target(FeedsSource $source, $entity, $target, array $values, array $mapping) {
+ $entity->body[$mapping['language']][0]['value'] = serialize($mapping);
}
/**