diff --git a/config/application.config.php b/config/application.config.php
index bd737f1eb2b3612e81e8b49e69b714f540d9021b..e7273758228dc0f9bf99e566ca564e0daae370e3 100644
--- a/config/application.config.php
+++ b/config/application.config.php
@@ -23,6 +23,9 @@ $config = array(
 if (PHP_SAPI == 'cli' && !defined('VUFIND_PHPUNIT_RUNNING')) {
     $config['modules'][] = 'VuFindConsole';
 }
+if (APPLICATION_ENV == 'development') {
+    $config['modules'][] = 'VuFindDevTools';
+}
 if ($localModules = getenv('VUFIND_LOCAL_MODULES')) {
     $localModules = array_map('trim', explode(',', $localModules));
     foreach ($localModules as $current) {
diff --git a/module/VuFindDevTools/Module.php b/module/VuFindDevTools/Module.php
new file mode 100644
index 0000000000000000000000000000000000000000..1fd5615a092497f1d2ef71e1e8e0bf17b7ca38f9
--- /dev/null
+++ b/module/VuFindDevTools/Module.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * VuFind Developer Tools module.
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  Module
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://github.com/dmj/vf2-proxy
+ */
+namespace VuFindDevTools;
+use Zend\ModuleManager\ModuleManager,
+    Zend\Mvc\MvcEvent;
+
+/**
+ * VuFind Developer Tools module.
+ *
+ * @category VuFind2
+ * @package  Module
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://github.com/dmj/vf2-proxy
+ */
+class Module
+{
+    /**
+     * Get module configuration
+     *
+     * @return array
+     */
+    public function getConfig()
+    {
+        return include __DIR__ . '/config/module.config.php';
+    }
+
+    /**
+     * Get autoloader configuration
+     *
+     * @return array
+     */
+    public function getAutoloaderConfig()
+    {
+        return array(
+            'Zend\Loader\StandardAutoloader' => array(
+                'namespaces' => array(
+                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
+                ),
+            ),
+        );
+    }
+}
diff --git a/module/VuFindDevTools/config/module.config.php b/module/VuFindDevTools/config/module.config.php
new file mode 100644
index 0000000000000000000000000000000000000000..e37ca41d6c049130a92511287b992b836d50d8c7
--- /dev/null
+++ b/module/VuFindDevTools/config/module.config.php
@@ -0,0 +1,12 @@
+<?php
+namespace VuFindLocalTemplate\Module\Configuration;
+
+$config = array(
+    'controllers' => array(
+        'invokables' => array(
+            'devtools' => 'VuFindDevTools\Controller\DevtoolsController',
+        ),
+    ),
+);
+
+return $config;
\ No newline at end of file
diff --git a/module/VuFindDevTools/src/VuFindDevTools/Controller/DevtoolsController.php b/module/VuFindDevTools/src/VuFindDevTools/Controller/DevtoolsController.php
new file mode 100644
index 0000000000000000000000000000000000000000..88aac6adad009885b11b99a0205df1f71eb31c8c
--- /dev/null
+++ b/module/VuFindDevTools/src/VuFindDevTools/Controller/DevtoolsController.php
@@ -0,0 +1,197 @@
+<?php
+/**
+ * Development Tools Controller
+ *
+ * PHP Version 5
+ *
+ * Copyright (C) Villanova University 2011.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA    02111-1307    USA
+ *
+ * @category VuFind2
+ * @package  Controller
+ * @author   Mark Triggs <vufind-tech@lists.sourceforge.net>
+ * @author   Chris Hallberg <challber@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/alphabetical_heading_browse Wiki
+ */
+namespace VuFindDevTools\Controller;
+use Zend\I18n\Translator\TextDomain;
+
+/**
+ * Development Tools Controller
+ *
+ * @category VuFind2
+ * @package  Controller
+ * @author   Mark Triggs <vufind-tech@lists.sourceforge.net>
+ * @author   Chris Hallberg <challber@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/alphabetical_heading_browse Wiki
+ */
+class DevtoolsController extends \VuFind\Controller\AbstractBase
+{
+    /**
+     * Get the path to the language files
+     *
+     * @param string $language Language file to include on path (null for base)
+     *
+     * @return string
+     */
+    protected function getLanguagePath($language = null)
+    {
+        $path = APPLICATION_PATH . '/languages';
+        if (null !== $language) {
+            $path .= '/' . $language . '.ini';
+        }
+        return $path;
+    }
+
+    /**
+     * Get a list of help files in the specified language.
+     *
+     * @param string $language Language to check.
+     *
+     * @return array
+     */
+    protected function getHelpFiles($language)
+    {
+        $dir = APPLICATION_PATH
+            . '/themes/root/templates/HelpTranslations/' . $language;
+        if (!file_exists($dir) || !is_dir($dir)) {
+            return array();
+        }
+        $handle = opendir($dir);
+        $files = array();
+        while ($file = readdir($handle)) {
+            if (substr($file, -6) == '.phtml') {
+                $files[] = $file;
+            }
+        }
+        closedir($handle);
+        return $files;
+    }
+
+    /**
+     * Get a list of languages supported by VuFind:
+     *
+     * @return array
+     */
+    protected function getLanguages()
+    {
+        $langs = array();
+        $dir = opendir($this->getLanguagePath());
+        while ($file = readdir($dir)) {
+            if (substr($file, -4) == '.ini') {
+                $lang = current(explode('.', $file));
+                if ('native' != $lang) {
+                    $langs[] = $lang;
+                }
+            }
+        }
+        closedir($dir);
+        return $langs;
+    }
+
+    /**
+     * Find strings that are absent from a language file.
+     *
+     * @param TextDomain $lang1 Left side of comparison
+     * @param TextDomain $lang2 Right side of comparison
+     *
+     * @return array
+     */
+    protected function findMissingLanguageStrings($lang1, $lang2)
+    {
+        // Find strings missing from language 2:
+        $notInL2 = array();
+        $l2Keys = array_keys((array)$lang2);
+        foreach($lang1 as $key => $junk) {
+            if (!in_array($key, $l2Keys)) {
+                $notInL2[] = $key;
+            }
+        }
+        return $notInL2;
+    }
+
+    /**
+     * Compare two languages and return an array of details about how they differ.
+     *
+     * @param TextDomain $lang1 Left side of comparison
+     * @param TextDomain $lang2 Right side of comparison
+     *
+     * @return array
+     */
+    protected function compareLanguages($lang1, $lang2)
+    {
+        return array(
+            'notInL1' => $this->findMissingLanguageStrings($lang2, $lang1),
+            'notInL2' => $this->findMissingLanguageStrings($lang1, $lang2),
+            'l1Percent' => number_format(count($lang1) / count($lang2) * 100, 2),
+            'l2Percent' => number_format(count($lang2) / count($lang1) * 100, 2),
+        );
+    }
+
+    /**
+     * Get English name of language
+     *
+     * @param string $lang Language code
+     *
+     * @return string
+     */
+    public function getLangName($lang)
+    {
+        $config = \VuFind\Config\Reader::getConfig();
+        if (isset($config->Languages->$lang)) {
+            return $config->Languages->$lang;
+        }
+        switch($lang) {
+        case 'en-gb':
+            return 'British English';
+        case 'pt-br':
+            return 'Brazilian Portuguese';
+        default:
+            return $lang;
+        }
+    }
+
+    /**
+     * Language action
+     *
+     * @return array
+     */
+    public function languageAction()
+    {
+        $loader = new \VuFind\I18n\Translator\Loader\ExtendedIni();
+        $mainLanguage = $this->params()->fromQuery('main', 'en');
+        $main = $loader->load(null, $this->getLanguagePath($mainLanguage));
+
+        $details = array();
+        $allLangs = $this->getLanguages();
+        sort($allLangs);
+        foreach ($allLangs as $langCode) {
+            $lang = $loader->load(null, $this->getLanguagePath($langCode));
+            $details[$langCode] = $this->compareLanguages($main, $lang);
+            $details[$langCode]['object'] = $lang;
+            $details[$langCode]['name'] = $this->getLangName($langCode);
+            $details[$langCode]['helpFiles'] = $this->getHelpFiles($langCode);
+        }
+
+        return array(
+            'details' => $details,
+            'mainCode' => $mainLanguage,
+            'mainName' => $this->getLangName($mainLanguage),
+            'main' => $main,
+        );
+    }
+}
\ No newline at end of file
diff --git a/themes/blueprint/templates/devtools/language.phtml b/themes/blueprint/templates/devtools/language.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..12b35eae153051c84e8010aee9d2c4a8a5f3e698
--- /dev/null
+++ b/themes/blueprint/templates/devtools/language.phtml
@@ -0,0 +1,35 @@
+<?
+    $this->headTitle($this->translate('Language'));
+?>
+
+<h1>Comparing Languages Against <?=$this->escapeHtml($mainName)?></h1>
+
+<h2>Summary</h2>
+
+<table>
+  <tr><th>Language</th><th>Missing Lines</th><th>Extra Lines</th><th>Percent Translated</th><th>Extra Help Files</th></tr>
+  <? foreach ($details as $langCode => $diffs): ?>
+    <tr>
+      <td><?=$this->escapeHtml($langCode . ' (' . $diffs['name'] . ')')?></td>
+      <td><?=count($diffs['notInL2'])?></td>
+      <td><?=count($diffs['notInL1'])?></td>
+      <td><?=$this->escapeHtml($diffs['l2Percent'])?></td>
+      <td><?=count($diffs['helpFiles'])?></td>
+    </tr>
+  <? endforeach; ?>
+</table>
+
+<? foreach ($details as $langCode => $diffs): ?>
+  <? if (count($diffs['notInL1']) > 0): ?>
+    <h2>Extra Lines In <?=$this->escapeHtml($diffs['name'])?> (<?=$this->escapeHtml($langCode)?>.ini)</h2>
+    <? foreach ($diffs['notInL1'] as $key): ?>
+      <?=$this->escapeHtml($key)?> = "<?=$this->escapeHtml($diffs['object'][$key])?>"<br />
+    <? endforeach; ?>
+  <? endif; ?>
+  <? if (count($diffs['notInL2']) > 0): ?>
+    <h2>Missing From <?=$this->escapeHtml($diffs['name'])?> (<?=$this->escapeHtml($langCode)?>.ini)</h2>
+    <? foreach ($diffs['notInL2'] as $key): ?>
+      <?=$this->escapeHtml($key)?> = "<?=$this->escapeHtml($main[$key])?>"<br />
+    <? endforeach; ?>
+  <? endif; ?>
+<? endforeach; ?>
\ No newline at end of file