diff --git a/core/Translate/Filter/ByBaseTranslations.php b/core/Translate/Filter/ByBaseTranslations.php
index dd5f98e5bd08d4229970655d8ea87ff7c07a7514..001a293c2e61bfc0e787eecc43644b10a4036cab 100644
--- a/core/Translate/Filter/ByBaseTranslations.php
+++ b/core/Translate/Filter/ByBaseTranslations.php
@@ -19,6 +19,18 @@ use Piwik\Translate\Filter\FilterAbstract;
  */
 class ByBaseTranslations extends FilterAbstract
 {
+    protected $_baseTranslations = array();
+
+    /**
+     * Sets base translations
+     *
+     * @param array $baseTranslations
+     */
+    public function __construct($baseTranslations=array())
+    {
+        $this->_baseTranslations = $baseTranslations;
+    }
+
     /**
      * Removes all translations that aren't present in the base translations set in constructor
      *
diff --git a/core/Translate/Filter/ByParameterCount.php b/core/Translate/Filter/ByParameterCount.php
index a98ef13f967767bf8339a07844648bf21d21eb77..1a1e716294a4fcf30834dda21b69785611717643 100644
--- a/core/Translate/Filter/ByParameterCount.php
+++ b/core/Translate/Filter/ByParameterCount.php
@@ -19,6 +19,18 @@ use Piwik\Translate\Filter\FilterAbstract;
  */
 class ByParameterCount extends FilterAbstract
 {
+    protected $_baseTranslations = array();
+
+    /**
+     * Sets base translations
+     *
+     * @param array $baseTranslations
+     */
+    public function __construct($baseTranslations=array())
+    {
+        $this->_baseTranslations = $baseTranslations;
+    }
+
     /**
      * Removes all translations where the placeholder parameter count differs to base translation
      *
diff --git a/core/Translate/Filter/FilterAbstract.php b/core/Translate/Filter/FilterAbstract.php
index f61bb614b5e5b93c22658e21078fc478db68988b..eca3489bdf6191fbc9be4b38b58226cb323185d1 100644
--- a/core/Translate/Filter/FilterAbstract.php
+++ b/core/Translate/Filter/FilterAbstract.php
@@ -19,18 +19,6 @@ abstract class FilterAbstract
 {
     protected $_filteredData = array();
 
-    protected $_baseTranslations = array();
-
-    /**
-     * Sets base translations
-     *
-     * @param array $baseTranslations
-     */
-    public function __construct($baseTranslations=array())
-    {
-        $this->_baseTranslations = $baseTranslations;
-    }
-
     /**
      * Filter the given translations
      *
diff --git a/core/Translate/Filter/UnnecassaryWhitespaces.php b/core/Translate/Filter/UnnecassaryWhitespaces.php
index 7a80a216127cb0d6786008b016c63d465829ae1f..1de5c50a1f01ea8531f21cdfce4ef5d6b899e436 100644
--- a/core/Translate/Filter/UnnecassaryWhitespaces.php
+++ b/core/Translate/Filter/UnnecassaryWhitespaces.php
@@ -19,6 +19,18 @@ use Piwik\Translate\Filter\FilterAbstract;
  */
 class UnnecassaryWhitespaces extends FilterAbstract
 {
+    protected $_baseTranslations = array();
+
+    /**
+     * Sets base translations
+     *
+     * @param array $baseTranslations
+     */
+    public function __construct($baseTranslations=array())
+    {
+        $this->_baseTranslations = $baseTranslations;
+    }
+
     /**
      * Removes all unnecassary whitespaces and newlines from the given translations
      *
@@ -32,14 +44,17 @@ class UnnecassaryWhitespaces extends FilterAbstract
         foreach ($translations AS $pluginName => $pluginTranslations) {
             foreach ($pluginTranslations AS $key => $translation) {
 
-                $baseTranslation  = $this->_baseTranslations[$pluginName][$key];
+                $baseTranslation = '';
+                if (isset($this->_baseTranslations[$pluginName][$key])) {
+                    $baseTranslation  = $this->_baseTranslations[$pluginName][$key];
+                }
 
                 // remove excessive line breaks (and leading/trailing whitespace) from translations
                 $stringNoLineBreak = trim($translation);
                 $stringNoLineBreak = str_replace("\r", "", $stringNoLineBreak); # remove useless carrige renturns
                 $stringNoLineBreak = preg_replace('/(\n[ ]+)/', "\n", $stringNoLineBreak); # remove useless white spaces after line breaks
                 $stringNoLineBreak = preg_replace('/([\n]{2,})/', "\n\n", $stringNoLineBreak); # remove excessive line breaks
-                if (!isset($baseTranslation) || !substr_count($baseTranslation, "\n")) {
+                if (empty($baseTranslation) || !substr_count($baseTranslation, "\n")) {
                     $stringNoLineBreak = preg_replace("/[\n]+/", " ", $stringNoLineBreak); # remove all line breaks if english string doesn't contain any
                 }
                 $stringNoLineBreak = preg_replace('/([ ]{2,})/', " ", $stringNoLineBreak); # remove excessive white spaces again as there might be any now, after removing line breaks
diff --git a/core/Translate/Validate/CoreTranslations.php b/core/Translate/Validate/CoreTranslations.php
index d1f53e93d0303613bb4e5c12109adeb6aa5d871d..068d1c3cbc1df3404500b0166ba08154e8f4eef9 100644
--- a/core/Translate/Validate/CoreTranslations.php
+++ b/core/Translate/Validate/CoreTranslations.php
@@ -32,6 +32,18 @@ class CoreTranslations extends ValidateAbstract
     const __ERRORSTATE_LOCALEINVALIDLANGUAGE__      = 'Locale is invalid - invalid language code';
     const __ERRORSTATE_LOCALEINVALIDCOUNTRY__       = 'Locale is invalid - invalid country code';
 
+    protected $_baseTranslations = array();
+
+    /**
+     * Sets base translations
+     *
+     * @param array $baseTranslations
+     */
+    public function __construct($baseTranslations=array())
+    {
+        $this->_baseTranslations = $baseTranslations;
+    }
+
     /**
      * Validates the given translations
      *  * There need to be more than 250 translations presen
@@ -46,30 +58,32 @@ class CoreTranslations extends ValidateAbstract
      */
     public function isValid($translations)
     {
+        $this->_message = null;
+
         if (250 > count($translations, COUNT_RECURSIVE)) {
-            $this->_error = self::__ERRORSTATE_MINIMUMTRANSLATIONS__;
+            $this->_message = self::__ERRORSTATE_MINIMUMTRANSLATIONS__;
             return false;
         }
 
         if (empty($translations['General']['Locale'])) {
-            $this->_error = self::__ERRORSTATE_LOCALEREQUIRED__;
+            $this->_message = self::__ERRORSTATE_LOCALEREQUIRED__;
             return false;
         }
 
         if (empty($translations['General']['TranslatorName'])) {
-            $this->_error = self::__ERRORSTATE_TRANSLATORINFOREQUIRED__;
+            $this->_message = self::__ERRORSTATE_TRANSLATORINFOREQUIRED__;
             return false;
         }
 
         if (empty($translations['General']['TranslatorEmail'])) {
-            $this->_error = self::__ERRORSTATE_TRANSLATOREMAILREQUIRED__;
+            $this->_message = self::__ERRORSTATE_TRANSLATOREMAILREQUIRED__;
             return false;
         }
 
         if (!empty($translations['General']['LayoutDirection']) &&
             !in_array($translations['General']['LayoutDirection'], array('ltr', 'rtl'))
         ) {
-            $this->_error = self::__ERRORSTATE_LAYOUTDIRECTIONINVALID__;
+            $this->_message = self::__ERRORSTATE_LAYOUTDIRECTIONINVALID__;
             return false;
         }
 
@@ -77,13 +91,13 @@ class CoreTranslations extends ValidateAbstract
         $allCountries = Common::getCountriesList();
 
         if (!preg_match('/^([a-z]{2})_([A-Z]{2})\.UTF-8$/', $translations['General']['Locale'], $matches)) {
-            $this->_error = self::__ERRORSTATE_LOCALEINVALID__;
+            $this->_message = self::__ERRORSTATE_LOCALEINVALID__;
             return false;
         } else if (!array_key_exists($matches[1], $allLanguages)) {
-            $this->_error = self::__ERRORSTATE_LOCALEINVALIDLANGUAGE__;
+            $this->_message = self::__ERRORSTATE_LOCALEINVALIDLANGUAGE__;
             return false;
         } else if (!array_key_exists(strtolower($matches[2]), $allCountries)) {
-            $this->_error = self::__ERRORSTATE_LOCALEINVALIDCOUNTRY__;
+            $this->_message = self::__ERRORSTATE_LOCALEINVALIDCOUNTRY__;
             return false;
         }
 
diff --git a/core/Translate/Validate/NoScripts.php b/core/Translate/Validate/NoScripts.php
index cdba2c608f589b7f08d95fd323954ed3b4bef86c..7116e409a864b3c5b9acb89650d3607b44352868 100644
--- a/core/Translate/Validate/NoScripts.php
+++ b/core/Translate/Validate/NoScripts.php
@@ -31,14 +31,14 @@ class NoScripts extends ValidateAbstract
      */
     public function isValid($translations)
     {
-        $this->_error = null;
+        $this->_message = null;
 
         // check if any translation contains restricted script tags
         $serializedStrings = serialize($translations);
         $invalids = array("<script", 'document.', 'javascript:', 'src=', 'background=', 'onload=');
         foreach ($invalids as $invalid) {
             if (stripos($serializedStrings, $invalid) !== false) {
-                $this->_error = 'script tags restricted for language files';
+                $this->_message = 'script tags restricted for language files';
                 return false;
             }
         }
diff --git a/core/Translate/Validate/ValidateAbstract.php b/core/Translate/Validate/ValidateAbstract.php
index 6fdee45ed24ea3b6eae3b2c4e5d5e9ac59db6b01..ca71850ed36fa7524e4ede89583b303c0ea95888 100644
--- a/core/Translate/Validate/ValidateAbstract.php
+++ b/core/Translate/Validate/ValidateAbstract.php
@@ -17,19 +17,7 @@ namespace Piwik\Translate\Validate;
  */
 abstract class ValidateAbstract
 {
-    protected $_baseTranslations = array();
-
-    protected $_error = null;
-
-    /**
-     * Sets base translations
-     *
-     * @param array $baseTranslations
-     */
-    public function __construct($baseTranslations=array())
-    {
-        $this->_baseTranslations = $baseTranslations;
-    }
+    protected $_message = null;
 
     /**
      * Returns if the given translations are valid
@@ -42,11 +30,13 @@ abstract class ValidateAbstract
     abstract public function isValid($translations);
 
     /**
-     * Returns the error occured while validating
-     * @return mixed
+     * Returns an array of messages that explain why the most recent isValid()
+     * call returned false.
+     *
+     * @return array
      */
-    public function getError()
+    public function getMessage()
     {
-        return $this->_error;
+        return $this->_message;
     }
 }
\ No newline at end of file
diff --git a/core/Translate/Writer.php b/core/Translate/Writer.php
index 66e34449ec00ff80da9a0bcffddfb2eb4aed989e..dea88a7103e5a3713f9865729addab023b5c8e1c 100644
--- a/core/Translate/Writer.php
+++ b/core/Translate/Writer.php
@@ -14,13 +14,8 @@ namespace Piwik\Translate;
 use Exception;
 use Piwik\Common;
 use Piwik\PluginsManager;
-use Piwik\Translate\Filter\ByBaseTranslations;
-use Piwik\Translate\Filter\ByParameterCount;
-use Piwik\Translate\Filter\EncodedEntities;
-use Piwik\Translate\Filter\EmptyTranslations;
-use Piwik\Translate\Filter\UnnecassaryWhitespaces;
-use Piwik\Translate\Validate\CoreTranslations;
-use Piwik\Translate\Validate\NoScripts;
+use Piwik\Translate\Filter\FilterAbstract;
+use Piwik\Translate\Validate\ValidateAbstract;
 
 /**
  * Writes clean translations to file
@@ -45,30 +40,44 @@ class Writer
     protected $_pluginName = null;
 
     /**
-     * base translations (english) for the current instance
+     * translations to write to file
      *
      * @var array
      */
-    protected $_baseTranslations = array();
+    protected $_translations = array();
 
     /**
-     * translations to write to file
+     * Validators to check translations with
      *
-     * @var array
+     * @var ValidateAbstract[]
      */
-    protected $_translations = array();
+    protected $_validators = array();
+
+    /**
+     * Message why validation failed
+     *
+     * @var string|null
+     */
+    protected $_validationMessage = null;
+
+    /**
+     * Filters to to apply to translations
+     *
+     * @var FilterAbstract[]
+     */
+    protected $_filters = array();
 
     /**
-     * Errors occured while cleaning the translations
+     * Messages which filter changed the data
      *
      * @var array
      */
-    protected $_cleanErrors = array();
+    protected $_filterMessages = array();
 
-    const __UNCLEANED__  = 'uncleaned';
-    const __CLEANED__    = 'cleaned';
+    const __UNFILTERED__  = 'unfiltered';
+    const __FILTERED__    = 'filtered';
 
-    protected $_currentState = self::__UNCLEANED__;
+    protected $_currentState = self::__UNFILTERED__;
 
     /**
      * If $pluginName is given, Writer will be initialized for the given plugin if it exists
@@ -92,9 +101,6 @@ class Writer
 
             $this->_pluginName = $pluginName;
         }
-
-        $this->_baseTranslations = $this->_loadTranslation('en');
-        $this->setTranslations($this->_loadTranslation($this->getLanguage()));
     }
 
     /**
@@ -125,7 +131,7 @@ class Writer
      */
     public function hasTranslations()
     {
-        return !empty($this->_baseTranslations) && !empty($this->_translations);
+        return !empty($this->_translations);
     }
 
     /**
@@ -135,19 +141,19 @@ class Writer
      */
     public function setTranslations($translations)
     {
-        $this->_currentState = self::__UNCLEANED__;
+        $this->_currentState = self::__UNFILTERED__;
         $this->_translations = $translations;
-        $this->_cleanTranslations();
+        $this->_applyFilters();
     }
 
     /**
-     * Load translations from file
+     * Get translations from file
      *
      * @param  string  $lang  ISO 639-1 alpha-2 language code
      * @throws Exception
      * @return array   Array of translations ( plugin => ( key => translated string ) )
      */
-    protected function _loadTranslation($lang)
+    public function getTranslations($lang)
     {
         $path = $this->_getTranslationPath('lang', $lang);
         if (!is_readable($path)) {
@@ -224,10 +230,17 @@ class Writer
     /**
      * Save translations to file; translations should already be cleaned.
      *
+     * @throws \Exception
      * @return bool|int  False if failure, or number of bytes written
      */
     public function save()
     {
+        $this->_applyFilters();
+
+        if (!$this->hasTranslations() || !$this->isValid()) {
+            throw new Exception('unable to save empty or invalid translations');
+        }
+
         $path = $this->getTranslationPath();
 
         Common::mkdir(dirname($path));
@@ -238,10 +251,17 @@ class Writer
     /**
      * Save translations to  temporary file; translations should already be cleansed.
      *
+     * @throws \Exception
      * @return bool|int False if failure, or number of bytes written
      */
     public function saveTemporary()
     {
+        $this->_applyFilters();
+
+        if (!$this->hasTranslations() || !$this->isValid()) {
+            throw new Exception('unable to save empty or invalid translations');
+        }
+
         $path = $this->getTemporaryTranslationPath();
 
         Common::mkdir(dirname($path));
@@ -249,14 +269,55 @@ class Writer
         return file_put_contents($path, $this->__toString());
     }
 
+    /**
+     * Adds an validator to check before saving
+     *
+     * @param ValidateAbstract $validator
+     */
+    public function addValidator(ValidateAbstract $validator)
+    {
+        $this->_validators[] = $validator;
+    }
+
+    /**
+     * Returns if translations are valid to save or not
+     *
+     * @return bool
+     */
+    public function isValid()
+    {
+        $this->_applyFilters();
+
+        $this->_validationMessage = null;
+
+        foreach ($this->_validators AS $validator) {
+            if (!$validator->isValid($this->_translations)) {
+                $this->_validationMessage = $validator->getMessage();
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns last validation message
+     *
+     * @return null|string
+     */
+    public function getValidationMessage()
+    {
+        return $this->_validationMessage;
+    }
+
     /**
      * Returns if the were translations removed while cleaning
      *
      * @return bool
      */
-    public function hasErrors()
+    public function wasFiltered()
     {
-        return !empty($this->_cleanErrors);
+        return !empty($this->_filterMessages);
     }
 
     /**
@@ -264,9 +325,17 @@ class Writer
      *
      * @return array
      */
-    public function getErrors()
+    public function getFilterMessages()
     {
-        return $this->_cleanErrors;
+        return $this->_filterMessages;
+    }
+
+    /**
+     * @param FilterAbstract $filter
+     */
+    public function addFilter(FilterAbstract $filter)
+    {
+        $this->_filters[] = $filter;
     }
 
     /**
@@ -274,77 +343,39 @@ class Writer
      *
      * @return bool   error state
      */
-    protected function _cleanTranslations()
+    protected function _applyFilters()
     {
         // skip if already cleaned
-        if ($this->_currentState == self::__CLEANED__) {
-            return $this->hasErrors();
+        if ($this->_currentState == self::__FILTERED__) {
+            return $this->wasFiltered();
         }
 
-        $this->_cleanErrors = array();
+        $this->_filterMessages = array();
 
         // skip if not translations available
         if (!$this->hasTranslations()) {
-            $this->_currentState = self::__CLEANED__;
+            $this->_currentState = self::__FILTERED__;
             return false;
         }
 
-        $basefilter = new ByBaseTranslations($this->_baseTranslations);
-        $cleanedTranslations = $basefilter->filter($this->_translations);
-        $filteredData = $basefilter->getFilteredData();
-        if (!empty($filteredData)) {
-            $this->_cleanErrors[] = "removed translations that are not present in base translations: " .var_export($filteredData, 1);
-        }
-
-        $emptyfilter = new EmptyTranslations($this->_baseTranslations);
-        $cleanedTranslations = $emptyfilter->filter($cleanedTranslations);
-        $filteredData = $emptyfilter->getFilteredData();
-        if (!empty($filteredData)) {
-            $this->_cleanErrors[] = "removed empty translations: " .var_export($filteredData, 1);
-        }
-
-        $parameterFilter = new ByParameterCount($this->_baseTranslations);
-        $cleanedTranslations = $parameterFilter->filter($cleanedTranslations);
-        $filteredData = $parameterFilter->getFilteredData();
-        if (!empty($filteredData)) {
-            $this->_cleanErrors[] = "removed translations that had diffrent parameter counts: " .var_export($filteredData, 1);
-        }
-
-        $whitespaceFilter = new UnnecassaryWhitespaces($this->_baseTranslations);
-        $cleanedTranslations = $whitespaceFilter->filter($cleanedTranslations);
-        $filteredData = $whitespaceFilter->getFilteredData();
-        if (!empty($filteredData)) {
-            $this->_cleanErrors[] = "filtered unnecassary whitespaces in some translations: " .var_export($filteredData, 1);
-        }
-
-        $entityFilter = new EncodedEntities($this->_baseTranslations);
-        $cleanedTranslations = $entityFilter->filter($cleanedTranslations);
-        $filteredData = $entityFilter->getFilteredData();
-        if (!empty($filteredData)) {
-            $this->_cleanErrors[] = "converting entities to characters in some translations: " .var_export($filteredData, 1);
-        }
-
-        $noscriptValidator = new NoScripts();
-        if (!$noscriptValidator->isValid($cleanedTranslations)) {
-            throw new Exception($noscriptValidator->getError());
-        }
+        $cleanedTranslations = $this->_translations;
 
-        // check requirements for core translations
-        if (empty($this->_pluginName)) {
+        foreach ($this->_filters AS $filter) {
 
-            $baseValidator = new CoreTranslations($this->_baseTranslations);
-            if(!$baseValidator->isValid($cleanedTranslations)) {
-                throw new Exception($baseValidator->getError());
+            $cleanedTranslations = $filter->filter($cleanedTranslations);
+            $filteredData = $filter->getFilteredData();
+            if (!empty($filteredData)) {
+                $this->_filterMessages[] = get_class($filter) . " changed: " .var_export($filteredData, 1);
             }
         }
 
-        $this->_currentState = self::__CLEANED__;
+        $this->_currentState = self::__FILTERED__;
 
         if ($cleanedTranslations != $this->_translations) {
-            $this->_cleanErrors[] = 'translations have been cleaned';
+            $this->_filterMessages[] = 'translations have been cleaned';
         }
 
         $this->_translations = $cleanedTranslations;
-        return $this->hasErrors();
+        return $this->wasFiltered();
     }
 }
diff --git a/tests/PHPUnit/Core/Translate/Validate/CoreTranslationsTest.php b/tests/PHPUnit/Core/Translate/Validate/CoreTranslationsTest.php
index 4c325db96c7c7a53d358718e658aabc82133c9eb..99ef39497c1fbbfa86133d258479812f12a7e86c 100644
--- a/tests/PHPUnit/Core/Translate/Validate/CoreTranslationsTest.php
+++ b/tests/PHPUnit/Core/Translate/Validate/CoreTranslationsTest.php
@@ -136,6 +136,6 @@ class CoreTranslationsTest extends PHPUnit_Framework_TestCase
         $filter = new CoreTranslations();
         $result = $filter->isValid($translations);
         $this->assertFalse($result);
-        $this->assertEquals($msg, $filter->getError());
+        $this->assertEquals($msg, $filter->getMessage());
     }
 }
diff --git a/tests/PHPUnit/Core/Translate/WriterTest.php b/tests/PHPUnit/Core/Translate/WriterTest.php
index 9606b66151c071314bd71025a87af1338e7c7ae1..8f2d6d6b3c470fc2758a0463a12c388ec6930ff3 100644
--- a/tests/PHPUnit/Core/Translate/WriterTest.php
+++ b/tests/PHPUnit/Core/Translate/WriterTest.php
@@ -2,6 +2,10 @@
 use Piwik\Common;
 use Piwik\Translate\Writer;
 use Piwik\Translate\Validate\CoreTranslations;
+use Piwik\Translate\Validate\NoScripts;
+use Piwik\Translate\Filter\ByBaseTranslations;
+use Piwik\Translate\Filter\ByParameterCount;
+use Piwik\Translate\Filter\UnnecassaryWhitespaces;
 
 /**
  * Piwik - Open source web analytics
@@ -26,7 +30,8 @@ class WriterTest extends PHPUnit_Framework_TestCase
     public function testConstructorValid($language, $plugin)
     {
         $translationWriter = new Writer($language, $plugin);
-        $this->assertTrue($translationWriter->hasTranslations());
+        $this->assertEquals($language, $translationWriter->getLanguage());
+        $this->assertFalse($translationWriter->hasTranslations());
     }
 
     public function getValidConstructorData()
@@ -51,21 +56,52 @@ class WriterTest extends PHPUnit_Framework_TestCase
     /**
      * @group Core
      * @group Translate
-     * @ expectedException Exception
-     * @dataProvider getExceptionalTranslations
      */
-    public function testSetTranslationsThrowsException($translations, $error)
+    public function testHasTranslations()
     {
         $writer = new Writer('de');
-        try {
-            $writer->setTranslations($translations);
-            $this->fail('Exception not thrown');
-        } catch (Exception $e) {
-            $this->assertEquals($error, $e->getMessage());
-        }
+        $writer->setTranslations(array('General' => array('test' => 'test')));
+        $this->assertTrue($writer->hasTranslations());
     }
 
-    public function getExceptionalTranslations()
+    /**
+     * @group Core
+     * @group Translate
+     */
+    public function testHasNoTranslations()
+    {
+        $writer = new Writer('de');
+        $this->assertFalse($writer->hasTranslations());
+    }
+
+    /**
+     * @group Core
+     * @group Translate
+     */
+    public function testSetTranslationsEmpty()
+    {
+        $writer = new Writer('de');
+        $writer->setTranslations(array());
+        $this->assertTrue($writer->isValid());
+        $this->assertFalse($writer->hasTranslations());
+    }
+
+    /**
+     * @group Core
+     * @group Translate
+     * @dataProvider getInvalidTranslations
+     */
+    public function testSetTranslationsInvalid($translations, $error)
+    {
+        $writer = new Writer('de');
+        $writer->setTranslations($translations);
+        $writer->addValidator(new NoScripts());
+        $writer->addValidator(new CoreTranslations());
+        $this->assertFalse($writer->isValid());
+        $this->assertEquals($error, $writer->getValidationMessage());
+    }
+
+    public function getInvalidTranslations()
     {
         $translations = json_decode(file_get_contents(PIWIK_INCLUDE_PATH.'/lang/de.json'), true);
         return array(
@@ -94,7 +130,28 @@ class WriterTest extends PHPUnit_Framework_TestCase
     /**
      * @group Core
      * @group Translate
-     * @group Translate_Write
+     * @expectedException Exception
+     */
+    public function testSaveException()
+    {
+        $writer = new Writer('it');
+        $writer->save();
+    }
+
+    /**
+     * @group Core
+     * @group Translate
+     * @expectedException Exception
+     */
+    public function testSaveTemporaryException()
+    {
+        $writer = new Writer('it');
+        $writer->saveTemporary();
+    }
+
+    /**
+     * @group Core
+     * @group Translate
      */
     public function testSaveTranslation()
     {
@@ -111,12 +168,20 @@ class WriterTest extends PHPUnit_Framework_TestCase
         );
 
         $translationWriter = new Writer('fr');
+
+        $translationWriter->addFilter(new UnnecassaryWhitespaces($translations));
+        $translationWriter->addFilter(new ByBaseTranslations($translations));
+        $translationWriter->addFilter(new ByParameterCount($translations));
+
         $translationWriter->setTranslations($translationsToWrite);
 
         $rc = $translationWriter->saveTemporary();
+
+        @unlink(PIWIK_INCLUDE_PATH.'/tmp/fr.json');
+
         $this->assertGreaterThan(50000, $rc);
 
-        $this->assertCount(4, $translationWriter->getErrors());
+        $this->assertCount(4, $translationWriter->getFilterMessages());
     }
 
     /**
diff --git a/tests/PHPUnit/Plugins/LanguagesManagerTest.php b/tests/PHPUnit/Plugins/LanguagesManagerTest.php
index 8e0047858f0504b47713995da4d715f2c986a5ff..dfe60e60988ff4ad7693bfff635e5865d89a919e 100755
--- a/tests/PHPUnit/Plugins/LanguagesManagerTest.php
+++ b/tests/PHPUnit/Plugins/LanguagesManagerTest.php
@@ -9,6 +9,13 @@ use Piwik\Common;
 use Piwik\Plugins\LanguagesManager\API;
 use Piwik\Translate\Writer;
 use Piwik\PluginsManager;
+use Piwik\Translate\Validate\NoScripts;
+use Piwik\Translate\Validate\CoreTranslations;
+use Piwik\Translate\Filter\ByBaseTranslations;
+use Piwik\Translate\Filter\ByParameterCount;
+use Piwik\Translate\Filter\EmptyTranslations;
+use Piwik\Translate\Filter\EncodedEntities;
+use Piwik\Translate\Filter\UnnecassaryWhitespaces;
 
 require_once 'LanguagesManager/API.php';
 
@@ -62,10 +69,33 @@ class Test_LanguagesManager extends PHPUnit_Framework_TestCase
     {
         $translationWriter = new Writer($language, $plugin);
 
-        if ($translationWriter->hasErrors()) {
+        $baseTranslations = $translationWriter->getTranslations('en');
+
+        $translationWriter->addValidator(new NoScripts());
+        if (empty($plugin)) {
+            $translationWriter->addValidator(new CoreTranslations($baseTranslations));
+        }
+
+        $translationWriter->addFilter(new ByBaseTranslations($baseTranslations));
+        $translationWriter->addFilter(new EmptyTranslations());
+        $translationWriter->addFilter(new ByParameterCount($baseTranslations));
+        $translationWriter->addFilter(new UnnecassaryWhitespaces($baseTranslations));
+        $translationWriter->addFilter(new EncodedEntities());
+
+        $translations = $translationWriter->getTranslations($language);
+
+        if (empty($translations)) {
+            return; // skip language / plugin combinations that aren't present
+        }
+
+        $translationWriter->setTranslations($translations);
+
+        $this->assertTrue($translationWriter->isValid(), $translationWriter->getValidationMessage());
+
+        if ($translationWriter->wasFiltered()) {
 
             $translationWriter->saveTemporary();
-            $this->fail(implode("\n", $translationWriter->getErrors()) . "\n" . 'Translation file errors detected in ' . $language . "...\n");
+            $this->fail(implode("\n", $translationWriter->getFilterMessages()) . "\n" . 'Translation file errors detected in ' . $language . "...\n");
         }
     }