Index: /lang/php/ZendFramework_ext/library/Twk/Filter/Kana.php
===================================================================
--- /lang/php/ZendFramework_ext/library/Twk/Filter/Kana.php (revision 3360)
+++ /lang/php/ZendFramework_ext/library/Twk/Filter/Kana.php (revision 3360)
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Requires mb_string environment
+ * Will only work with UTF-8 internal encoding.
+ */
+//require_once 'Zend/Filter/Interface.php';
+
+/**
+ * convert filter like mb_convert_kana does
+ */
+class Twk_Filter_Kana implements Zend_Filter_Interface
+{
+	/** alphabet a to z and A to Z */
+	const CONVERT_OPTION_ALPHA_FULL_TO_HALF = 'r';
+	const CONVERT_OPTION_ALPHA_HALF_TO_FULL = 'R';
+	const CONVERT_OPTION_NUMBER_FULL_TO_HALF = 'n';
+	const CONVERT_OPTION_NUMBER_HALF_TO_FULL = 'N';
+	/** Almost all ascii (NOT same as rn or RN).  U+0021 to U+007E except U+0022(") U+0027(') U+005C(\) and U+007E(~) */
+	const CONVERT_OPTION_ALNUM_FULL_TO_HALF = 'a';
+	const CONVERT_OPTION_ALNUM_HALF_TO_FULL = 'A';
+	/** U+0020 */
+	const CONVERT_OPTION_SPACE_FULL_TO_HALF = 's';
+	const CONVERT_OPTION_SPACE_HALF_TO_FULL = 'S';
+	const CONVERT_OPTION_KATAKANA_FULL_TO_HALF = 'k';
+	const CONVERT_OPTION_KATAKANA_HALF_TO_FULL = 'K';
+	const CONVERT_OPTION_FULL_HIRAGANA_TO_HALF_KATAKANA = 'h';
+	const CONVERT_OPTION_HALF_KATAKANA_TO_FULL_HIRAGANA = 'H';
+	const CONVERT_OPTION_FULL_HIRAGANA_TO_FULL_KATAKANA = 'c';
+	const CONVERT_OPTION_FULL_KATAKANA_TO_FULL_HIRAGANA = 'C';
+	/** use with 'K', 'H' */
+	const CONVERT_OPTION_VOICED_NOTATION_TO_SINGLE_CHAR = 'V';
+
+	/** 
+	 * U+0021 to U+007E except U+0022(") U+0027(') U+005C(\) and U+007E(~) 
+	 * Implemented with mb_ereg_replace
+	 */
+	const CONVERT_OPTION_SPECIAL_CHARACTERS_FULL_TO_HALF = 'p';
+	const CONVERT_OPTION_SPECIAL_CHARACTERS_HALF_TO_FULL = 'P';
+	
+	/** same as mb_convert_kana default option */
+	const CONVERT_OPTION_DEFAULT = 'KV';
+	/** default plus ascii normalization */
+	const CONVERT_OPTION_NORMALIZE = 'KVasp';
+
+	/**
+	 * Fixed array
+	 * XXX embedding DBCS in the source would be a bad way
+	 * @var $_specialCharactersTable array
+	 */
+	private static $_specialCharactersTable = array(
+    	"'" => "’",
+    	'"' => '”',
+    	'\\' => '￥',
+    	'~' => '～',
+	);
+	
+	/** @var $_convertOption String */
+	private $_convertOption;
+	/** @var $_option String */
+	private $_encoding;
+	
+	public function __construct($convertOption = self::CONVERT_OPTION_DEFAULT, $encoding = null)
+	{
+		$this->_convertOption = $convertOption;
+		$this->_encoding = $encoding ? $encoding : mb_internal_encoding();
+	}
+	
+    /**
+     * Returns the result of filtering $value
+     *
+     * @param  mixed $value
+     * @throws Zend_Filter_Exception If filtering $value is impossible
+     * @return mixed
+     */
+    public function filter($value)
+    {
+    	$option = $this->_convertOption;
+    	
+    	// special chars full to half
+    	if (strpos($option, self::CONVERT_OPTION_SPECIAL_CHARACTERS_FULL_TO_HALF) !== FALSE)
+    	{
+    		foreach (self::$_specialCharactersTable as $half => $full)
+    			$value = mb_ereg_replace($full, $half, $value);
+	 		
+	    	$option = strtr($option, array(self::CONVERT_OPTION_SPECIAL_CHARACTERS_FULL_TO_HALF => ''));
+	   	}
+	   	// special chars half to full
+    	if (strpos($option, self::CONVERT_OPTION_SPECIAL_CHARACTERS_HALF_TO_FULL) !== FALSE)
+    	{
+    		foreach (self::$_specialCharactersTable as $half => $full)
+	    		$value = mb_ereg_replace($half, $full, $value);
+       	
+    		$option = strtr($option, array(self::CONVERT_OPTION_SPECIAL_CHARACTERS_HALF_TO_FULL => ''));
+       	}
+    	
+    	return mb_convert_kana($value, $option, $this->_encoding);
+    }
+}
