Index: /CKLangTool/trunk/_dev/build.bat
===================================================================
--- /CKLangTool/trunk/_dev/build.bat	(revision 3136)
+++ /CKLangTool/trunk/_dev/build.bat	(revision 3136)
@@ -0,0 +1,16 @@
+@echo off
+
+if "%ANT_HOME%"=="" goto noAntHome
+if "%JAVA_HOME%"=="" goto noJavaHome
+call "%ANT_HOME%\bin\ant.bat" exe
+call "%ANT_HOME%\bin\ant.bat" clean
+goto end
+
+:noAntHome
+echo ANT_HOME environment variable is not set
+goto end
+
+:noJavaHome
+echo JAVA_HOME environment variable is not set
+
+:end
Index: /CKLangTool/trunk/_dev/build.xml
===================================================================
--- /CKLangTool/trunk/_dev/build.xml	(revision 3136)
+++ /CKLangTool/trunk/_dev/build.xml	(revision 3136)
@@ -0,0 +1,59 @@
+<project name="langtool" default="exe" basedir="../">
+	<property name="build" location="build" />
+	<property name="rhino.jar" location="_dev/_thirdparty/rhino/js.jar" />
+	<property name="source.dir" location="_source" />
+	<property name="launch4j.dir" location="_dev/_thirdparty/launch4j" />
+
+	<target name="init">
+		<tstamp />
+		<mkdir dir="${build}" />
+	</target>
+
+	<target name="compile" depends="init" description="compile js">
+		<java fork="yes" classname="org.mozilla.javascript.tools.jsc.Main" failonerror="true">
+			<arg value="-debug" />
+			<arg value="${source.dir}/langtool.js" />
+			<arg value="${source.dir}/includes/cklangtool.js" />
+			<arg value="${source.dir}/includes/io.js" />
+		</java>
+	</target>
+
+	<target name="copy" depends="compile" description="copy files">
+		<copy file="${source.dir}/includes/cklangtool.class" tofile="${build}/cklangtool.class" overwrite="true" />
+		<copy file="${source.dir}/includes/io.class" tofile="${build}/io.class" overwrite="true" />
+		<copy file="${source.dir}/langtool.class" tofile="${build}/langtool.class" overwrite="true" />
+		<copy file="${rhino.jar}" tofile="${build}/langtool.jar" overwrite="true" />
+	</target>
+
+	<target name="jar" depends="copy" description="update the jar">
+		<!-- Put everything in ${build} into a jar file -->
+		<jar jarfile="${build}/langtool.jar" update="true">
+			<fileset dir="${build}">
+				<include name="**/*.class" />
+			</fileset>
+			<manifest>
+				<attribute name="Main-Class" value="langtool" />
+			</manifest>
+		</jar>
+	</target>
+
+	<target name="exe" depends="jar">
+		<taskdef name="launch4j" classname="net.sf.launch4j.ant.Launch4jTask" classpath="${launch4j.dir}/launch4j.jar:${launch4j.dir}/lib/xstream.jar" />
+		<launch4j>
+			<config headerType="console" jar="${build}/langtool.jar" outfile="${build}/langtool.exe" errTitle="Langtool" chdir="." customProcName="true">
+				<singleInstance mutexName="net.sf.launch4j.example.ConsoleApp" />
+				<jre minVersion="1.4.0" />
+			</config>
+		</launch4j>
+	</target>
+
+	<target name="clean" description="clean up">
+		<copy file="${build}/langtool.exe" tofile="langtool.exe" overwrite="true" />
+		<copy file="${build}/langtool.jar" tofile="langtool.jar" overwrite="true" />
+		<delete dir="${build}" />
+		<delete file="${source.dir}/langtool.class" />
+		<delete file="${source.dir}/includes/cklangtool.class" />
+		<delete file="${source.dir}/includes/io.class" />
+	</target>
+	
+</project>
Index: /CKLangTool/trunk/_source/includes/cklangtool.js
===================================================================
--- /CKLangTool/trunk/_source/includes/cklangtool.js	(revision 3136)
+++ /CKLangTool/trunk/_source/includes/cklangtool.js	(revision 3136)
@@ -0,0 +1,594 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+importPackage( java.util.regex );
+
+var CKLANGTOOL =
+{
+	languageDir :"",
+	templateFile :"",
+	/**
+	 * Holds the content of en.js language file where strings are replaced with
+	 * special placeholders: #ckeditor_translation.placeholder.key#.
+	 */
+	template :""
+};
+
+( function()
+{
+	CKLANGTOOL.translator = function()
+	{
+		CKLANGTOOL.englishTranslation =
+		{};
+	};
+
+	/**
+	 * Language code of currently processed file (taken from
+	 * CKEDITOR.lang['code']).
+	 */
+	var languageCode;
+	var fileOverviewBlock;
+
+	/**
+	 * Check whether the javascript file is valid.
+	 */
+	function checkFile( file )
+	{
+		var compilerEnv = new CompilerEnvirons();
+		var errorReporter = compilerEnv.getErrorReporter();
+		var parser = new Parser( compilerEnv, errorReporter );
+
+		try
+		{
+			parser.parse( 'var CKEDITOR = { lang : {} }; ' + CKLANGTOOL.io.readFile( file ), null, 1 );
+			return false;
+		}
+		catch ( e )
+		{
+			throw ("Error in " + file.getAbsolutePath() + "\n" + "Line: " + e.lineNumber + "\nMessage: " + e.message);
+		}
+	}
+
+	/**
+	 * Load language file and return an object with the whole translation.
+	 */
+	function loadLanguageFile( file )
+	{
+		var translationCode = 'var CKEDITOR = { lang : {} }; ' + CKLANGTOOL.io.readFile( file );
+
+		var cx = Context.enter(), scope = cx.initStandardObjects();
+
+		cx.evaluateString( scope, translationCode, file.getName(), 1, null );
+
+		try
+		{
+			languageCode = '';
+
+			/*
+			 * Get the number of variables in parent scope.
+			 */
+			var size = 0;
+			for ( var i in scope )
+			{
+				size++;
+			}
+
+			/*
+			 * If there is more than one variable, then it's not a CKEDITOR language file.
+			 */
+			if ( size > 1 )
+			{
+				/**
+				 * Return the first variable from parent scope different than
+				 * CKEDITOR.
+				 */
+				for ( var i in scope )
+				{
+					if ( i != "CKEDITOR" )
+						return scope[ i ];
+				}
+			}
+			else
+			{
+				/*
+				 * Return the first entry from scope.CKEDITOR.lang object
+				 */
+				for ( var i in scope.CKEDITOR.lang )
+				{
+					languageCode = i;
+					return scope.CKEDITOR.lang[ i ];
+				}
+			}
+		}
+		catch ( e )
+		{
+			throw ("Language file is invalid (" + file.getAbsolutePath() + ")");
+		}
+	}
+
+	var regexLib =
+	{
+		inlineComment :Pattern.compile( "^\\s*\\/\\/" ),
+		missing :Pattern.compile( "\\/\\/\\s*MISSING", Pattern.CASE_INSENSITIVE ),
+		blockCommentStart :Pattern.compile( "\\/\\*" ),
+		blockCommentEnd :Pattern.compile( "\\*\\/" ),
+		entry :Pattern.compile( "^(\\s*)([a-z0-9][_a-z0-9]*)(\\s*:\\s*\\').*?(\\'.*)$", Pattern.CASE_INSENSITIVE ),
+		arrayEntry :Pattern.compile( "^(\\s*)([a-z0-9][_a-z0-9]*)(\\s*:\\s*\\[)(.*?)(\\].*)$", Pattern.CASE_INSENSITIVE ),
+		arrayItemEntry :Pattern.compile( "\\s*(?:'(.*?)'(?:\\s*,\\s*)?)" ),
+		arrayTranslationKey :Pattern.compile( "^(.*)\\[(\\d+)\\]$" ),
+		objectName :Pattern.compile( "^\\s*([a-z][_a-z0-9]*)\\s*:\\s*$", Pattern.CASE_INSENSITIVE ),
+		objectStart :Pattern.compile( "\\{" ),
+		objectEnd :Pattern.compile( "\\}" ),
+		fileOverview :Pattern.compile( " @fileOverview" ),
+		translation :Pattern.compile( "#ckeditor_translation[^#]*?#" ),
+		ckeditorLang :Pattern.compile( "(.*CKEDITOR\\.lang\\[).*?(\\]\\s*=.*)" )
+	};
+
+	/**
+	 * Returns an array with missing keys (already marked as //MISSING).
+	 */
+	function analyzeLanguageFile( file )
+	{
+		fileOverviewBlock = '/**\n* @fileOverview \n*/';
+
+		var key = "ckeditor_translation";
+		var out =
+		{};
+		var inBlockComment = false;
+		var blockComment = [];
+		var objectName, matcher, line, translationKey;
+		var lines = CKLANGTOOL.io.readFileIntoArray( file );
+
+		for ( var j = 0 ; j < lines.length ; j++ )
+		{
+			line = lines[ j ];
+			if ( !inBlockComment )
+			{
+				matcher = regexLib.inlineComment.matcher( line );
+				if ( matcher.find() )
+				{
+					continue;
+				}
+
+				matcher = regexLib.blockCommentStart.matcher( line );
+				if ( matcher.find() )
+				{
+					inBlockComment = true;
+					blockComment.push( line );
+					continue;
+				}
+
+				matcher = regexLib.objectName.matcher( line );
+				if ( matcher.find() )
+				{
+					objectName = matcher.group( 1 );
+					continue;
+				}
+
+				if ( objectName )
+				{
+					matcher = regexLib.objectStart.matcher( line );
+					/*
+					 * We have found an opening bracket, key -> key.objectName
+					 */
+					if ( matcher.find() )
+					{
+						key = key + "." + objectName;
+						continue;
+					}
+
+					matcher = regexLib.objectEnd.matcher( line );
+					/*
+					 * We have found a closing bracket, key.objectName -> key
+					 */
+					if ( matcher.find() )
+					{
+						key = key.slice( 0, key.lastIndexOf( "." ) );
+						continue;
+					}
+				}
+
+				/*
+				 * Get rid of all escaped quotes, we don't need the exact content at this stage, just the key
+				 */
+				matcher = regexLib.entry.matcher( line.replaceAll( "\\\\'", "" ) );
+				if ( matcher.find() && regexLib.missing.matcher( line ).find() )
+				{
+					translationKey = key + "." + matcher.group( 2 );
+					translationKey = translationKey.replace( /^ckeditor_translation\./, "" );
+					out[ translationKey ] = true;
+				}
+
+				/* 
+				 * Get rid of all escaped quotes, we don't need the exact content at this stage, just the key.
+				 */
+				matcher = regexLib.arrayEntry.matcher( line.replaceAll( "\\\\'", "" ) );
+				if ( matcher.find() && regexLib.missing.matcher( line ).find() )
+				{
+					translationKey = key + "." + matcher.group( 2 );
+					translationKey = translationKey.replace( /^ckeditor_translation\./, "" );
+					out[ translationKey ] = true;
+				}
+			}
+			else
+			{
+				blockComment.push( line );
+
+				matcher = regexLib.blockCommentEnd.matcher( line );
+				if ( matcher.find() )
+				{
+					inBlockComment = false;
+
+					matcher = regexLib.fileOverview.matcher( blockComment.join( "" ) );
+					if ( matcher.find() )
+					{
+						fileOverviewBlock = blockComment.join( "\n" );
+					}
+					blockComment = [];
+				}
+			}
+		}
+
+		return out;
+	}
+
+	/**
+	 * Creates template from the english language file.
+	 * 
+	 * All strings are replaced with placeholders:
+	 * #ckeditor_translation.translationKey#
+	 * 
+	 * There are also two special placeholders:
+	 * #ckeditor_translation.__languageCode# (language code)
+	 * 
+	 * #ckeditor_translation.__fileOverview# (the block comment with the file
+	 * description)
+	 */
+	function createTemplate( file )
+	{
+		var key = "ckeditor_translation";
+		var out = [];
+		var inBlockComment = false;
+		var blockComment = [];
+		var i, matcher, matchResult, objectName, string, line;
+		var arrayEntryItems, arrayEntryItemsMatcher, arrayEntryLineEnd, arrayEntryLine, arrayEntryKey;
+		var lines = CKLANGTOOL.io.readFileIntoArray( file );
+
+		for ( var j = 0 ; j < lines.length ; j++ )
+		{
+			line = lines[ j ];
+
+			if ( !inBlockComment )
+			{
+				matcher = regexLib.inlineComment.matcher( line );
+				if ( matcher.find() )
+				{
+					out.push( line );
+					continue;
+				}
+
+				matcher = regexLib.blockCommentStart.matcher( line );
+				if ( matcher.find() )
+				{
+					inBlockComment = true;
+					blockComment.push( line );
+					continue;
+				}
+
+				matcher = regexLib.objectName.matcher( line );
+				if ( matcher.find() )
+				{
+					objectName = matcher.group( 1 );
+					out.push( line );
+					continue;
+				}
+
+				if ( objectName )
+				{
+					matcher = regexLib.objectStart.matcher( line );
+					/*
+					 * We have found an opening bracket, key -> key.objectName
+					 */
+					if ( matcher.find() )
+					{
+						key = key + "." + objectName;
+						out.push( line );
+						continue;
+					}
+
+					matcher = regexLib.objectEnd.matcher( line );
+					/*
+					 * We have found a closing bracket, key.objectName -> key
+					 */
+					if ( matcher.find() )
+					{
+						key = key.slice( 0, key.lastIndexOf( "." ) );
+						out.push( line );
+						continue;
+					}
+				}
+
+				/* 
+				 * Find CKEDITOR.lang['en']
+				 */
+				matcher = regexLib.ckeditorLang.matcher( line );
+				if ( matcher.find() )
+				{
+					out.push( matcher.group( 1 ) + "'#ckeditor_translation.__languageCode#'" + matcher.group( 2 ) );
+					continue;
+				}
+
+				/* 
+				 * Get rid of all escaped quotes, we don't need the exact content at this stage, just the key.
+				 * We're changing here the entry into the key.
+				 * So 'Upload' becomes '#ckeditor_translation.Upload#' in our temporary template.  
+				 */
+				matcher = regexLib.entry.matcher( line.replaceAll( "\\\\'", "" ) );
+				if ( matcher.find() )
+				{
+					out.push( matcher.group( 1 ) + matcher.group( 2 ) + matcher.group( 3 ) + "#" + key + "." + matcher.group( 2 ) + "#"
+							+ matcher.group( 4 ) );
+					continue;
+				}
+
+				/* 
+				 * Get rid of all escaped quotes, we don't need the exact content at this stage, just the key.
+				 * We're changing here the entry into the key.
+				 * So ['AM', 'PM'] becomes 
+				 * ['#ckeditor_translation.DateAmPm[0]#', '#ckeditor_translation.DateAmPm[1]#'] 
+				 * in our temporary template.  
+				 */
+				matcher = regexLib.arrayEntry.matcher( line.replaceAll( "\\\\'", "" ) );
+				if ( matcher.find() )
+				{
+					i = 0;
+
+					arrayEntryLine = matcher.group( 1 ) + matcher.group( 2 ) + matcher.group( 3 );
+					arrayEntryKey = matcher.group( 2 );
+					arrayEntryLineEnd = matcher.group( 5 );
+					arrayEntryItems = matcher.group( 4 );
+
+					arrayEntryItemsMatcher = regexLib.arrayItemEntry.matcher( arrayEntryItems );
+					while ( arrayEntryItemsMatcher.find() )
+					{
+						matchResult = arrayEntryItemsMatcher.toMatchResult();
+						if ( i > 0 )
+						{
+							arrayEntryLine += ", ";
+						}
+						arrayEntryLine += "'#" + key + "." + arrayEntryKey + "[" + i + "]" + "#'";
+						i++;
+					}
+					arrayEntryLine += arrayEntryLineEnd;
+					out.push( arrayEntryLine );
+					continue;
+				}
+
+				out.push( line );
+			}
+			else
+			{
+				blockComment.push( line );
+
+				matcher = regexLib.blockCommentEnd.matcher( line );
+				if ( matcher.find() )
+				{
+					inBlockComment = false;
+
+					matcher = regexLib.fileOverview.matcher( blockComment.join( "" ) );
+					/**
+					 * Add a placeholder for the fileOverview section.
+					 */
+					if ( matcher.find() )
+					{
+						out.push( "#ckeditor_translation.__fileOverview#" );
+					}
+					else
+					{
+						out.push( blockComment.join( "\n" ) );
+					}
+					blockComment = [];
+				}
+			}
+		}
+
+		/**
+		 * Uncomment this line to see the template.
+		 */
+		// CKLANGTOOL.io.saveFile( new File( CKLANGTOOL.languageDir, "template.txt" ), out.join( "\r\n" ), false );
+		return out.join( "\n" );
+	}
+
+	/**
+	 * Return translation[translationKey].
+	 * 
+	 * If translation contains dots, for example: common.textField then return
+	 * translation[common][textfield]
+	 */
+	function getTranslation( translation, translationKey )
+	{
+		var dotPos;
+		var result = translation;
+
+		/**
+		 * Special case, return the language code of processed file.
+		 */
+		if ( translationKey == "__languageCode" )
+			return languageCode;
+
+		/**
+		 * Special case, return the fileOverview block of processed file.
+		 */
+		if ( translationKey == "__fileOverview" )
+			return fileOverviewBlock;
+
+		while ( (dotPos = translationKey.indexOf( "." )) != -1 )
+		{
+			result = result[ translationKey.substring( 0, dotPos ) ];
+			if ( typeof (result) == "undefined" )
+			{
+				return false;
+			}
+			translationKey = translationKey.slice( dotPos + 1 );
+		}
+
+		/*
+		 * First make sure that the translationKey is not an array.
+		 */
+		var matcher = regexLib.arrayTranslationKey.matcher( translationKey );
+		if ( matcher.find() )
+		{
+			if ( typeof (result[ matcher.group( 1 ) ]) != "object" )
+			{
+				return false;
+			}
+			result = result[ matcher.group( 1 ) ][ matcher.group( 2 ) ];
+		}
+		else
+		{
+			result = result[ translationKey ];
+		}
+
+		if ( typeof (result) == "undefined" )
+		{
+			return false;
+		}
+
+		return escapeString( result );
+	}
+
+	/*
+	 * Escapes all characters so that a string could be properly saved to a file.
+	 */
+	function escapeString( string )
+	{
+		return string.replace( "\\", "\\\\" ).replace( "\r", "\\r" ).replace( "\n", "\\n" ).replace( "'", "\\'" ).replace( "\u200b",
+				"\\u200b" );
+	}
+
+	function processFile( file )
+	{
+		translation = loadLanguageFile( file );
+		var missingKeys = analyzeLanguageFile( file );
+		var matchResult, replacement, translationKey;
+		var string = CKLANGTOOL.template;
+		var matcher = regexLib.translation.matcher( string );
+		var found = 0, missing = 0;
+
+		while ( matcher.find() )
+		{
+			matchResult = matcher.toMatchResult();
+			/*
+			 * #ckeditor_translation.common.textField# -> common.textField
+			 */
+			translationKey = matchResult.group( 0 ).slice( 22, -1 );
+			replacement = getTranslation( translation, translationKey );
+
+			/*
+			 * common.textField[1] -> common.textField
+			 */
+			if ( replacement == false || missingKeys[ translationKey.replace( /\[\d+\]$/, "" ) ] )
+			{
+				/**
+				 * FoldersTitle : '#ckeditor_translation.FoldersTitle#', ->
+				 * FoldersTitle : '[MISSING_TRANSLATION]Folders',
+				 */
+				replacement = "[MISSING_TRANSLATION]" + getTranslation( CKLANGTOOL.englishTranslation, translationKey );
+				string = (string.substring( 0, matchResult.start() ) + replacement + string.substring( matchResult.end() ));
+
+				if ( translationKey.substring( 0, 2 ) != "__" )
+					missing++;
+			}
+			else
+			{
+				string = (string.substring( 0, matchResult.start() ) + replacement + string.substring( matchResult.end() ));
+
+				if ( translationKey.substring( 0, 2 ) != "__" )
+					found++;
+			}
+
+			matcher.reset( string );
+		}
+
+		/**
+		 * Loop through all lines, remove [MISSING_TRANSLATION] and add
+		 * //MISSING comment at the end of line (if necessary).
+		 */
+		var line, lines = string.split( "\n" );
+		for ( var i = 0 ; i < lines.length ; i++ )
+		{
+			line = lines[ i ];
+			if ( line.indexOf( "[MISSING_TRANSLATION]" ) != -1 )
+			{
+				if ( line.indexOf( "//" ) == -1 )
+				{
+					lines[ i ] = line.replace( /\[MISSING_TRANSLATION\]/g, '' ) + " // MISSING";
+				}
+				else
+				{
+					lines[ i ] = line.replace( "//", "// MISSING //" ).replace( /\[MISSING_TRANSLATION\]/g, '' );
+				}
+			}
+		}
+
+		CKLANGTOOL.io.saveFile( file, lines.join( "\r\n" ), false );
+
+		var result =
+		{
+			found :found,
+			missing :missing
+		};
+
+		return result;
+	}
+
+	function padRight( value, length )
+	{
+		return value + Array( length - value.length() ).join( " " );
+	}
+
+	CKLANGTOOL.translator.prototype =
+	{
+		run : function()
+		{
+			CKLANGTOOL.template = createTemplate( CKLANGTOOL.templateFile );
+			CKLANGTOOL.englishTranslation = loadLanguageFile( CKLANGTOOL.templateFile );
+
+			var children = CKLANGTOOL.languageDir.list();
+			var errors, file, status = [];
+			var foundFiles = false;
+
+			for ( var i = 0 ; i < children.length ; i++ )
+			{
+				if ( children[ i ] == 'en.js' )
+					continue;
+
+				if ( CKLANGTOOL.io.getExtension( children[ i ] ) != "js" )
+					continue;
+
+				file = new File( CKLANGTOOL.languageDir, children[ i ] );
+				if ( file.isFile() )
+				{
+					print( "Processing " + file.getAbsolutePath() );
+					result = processFile( file );
+					checkFile( file );
+
+					status.push( padRight( children[ i ], 12 ) + "Found: " + result.found + " Missing: " + result.missing );
+					foundFiles = true;
+				}
+			}
+
+			if ( !foundFiles )
+			{
+				print( "WARNING: language files not found." );
+			}
+
+			var header = "Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.\r\nFor licensing, see LICENSE.html or http://ckeditor.com/license\r\n\r\n";
+
+			CKLANGTOOL.io.saveFile( new File( CKLANGTOOL.languageDir, "_translationstatus.txt" ), header + status.join( "\r\n" ), false );
+			print( "Process completed." );
+		}
+	};
+})();
Index: /CKLangTool/trunk/_source/includes/io.js
===================================================================
--- /CKLangTool/trunk/_source/includes/io.js	(revision 3136)
+++ /CKLangTool/trunk/_source/includes/io.js	(revision 3136)
@@ -0,0 +1,118 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+importClass( java.io.BufferedReader );
+importClass( java.io.BufferedWriter );
+importClass( java.io.DataInputStream );
+importClass( java.io.File );
+importClass( java.io.FileInputStream );
+importClass( java.io.FileOutputStream );
+importClass( java.io.InputStreamReader );
+importClass( java.io.OutputStreamWriter );
+importClass( java.lang.StringBuffer );
+
+( function()
+{
+	CKLANGTOOL.io =
+	{
+		saveFile : function( file, text, includeBom )
+		{
+			try
+			{
+				var stream = new BufferedWriter( new OutputStreamWriter( new FileOutputStream( file ), "UTF-8" ) );
+				if ( includeBom )
+					stream.write( 65279 );
+				stream.write( text );
+				stream.flush();
+				stream.close();
+			}
+			catch ( e )
+			{
+				throw "Cannot save file:\n Path: " + file.getCanonicalPath() + "\n Eception details: " + e.message;
+			}
+		},
+
+		/**
+		 * Reads file and returns file contents without initial UTF-8 Byte Order
+		 * Mark
+		 */
+		readFile : function( file )
+		{
+			var buffer = new StringBuffer();
+			var chars = new Packages.java.lang.reflect.Array.newInstance( java.lang.Character.TYPE, 8192 );
+			var count;
+
+			try
+			{
+				var inStream = new InputStreamReader( new FileInputStream( file ), "UTF-8" );
+
+				while ( (count = inStream.read( chars, 0, 8192 )) != -1 )
+				{
+					if ( count > 0 )
+					{
+						buffer.append( chars, 0, count );
+					}
+				}
+			}
+			catch ( e )
+			{
+				throw 'An I/O error occurred while reading the ' + file.getCanonicalPath() + ' file.';
+			}
+			finally
+			{
+				inStream.close();
+			}
+
+			/* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 */
+			if ( buffer.length() && buffer.charAt( 0 ) == 65279 )
+				buffer.deleteCharAt( 0 );
+
+			return String( buffer.toString() );
+		},
+
+		readFileIntoArray : function( file )
+		{
+			var out = [];
+
+			try
+			{
+				var fstream = new FileInputStream( file );
+				var dis = new DataInputStream( fstream );
+				var br = new BufferedReader( new InputStreamReader( dis, "UTF-8" ) );
+				var line;
+
+				while ( (line = br.readLine()) != null )
+				{
+					out.push( line );
+				}
+			}
+			catch ( e )
+			{
+				throw 'An I/O error occurred while reading the ' + file.getCanonicalPath() + ' file.';
+			}
+			finally
+			{
+				dis.close();
+			}
+
+			return out;
+		},
+
+		getFileName : function( filePath )
+		{
+			var file = new File( filePath );
+			return file.getName();
+		},
+
+		getExtension : function( fileName )
+		{
+			var pos = fileName.lastIndexOf( "." );
+			if ( pos == -1 )
+				return "";
+			else
+				return String( fileName.substring( pos + 1 ).toLowerCase() );
+		}
+	};
+})();
Index: /CKLangTool/trunk/_source/langtool.js
===================================================================
--- /CKLangTool/trunk/_source/langtool.js	(revision 3136)
+++ /CKLangTool/trunk/_source/langtool.js	(revision 3136)
@@ -0,0 +1,78 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+ */
+
+importPackage( org.mozilla.javascript );
+importClass( java.lang.System );
+importClass( java.io.File );
+
+/*
+ * Check if we're running the compiled version of this script. If yes, the
+ * langtool class should be available.
+ */
+var isCompiled = true;
+var command = "java -cp js.jar org.mozilla.javascript.tools.shell.Main langtool.js";
+
+try
+{
+	java.lang.Class.forName( "langtool" );
+}
+catch ( e )
+{
+	isCompiled = false;
+}
+
+if ( isCompiled )
+{
+	var quit = function()
+	{
+		System.exit( 0 );
+	};
+
+	loadClass( "cklangtool" );
+	loadClass( "io" );
+
+	var resource = JavaAdapter( org.mozilla.javascript.Parser )["class"].getResource( "/org/mozilla/javascript" ).toString();
+	if ( resource.indexOf( ".exe" ) )
+		command = "langtool.exe";
+	else
+		command = "java -jar langtool.jar";
+}
+else
+{
+	load( "includes/cklangtool.js" );
+	load( "includes/io.js" );
+}
+
+if ( !arguments[0] )
+	error( 'Usage: ' + command + ' [lang_dir]' );
+
+CKLANGTOOL.languageDir = new File( arguments[0] );
+CKLANGTOOL.templateFile = new File( arguments[0], 'en.js' );
+
+if ( !CKLANGTOOL.templateFile.exists() )
+{
+	error( 'ERROR: The english language file "en.js" was not found (' + CKLANGTOOL.templateFile.getAbsolutePath() + ')' );
+}
+
+function error( msg )
+{
+	print( msg );
+	print( '' );
+	quit();
+}
+
+( function()
+{
+	try
+	{
+		var translator = new CKLANGTOOL.translator();
+		translator.run();
+	}
+	catch ( e )
+	{
+		print( "" );
+		error( e );
+	}
+} )();
