diff --git c/plugins/access/site_language.inc w/plugins/access/site_language.inc
index 9ff2f70..43760a6 100644
--- c/plugins/access/site_language.inc
+++ w/plugins/access/site_language.inc
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Plugin to provide access control based upon node type.
+ * Plugin to provide access control based upon language.
  */
 
 /**
@@ -11,13 +11,14 @@
  */
 if (module_exists('locale')) {
   $plugin = array(
-    'title' => t("User: language"),
-    'description' => t('Control access by the language the user or site currently uses.'),
+    'title' => t('Language'),
+    'description' => t('Control access by the language the user or site currently uses, or an existing language context.'),
     'callback' => 'ctools_site_language_ctools_access_check',
     'default' => array('language' => array()),
     'settings form' => 'ctools_site_language_ctools_access_settings',
     'settings form submit' => 'ctools_site_language_ctools_access_settings_submit',
     'summary' => 'ctools_site_language_ctools_access_summary',
+    'required context' => new ctools_context_optional(t('Language Source'), 'language'),
   );
 }
 
@@ -30,10 +31,10 @@ function ctools_site_language_ctools_access_settings($form, &$form_state, $conf)
   );
   $options = array_merge($options, locale_language_list());
   $form['settings']['language'] = array(
-    '#title' => t('Language'),
+    '#title' => t('Language to compare with'),
     '#type' => 'checkboxes',
     '#options' => $options,
-    '#description' => t('Pass only if the current site language is one of the selected languages.'),
+    '#description' => t('Pass only if the current site language (or chosen language source) is one of the selected languages.'),
     '#default_value' => $conf['language'],
   );
   return $form;
