diff --git a/recipe.info b/recipe.info
index 2940516..430bedd 100644
--- a/recipe.info
+++ b/recipe.info
@@ -4,5 +4,3 @@ package = Recipe
 core = 7.x
 
 configure = admin/config/system/recipe
-
-files[] = recipe.test
diff --git a/recipe.module b/recipe.module
index 19254db..31aa6e2 100644
--- a/recipe.module
+++ b/recipe.module
@@ -293,6 +293,32 @@ function recipe_delete($node) {
 }
 
 /**
+ * Implements hook_node_prepare().
+ */
+function recipe_node_prepare($node) {
+  // Populate new translation nodes with translation source values.
+  if ($node->type == 'recipe' && !isset($node->nid) && isset($node->translation_source)) {
+    $node->recipe_source = $node->translation_source->recipe_source;
+    $node->recipe_yield = $node->translation_source->recipe_yield;
+    $node->recipe_yield_unit = $node->translation_source->recipe_yield_unit;
+    $node->recipe_description = $node->translation_source->recipe_description;
+    $node->recipe_instructions = $node->translation_source->recipe_instructions;
+    $node->recipe_notes = $node->translation_source->recipe_notes;
+    $node->recipe_preptime = $node->translation_source->recipe_preptime;
+    $node->recipe_cooktime = $node->translation_source->recipe_cooktime;
+    $node->recipe_ingredients = $node->translation_source->recipe_ingredients;
+    // Don't copy ri_id or ingredient_id because they reference the source
+    // recipe node; by excluding it, it creates a new record.
+    if (isset($node->recipe_ingredients['ing'])) {
+      foreach ($node->recipe_ingredients['ing'] as &$ing) {
+        $ing['ri_id'] = NULL;
+        $ing['ingredient_id'] = NULL;
+      }
+    }
+  }
+}
+
+/**
  * Implements hook_form().
  */
 function recipe_form($node, &$form_state) {
@@ -2054,3 +2080,17 @@ function recipe_clone_node_alter($node, $context) {
     }
   }
 }
