diff --git a/languagefield.module b/languagefield.module
index a1b60b7..d931a2c 100644
--- a/languagefield.module
+++ b/languagefield.module
@@ -39,63 +39,12 @@ function languagefield_field_info() {
 //                             ),
       'default_widget' => 'options_select',
       'default_formatter' => 'language_default',
-      'property_type' => 'text',
-      'property_callbacks' => array('languagefield_property_info_callback'),
+      'property_type' => 'token',
     ),
   );
 }
 
 /**
- * Callback to alter the 'property_type' info.
- *
- * @see languagefield_field_info().
- */
-function languagefield_property_info_callback(&$info, $entity_type, $field, $instance, $field_type) {
-  $name = $field['field_name'];
-  $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];
-
-//  $property['type'] = ($field['cardinality'] != 1) ? 'list<languagefield>' : 'languagefield';
-//  $property['getter callback'] = 'entity_metadata_field_verbatim_get';
-//  $property['type'] = ($field['cardinality'] != 1) ? 'list<text>' : 'text';
-//  $property['getter callback'] = 'entity_metadata_field_verbatim_get';
-  $property['setter callback'] = 'entity_metadata_field_verbatim_set';
-  $property['property info'] = languagefield_data_property_info();
-
-  unset($property['query callback']);
-}
-
-/**
- * Defines info for the properties of the address field data structure.
- */
-function languagefield_data_property_info($name = NULL) {
-  // Build an array of basic property information.
-  $properties = array(
-    'value' => array(
-      'label' => t('ISO 639 code'),
-      'type' => 'token',
-    ),
-    'safe_value' => array(
-      'label' => t('Name'),
-    ),
-    'safe_value_with_native' => array(
-      'label' => t('Name (with native)'),
-//       'options list' => 'languagefield_options',
-    ),
-  );
-
-  // Add the default values for each of the field properties.
-  foreach ($properties as &$value) {
-    $value += array(
-      'description' => !empty($name) ? t('!label of field %name', array('!label' => $value['label'], '%name' => $name)) : '',
-      'getter callback' => 'entity_property_verbatim_get',
-      'setter callback' => 'entity_property_verbatim_set',
-    );
-    $value['type'] = isset($value['type']) ? $value['type'] : 'text';
-  }
-  return $properties;
-}
-
-/**
  * Implements hook_field_settings_form().
  */
 function languagefield_field_settings_form($field, $instance, $has_data) {
@@ -215,7 +164,7 @@ function languagefield_field_settings_form($field, $instance, $has_data) {
  * Implements hook_field_prepare_view().
  */
 function languagefield_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
-  // Get all possible languages, even if not settable. 
+  // Get all possible languages, even if not settable.
   $languages = _languagefield_options(NULL, $langcode);
   foreach ($entities as $id => $object) {
     foreach ($items[$id] as $delta => $item) {
@@ -285,7 +234,7 @@ function languagefield_field_formatter_settings_summary($field, $instance, $view
     foreach ($settings as $value) {
       switch ($value) {
         case '0':
-          // Option is not selected. 
+          // Option is not selected.
           break;
         default:
           $summary[] = isset($options[$value]) ? $options[$value] : '...';
diff --git a/languagefield.tokens.inc b/languagefield.tokens.inc
new file mode 100644
index 0000000..8941a3b
--- /dev/null
+++ b/languagefield.tokens.inc
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * @file
+* Token module integration.
+*
+* Pretty much copy-pasted from addressfield.
+*/
+
+/**
+ * Implements hook_token_info().
+*/
+function languagefield_token_info() {
+  $type = array(
+    'name' => t('Language field'),
+    'description' => t('Tokens related to languagefields.'),
+    'needs-data' => 'language-field',
+    'field' => TRUE,
+  );
+
+  $info['value'] = array(
+    'name' => t('Language code'),
+    'description' => t('ISO 639 language code.'),
+  );
+
+  return array(
+    'types' => array('language-field' => $type),
+    'tokens' => array('language-field' => $info),
+  );
+}
+
+/**
+ * Implements hook_tokens().
+ */
+function languagefield_tokens($type, $tokens, array $data = array(), array $options = array()) {
+  if (isset($options['language'])) {
+    $language_code = $options['language']->language;
+  }
+  else {
+    $language_code = LANGUAGE_NONE;
+  }
+
+  $sanitize = !empty($options['sanitize']);
+
+  $replacements = array();
+
+  if ($type == 'language-field' && !empty($data['language-field'][$language_code]) && is_array($data['language-field'][$language_code])) {
+    $language = reset($data['language-field'][$language_code]);
+
+    foreach ($tokens as $name => $original) {
+      switch ($name) {
+        case 'value':
+          $replacements[$original] = $sanitize ? check_plain($language['value']) : $language['value'];
+          break;
+
+      }
+    }
+  }
+
+  if ($type == 'entity') {
+    foreach (array_filter(field_info_field_map(), 'languagefield_field_map_filter') as $field_name => $field) {
+      if ($languagefield_tokens = token_find_with_prefix($tokens, $field_name)) {
+        // If the current field is on the matching entity type...
+        if (!empty($field['bundles'][$data['entity_type']])) {
+          // Extract the format handlers selected in a representative instance
+          // settings form for use in formatting tokens.
+          $instance = field_info_instance($data['entity_type'], $field_name, reset($field['bundles'][$data['entity_type']]));
+        }
+
+        $replacements += token_generate('language-field', $languagefield_tokens, array('language-field' => $data['entity']->$field_name), $options);
+      }
+    }
+  }
+
+  return $replacements;
+}
+
+/**
+ * Returns TRUE if a field map array value represents an languagefield.
+ *
+ * Provided for use as a callback by array_filter().
+ */
+function languagefield_field_map_filter($field) {
+  return !empty($field['type']) && $field['type'] == 'language_field';
+}
