diff --git a/core/modules/entity/entity.class.inc b/core/modules/entity/entity.class.inc
index 2311af5..9136c58 100644
--- a/core/modules/entity/entity.class.inc
+++ b/core/modules/entity/entity.class.inc
@@ -93,6 +93,60 @@ interface EntityInterface {
   public function uri();
 
   /**
+   * Returns the default language of a language-specific entity.
+   *
+   * @return
+   *   The language object of the entity's default language, or FALSE if the
+   *   entity is not language-specific.
+   *
+   * @see EntityInterface::translations()
+   */
+  public function language();
+
+  /**
+   * Returns the languages the entity is translated to.
+   *
+   * @return
+   *   An array of language objects, keyed by language codes.
+   *
+   * @see EntityInterface::language()
+   */
+  public function translations();
+
+  /**
+   * Returns the value of an entity property.
+   *
+   * @param $property_name
+   *   The name of the property to return; e.g., 'title'.
+   * @param $langcode
+   *   (optional) If the property is translatable, the language code of the
+   *   language that should be used for getting the property. If set to NULL,
+   *   the entity's default language is being used.
+   *
+   * @return
+   *   The property value, or NULL if it is not defined.
+   *
+   * @see EntityInterface::language()
+   */
+  public function get($property_name, $langcode = NULL);
+
+  /**
+   * Sets the value of an entity property.
+   *
+   * @param $property_name
+   *   The name of the property to set; e.g., 'title'.
+   * @param $value
+   *   The value to set, or NULL to unset the property.
+   * @param $langcode
+   *   (optional) If the property is translatable, the language code of the
+   *   language that should be used for getting the property. If set to
+   *   NULL, the entity's default language is being used.
+   *
+   * @see EntityInterface::language()
+   */
+  public function set($property_name, $value, $langcode = NULL);
+
+  /**
    * Saves an entity permanently.
    *
    * @return
@@ -139,6 +193,13 @@ interface EntityInterface {
 class Entity implements EntityInterface {
 
   /**
+   * The language code of the entity's default language.
+   *
+   * @var string
+   */
+  public $langcode = LANGUAGE_NOT_SPECIFIED;
+
+  /**
    * The entity type.
    *
    * @var string
@@ -247,6 +308,92 @@ class Entity implements EntityInterface {
   }
 
   /**
+   * Implements EntityInterface::language().
+   */
+  public function language() {
+    // @todo: Check for language.module instead, once Field API language
+    // handling depends upon it too.
+    return module_exists('locale') ? language_load($this->langcode) : FALSE;
+  }
+
+  /**
+   * Implements EntityInterface::translations().
+   */
+  public function translations() {
+    $languages = array();
+    $entity_info = $this->entityInfo();
+    if ($entity_info['fieldable'] && ($default_language = $this->language())) {
+      // Go through translatable properties and determine all languages for
+      // which translated values are available.
+      foreach (field_info_instances($this->entityType, $this->bundle()) as $field_name => $instance) {
+        $field = field_info_field($field_name);
+        if (field_is_translatable($this->entityType, $field) && isset($this->$field_name)) {
+          foreach ($this->$field_name as $langcode => $value)  {
+            $languages[$langcode] = TRUE;
+          }
+        }
+      }
+      // Remove the default language from the translations.
+      unset($languages[$default_language->langcode]);
+      $languages = array_intersect_key(language_list(), $languages);
+    }
+    return $languages;
+  }
+
+  /**
+   * Implements EntityInterface::get().
+   */
+  public function get($property_name, $langcode = NULL) {
+    // Handle fields.
+    $entity_info = $this->entityInfo();
+    if ($entity_info['fieldable'] && field_info_instance($this->entityType, $property_name, $this->bundle())) {
+      $field = field_info_field($property_name);
+      $langcode = $this->getFieldLangcode($field, $langcode);
+      return isset($this->{$property_name}[$langcode]) ? $this->{$property_name}[$langcode] : NULL;
+    }
+    else {
+      // Handle properties being not fields.
+      // @todo: Add support for translatable properties being not fields.
+      return isset($this->{$property_name}) ? $this->{$property_name} : NULL;
+    }
+  }
+
+  /**
+   * Implements EntityInterface::set().
+   */
+  public function set($property_name, $value, $langcode = NULL) {
+    // Handle fields.
+    $entity_info = $this->entityInfo();
+    if ($entity_info['fieldable'] && field_info_instance($this->entityType, $property_name, $this->bundle())) {
+      $field = field_info_field($property_name);
+      $langcode = $this->getFieldLangcode($field, $langcode);
+      $this->{$property_name}[$langcode] = $value;
+    }
+    else {
+      // Handle properties being not fields.
+      // @todo: Add support for translatable properties being not fields.
+      $this->{$property_name} = $value;
+    }
+  }
+
+  /**
+   * Determines the language code to use for accessing a field value in a certain language.
+   */
+  protected function getFieldLangcode($field, $langcode = NULL) {
+    // Only apply the given langcode if the entity is language-specific.
+    // Otherwise translatable fields are handled as non-translatable fields.
+    if (field_is_translatable($this->entityType, $field) && ($default_language = $this->language())) {
+      // For translatable fields the values in default language are stored using
+      // the language code of the default language.
+      return isset($langcode) ? $langcode : $default_language->langcode;
+    }
+    else {
+      // Non-translatable fields always use LANGUAGE_NOT_SPECIFIED.
+      return LANGUAGE_NOT_SPECIFIED;
+    }
+  }
+
+  /**
    * Implements EntityInterface::save().
    */
   public function save() {
diff --git a/core/modules/entity/tests/entity.test b/core/modules/entity/tests/entity.test
index 35b6ab1..57600a3 100644
--- a/core/modules/entity/tests/entity.test
+++ b/core/modules/entity/tests/entity.test
@@ -65,6 +65,138 @@ class EntityAPITestCase extends DrupalWebTestCase {
     $all = entity_test_load_multiple(FALSE);
     $this->assertTrue(empty($all), 'Deleted all entities.');
   }
+
+  /**
+   * Tests Entity getters/setters.
+   */
+  function testEntityGettersSetters() {
+    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => NULL));
+    $this->assertNull($entity->get('uid'), 'Property is not set.');
+
+    $entity->set('uid', $GLOBALS['user']->uid);
+    $this->assertEqual($entity->uid, $GLOBALS['user']->uid, 'Property has been set.');
+
+    $value = $entity->get('uid');
+    $this->assertEqual($value, $entity->uid, 'Property has been retrieved.');
+
+    // Make sure setting/getting translations boils down to setting/getting the
+    // regular value as the entity and property are not translatable.
+    $entity->set('uid', NULL, 'en');
+    $this->assertNull($entity->uid, 'Language neutral property has been set.');
+
+    $value = $entity->get('uid', 'en');
+    $this->assertNull($value, 'Language neutral property has been retrieved.');
+  }
+}
+
+/**
+ * Tests entity translation.
+ */
+class EntityTranslationTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity Translation',
+      'description' => 'Tests entity translation functionality.',
+      'group' => 'Entity API',
+    );
+  }
+
+  function setUp() {
+    // Enable translations for the test entity type. We cannot use
+    // variable_set() here as variables are cleared by parent::setUp();
+    $GLOBALS['entity_test_translation'] = TRUE;
+    parent::setUp('entity_test', 'language', 'locale');
+
+    // Create a translatable test field.
+    $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
+    $field = array(
+      'field_name' => $this->field_name,
+      'type' => 'text',
+      'cardinality' => 4,
+      'translatable' => TRUE,
+    );
+    field_create_field($field);
+    $this->field = field_read_field($this->field_name);
+
+    $instance = array(
+      'field_name' => $this->field_name,
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
+    );
+    field_create_instance($instance);
+    $this->instance = field_read_instance('entity_test', $this->field_name, 'entity_test');
+
+    // Create test languages.
+    $this->langcodes = array();
+    for ($i = 0; $i < 3; ++$i) {
+      $language = (object) array(
+        'langcode' => 'l' . $i,
+        'name' => $this->randomString(),
+      );
+      $this->langcodes[$i] = $language->langcode;
+      language_save($language);
+    }
+  }
+
+  /**
+   * Tests language related methods of the Entity class.
+   */
+  function testEntityLanguageMethods() {
+    $entity = entity_create('entity_test', array(
+      'name' => 'test',
+      'uid' => $GLOBALS['user']->uid,
+    ));
+    $this->assertFalse($entity->language(), 'No entity language has been specified.');
+    $this->assertFalse($entity->translations(), 'No translations are available');
+
+    // Set the value in default language.
+    $entity->set($this->field_name, array(0 => array('value' => 'default value')));
+    // Get the value.
+    $value = $entity->get($this->field_name);
+    $this->assertEqual($value, array(0 => array('value' => 'default value')), 'Untranslated value retrieved.');
+
+    // Set the value in a certain language. As the entity is not
+    // language-specific it should use the default language and so ignore the
+    // specified language.
+    $entity->set($this->field_name, array(0 => array('value' => 'default value2')), $this->langcodes[1]);
+    $value = $entity->get($this->field_name);
+    $this->assertEqual($value, array(0 => array('value' => 'default value2')), 'Untranslated value updated.');
+    $this->assertFalse($entity->translations(), 'No translations are available');
+
+    // Test getting a field value using the default language for a not
+    // language-specific entity.
+    $value = $entity->get($this->field_name, $this->langcodes[1]);
+    $this->assertEqual($value, array(0 => array('value' => 'default value2')), 'Untranslated value retrieved.');
+
+    // Now, make the entity language-specific by assigning a language and test
+    // translating it.
+    $entity->langcode = $this->langcodes[0];
+    $entity->{$this->field_name} = array();
+    $this->assertEqual($entity->language(), language_load($this->langcodes[0]), 'Entity language retrieved.');
+    $this->assertFalse($entity->translations(), 'No translations are available');
+
+    // Set the value in default language.
+    $entity->set($this->field_name, array(0 => array('value' => 'default value')));
+    // Get the value.
+    $value = $entity->get($this->field_name);
+    $this->assertEqual($value, array(0 => array('value' => 'default value')), 'Untranslated value retrieved.');
+
+    // Set a translation.
+    $entity->set($this->field_name, array(0 => array('value' => 'translation 1')), $this->langcodes[1]);
+    $value = $entity->get($this->field_name, $this->langcodes[1]);
+    $this->assertEqual($value, array(0 => array('value' => 'translation 1')), 'Translated value set.');
+    // Make sure the untranslated value stays.
+    $value = $entity->get($this->field_name);
+    $this->assertEqual($value, array(0 => array('value' => 'default value')), 'Untranslated value stays.');
+
+    $translations[$this->langcodes[1]] = language_load($this->langcodes[1]);
+    $this->assertEqual($entity->translations(), $translations, 'Translations retrieved.');
+
+    // Try to get a not available translation.
+    $value = $entity->get($this->field_name, $this->langcodes[2]);
+    $this->assertNull($value, 'A translation that is not available is NULL.');
+  }
 }
 
 /**
diff --git a/core/modules/entity/tests/entity_test.install b/core/modules/entity/tests/entity_test.install
index ec2e5bd..c0c7703 100644
--- a/core/modules/entity/tests/entity_test.install
+++ b/core/modules/entity/tests/entity_test.install
@@ -57,6 +57,13 @@ function entity_test_schema() {
         'default' => NULL,
         'description' => "The {users}.uid of the associated user.",
       ),
+      'langcode' => array(
+        'description' => 'The {language}.langcode of the test entity.',
+        'type' => 'varchar',
+        'length' => 12,
+        'not null' => TRUE,
+        'default' => '',
+      ),
     ),
     'indexes' => array(
       'uid' => array('uid'),
diff --git a/core/modules/entity/tests/entity_test.module b/core/modules/entity/tests/entity_test.module
index 6034b06..f7dffa0 100644
--- a/core/modules/entity/tests/entity_test.module
+++ b/core/modules/entity/tests/entity_test.module
@@ -9,19 +9,21 @@
  * Implements hook_entity_info().
  */
 function entity_test_entity_info() {
-  $return = array(
-    'entity_test' => array(
-      'label' => t('Test entity'),
-      'entity class' => 'Entity',
-      'controller class' => 'EntityDatabaseStorageController',
-      'base table' => 'entity_test',
-      'fieldable' => TRUE,
-      'entity keys' => array(
-        'id' => 'id',
-      ),
+  $items['entity_test'] = array(
+    'label' => t('Test entity'),
+    'entity class' => 'Entity',
+    'controller class' => 'EntityDatabaseStorageController',
+    'base table' => 'entity_test',
+    'fieldable' => TRUE,
+    'entity keys' => array(
+      'id' => 'id',
     ),
   );
-  return $return;
+  // Optionally specify a translation handler for testing translations.
+  if (!empty($GLOBALS['entity_test_translation'])) {
+    $items['entity_test']['translation']['entity_test'] = TRUE;
+  }
+  return $items;
 }
 
 /**