+
+/**
+ * Implements hook_module_implements_alter().
+ */
+function recipe_module_implements_alter(&$implementations, $hook) {
+  // Ensure our implementation of hook_node_prepare() runs after the translation
+  // module's implementation so that source translation data has been added to
+  // the node object.
+  if ($hook == 'node_prepare') {
+    $group = $implementations['recipe'];
+    unset($implementations['recipe']);
+    $implementations['recipe'] = $group;
+  }
+}
diff --git a/src/Tests/RecipeTranslationTest.php b/src/Tests/RecipeTranslationTest.php
new file mode 100644
index 0000000..f77a00c
--- /dev/null
+++ b/src/Tests/RecipeTranslationTest.php
@@ -0,0 +1,173 @@
+<?php
+
+namespace Drupal\recipe\Tests;
+
+/**
+ * Tests translating Recipe nodes.
+ */
+class RecipeTranslationTest extends \DrupalWebTestCase {
+
+  /**
+   * A user with administrative privileges.
+   *
+   * @var \stdClass
+   */
+  protected $adminUser;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Recipe content translation',
+      'description' => 'Ensure that the recipe content translation functions properly.',
+      'group' => 'Recipe',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    // Enable modules required for testing. Bypass \TranslationTestCase::setUp()
+    // because we don't want the configuration that it sets up.
+    parent::setUp(array(
+      'locale',
+      'recipe',
+      'translation',
+    ));
+
+    // Create and log in the admin user with Recipe content permissions.
+    $this->adminUser = $this->drupalCreateUser(array(
+      'administer content types',
+      'administer languages',
+      'administer site configuration',
+      'bypass node access',
+      'translate content',
+    ));
+    $this->drupalLogin($this->adminUser);
+
+    // Add languages.
+    $this->addLanguage('en');
+    $this->addLanguage('es');
+
+    // Set Recipes to use multilingual support with translation.
+    $this->drupalGet('admin/structure/types/manage/recipe');
+    $edit = array();
+    $edit['language_content_type'] = 2;
+    $this->drupalPost('admin/structure/types/manage/recipe', $edit, t('Save content type'));
+    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Recipe')), 'Recipe content type has been updated.');
+  }
+
+  /**
+   * Tests translation of recipe data.
+   */
+  public function testRecipeTranslation() {
+    // Create a recipe node.
+    $node_title = $this->randomName(16);
+    $source = $this->randomName(16);
+    $yield = 10;
+    $yield_unit = $this->randomName(10);
+    $description = $this->randomName(32);
+    $instructions = $this->randomName(32);
+    $notes = $this->randomName(32);
+    $preptime = 30;
+    $cooktime = 90;
+    $quantity = 2;
+    $unit_key = 'cup';
+    $ingredient_name = $this->randomName(16);
+    $ingredient_note = $this->randomName(16);
+    $edit = array(
+      'type' => 'recipe',
+      'title' => $node_title,
+      'recipe_source' => $source,
+      'recipe_yield' => $yield,
+      'recipe_yield_unit' => $yield_unit,
+      'recipe_description' => array(
+        'value' => $description,
+      ),
+      'recipe_instructions' => array(
+        'value' => $instructions,
+      ),
+      'recipe_notes' => array(
+        'value' => $notes,
+      ),
+      'recipe_preptime' => $preptime,
+      'recipe_cooktime' => $cooktime,
+      'recipe_ingredients' => array(
+        'ing' => array(
+          0 => array(
+            'quantity' => $quantity,
+            'unit_key' => $unit_key,
+            'name' => $ingredient_name,
+            'note' => $ingredient_note,
+            'weight' => 0,
+          ),
+        ),
+      ),
+      'language' => 'en',
+    );
+    $this->drupalCreateNode($edit);
+
+    // Verify that the node was created and that the translation link exists.
+    $this->drupalGet('node/1');
+    $this->assertLink('Translate', 0, 'Found the translate link.');
+    $this->clickLink('Translate', 0);
+    $this->assertLink('add translation', 0, 'Found the add translation link.');
+    $this->clickLink('add translation', 0);
+
+    // Verify that the translation form is populated with the source values.
+    $this->assertFieldById('edit-recipe-description-value', $description, 'Found the source description.');
+    $this->assertFieldById('edit-recipe-yield-unit', $yield_unit, 'Found the source yield units.');
+    $this->assertFieldById('edit-recipe-yield', $yield, 'Found the source yield.');
+    $this->assertFieldById('edit-recipe-ingredients-ing-0-quantity', $quantity, 'Found the source ingredient quantity.');
+    $this->assertFieldById('edit-recipe-ingredients-ing-0-unit-key', $unit_key, 'Found the source ingredient unit key.');
+    $this->assertFieldById('edit-recipe-ingredients-ing-0-name', $ingredient_name, 'Found the source ingredient name.');
+    $this->assertFieldById('edit-recipe-ingredients-ing-0-note', $ingredient_note, 'Found the source ingredient note.');
+    $this->assertFieldById('edit-recipe-source', $source, 'Found the source source.');
+    $this->assertFieldById('edit-recipe-instructions-value', $instructions, 'Found the source instructions.');
+    $this->assertFieldById('edit-recipe-notes-value', $notes, 'Found the source notes.');
+    $this->assertFieldById('edit-recipe-preptime', $preptime, 'Found the source prep time.');
+    $this->assertFieldById('edit-recipe-cooktime', $cooktime, 'Found the source cook time.');
+  }
+
+  /**
+   * Installs the specified language, or enables it if it is already installed.
+   *
+   * This was copied from the translation module test class.
+   *
+   * @param $language_code
+   *   The language code to check.
+   */
+  function addLanguage($language_code) {
+    // Check to make sure that language has not already been installed.
+    $this->drupalGet('admin/config/regional/language');
+
+    if (strpos($this->drupalGetContent(), 'enabled[' . $language_code . ']') === FALSE) {
+      // Doesn't have language installed so add it.
+      $edit = array();
+      $edit['langcode'] = $language_code;
+      $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+      // Make sure we are not using a stale list.
+      drupal_static_reset('language_list');
+      $languages = language_list('language');
+      $this->assertTrue(array_key_exists($language_code, $languages), 'Language was installed successfully.');
+
+      if (array_key_exists($language_code, $languages)) {
+        $this->assertRaw(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => $languages[$language_code]->name, '@locale-help' => url('admin/help/locale'))), 'Language has been created.');
+      }
+    }
+    elseif ($this->xpath('//input[@type="checkbox" and @name=:name and @checked="checked"]', array(':name' => 'enabled[' . $language_code . ']'))) {
+      // It's installed and enabled. No need to do anything.
+      $this->assertTrue(true, 'Language [' . $language_code . '] already installed and enabled.');
+    }
+    else {
+      // It's installed but not enabled. Enable it.
+      $this->assertTrue(true, 'Language [' . $language_code . '] already installed.');
+      $this->drupalPost(NULL, array('enabled[' . $language_code . ']' => TRUE), t('Save configuration'));
+      $this->assertRaw(t('Configuration saved.'), 'Language successfully enabled.');
+    }
+  }
+
+}