@@ -43,7 +44,18 @@ function ctools_site_language_ctools_access_settings($form, &$form_state, $conf)
  * Check for access.
  */
 function ctools_site_language_ctools_access_check($conf, $context) {
-  global $language;
+  // We use the site's current language if there is no specified languaged context.
+  if (!$context->is_type('language')) {
+    global $language;
+  }
+
+  elseif (isset($context) && !empty($context->data)) {
+    $language = $context->data;
+  }
+
+  else {
+    return FALSE;
+  }
 
   // Specialcase: If 'default' is checked, return TRUE if the default site language
   // matches the node language.
@@ -64,6 +76,8 @@ function ctools_site_language_ctools_access_check($conf, $context) {
  * Provide a summary description based upon the checked site_languages.
  */
 function ctools_site_language_ctools_access_summary($conf, $context) {
+  $language_identifier = $context->is_type('language') ? $context->get_identifier() : t('Site language');
+
   $languages = array(
     'default' => t('Default site language'),
   );
@@ -79,9 +93,9 @@ function ctools_site_language_ctools_access_summary($conf, $context) {
   }
 
   if (empty($names)) {
-    return t('Site language is any language');
+    return t('@language_identifier is any language', array('@language_identifier' => $language_identifier));
   }
 
-  return format_plural(count($names), 'Site language is "@languages"', 'Site language is one of "@languages"', array('@languages' => implode(', ', $names)));
+  return format_plural(count($names), '@language_identifier is "@languages"', '@language_identifier is one of "@languages"', array('@language_identifier' => $language_identifier, '@languages' => implode(', ', $names)));
 }
 
diff --git c/plugins/arguments/language.inc w/plugins/arguments/language.inc
new file mode 100644
index 0000000..a6cf4be
--- /dev/null
+++ w/plugins/arguments/language.inc
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ *
+ * Plugin to provide an argument handler for a language context.
+ */
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'title' => t('Language'),
+  // keyword to use for %substitution
+  'keyword' => 'language',
+  'description' => t('Creates a language context from a language code.'),
+  'context' => 'ctools_argument_language_context',
+);
+
+/**
+ * Discover if this argument gives us the node we crave.
+ */
+function ctools_argument_language_context($arg = NULL, $conf = NULL, $empty = FALSE) {
+  // If unset it wants a generic, unfilled context.
+  if (!isset($arg)) {
+    return ctools_context_create_empty('language');
+  }
+
+  return ctools_context_create('language', $arg);
+}
diff --git c/plugins/contexts/language.inc w/plugins/contexts/language.inc
new file mode 100644
index 0000000..b7c16e8
--- /dev/null
+++ w/plugins/contexts/language.inc
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * @file
+ *
+ * Plugin to provide a language context
+ */
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'title' => t('Language'),
+  'description' => t('A language context.'),
+  'context' => 'ctools_context_create_language',
+  'keyword' => 'language',
+  'edit form' => 'ctools_context_language_settings_form',
+  'context name' => 'language',
+  'convert list' => 'ctools_context_language_convert_list',
+  'convert' => 'ctools_context_language_convert',
+);
+
+/**
+ * It's important to remember that $conf is optional here, because contexts
+ * are not always created from the UI.
+ */
+function ctools_context_create_language($empty, $data = NULL, $conf = FALSE) {
+  $context = new ctools_context('language');
+  $context->plugin = 'language';
+
+  if ($empty) {
+    return $context;
+  }
+
+  // We've been given a full language object.
+  if (is_object($data)) {
+    $context->data = $data;
+    $context->title = $data->native;
+    return $context;
+  }
+  // We've been given a UI configured language.
+  if (is_array($data) && isset($data['language'])) {
+    switch ($data['language']) {
+      case 'current':
+        global $language;
+        break;
+      default:
+        // Assume we have a language code.
+        $languages = language_list();
+        $language = $languages[$data['language']];
+        break;
+    }
+    $context->data = $language;
+    $context->title = $language->native;
+    return $context;
+  }
+  // This is probably a programatically passed language code.
+  if (is_string($data)) {
+    $languages = language_list();
+    if (isset($languages[$data])) {
+      $language = $languages[$data];
+      $context->data = $language;
+      $context->title = $language->native;
+    }
+    return $context;
+  }
+}
+
+function ctools_context_language_settings_form($form, &$form_state) {
+  $conf = $form_state['conf'];
+  $options = array(
+    'current' => t('Current Language'),
+  );
+  $languages = language_list();
+  foreach ($languages as $code => $language) {
+    $options[$code] = $language->native;
+  }
+
+  $form['language'] = array(
+    '#type' => 'select',
+    '#title' => t('Choose Language Context'),
+    '#default_value' => $conf['language'],
+    '#options' => $options,
+  );
+  return $form;
+}
+
+function ctools_context_language_settings_form_submit($form, &$form_state) {
+  $form_state['conf']['language'] = $form_state['values']['language'];
+}
+
+/**
+ * Provide a list of ways that this context can be converted to a string.
+ */
+function ctools_context_language_convert_list() {
+  return array (
+    'language' => t('Language Code'),
+    'name' => t('English Language Name'),
+    'native' => t('Native Language Name'),
+    'direction' => t('Language Direction'),
+    'enabled' => t('Language Status'),
+    'plurals' => t('Plurals'),
+    'formula' => t('Plural Formula'),
+    'domain' => t('Domain Prefix Language Code'),
+    'prefix' => t('URL Prefix Language Code'),
+    'weight' => t('Language Weight'),
+  );
+}
+
+/**
+ * Convert a context into a string.
+ */
+function ctools_context_language_convert($context, $type) {
+  return $context->data->{$type};
+}
diff --git c/plugins/relationships/entity_language.inc w/plugins/relationships/entity_language.inc
new file mode 100644
index 0000000..d33194b
--- /dev/null
+++ w/plugins/relationships/entity_language.inc
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Plugin to provide an relationship handler for a language from an entity.
+ */
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'title' => t('Language from Entity'),
+  'get child' => 'ctools_entity_language_get_child',
+  'get children' => 'ctools_entity_language_get_children',
+);
+
+function ctools_entity_language_get_child($plugin, $parent, $child) {
+  $plugins = ctools_entity_language_get_children($plugin, $parent);
+  return $plugins[$parent . ':' . $child];
+}
+
+function ctools_entity_language_get_children($parent_plugin, $parent) {
+  $entities = entity_get_info();
+  $plugins = array();
+
+  foreach (module_implements('entity_info') as $module) {
+    module_load_install($module);
+    $schemas = drupal_get_schema();
+
+    foreach ($entities as $entity_type => $entity_info) {
+      if (empty($entity_info['base table'])) {
+        continue;
+      }
+
+      $table = $entity_info['base table'];
+      if (isset($schemas[$table]['fields']['language'])) {
+        $plugin_id = $parent . ':' . $entity_type;
+        $plugin['title'] = t('Language from @entity', array('@entity' => $entity_info['label']));
+        $plugin['description'] = t('Creates a language context from the @entity schema.', array('@entity' => $entity_info['label']));
+        $plugin['keyword'] = 'language';
+        $plugin['context name'] = 'language';
+        $plugin['name'] = $plugin_id;
+        $plugin['context'] = 'ctools_entity_language_context';
+        $plugin['required context'] = new ctools_context_required($entity_info['label'], $entity_type);
+        $plugins[$plugin_id] = $plugin;
+      }
+    }
+  }
+  drupal_alter('ctools_entity_language_relationships', $plugins);
+  return $plugins;
+}
+
+/**
+ * Return a new context based on an existing context.
+ */
+function ctools_entity_language_context($context, $conf) {
+  $plugin = $conf['name'];
+  list($plugin, $entity_type) = explode(':', $plugin);
+  // If unset it wants a generic, unfilled context, which is just NULL.
+  $entity_info = entity_get_info($entity_type);
+  if (empty($context->data) || !isset($context->data->{$entity_info['entity keys']['id']})) {
+    $language = language_default();
+    return ctools_context_create_empty('language', $language);
+  }
+
+  if (isset($context->data->{$entity_info['entity keys']['id']})) {
+    return ctools_context_create('language', $context->data->language);
+  }
+}
