diff --git a/CHANGES b/CHANGES
new file mode 100644
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,5 @@
+Version 0.2.5 - released 2009-02-05; changes from 0.2.4
+
+ * Fix bug in percent-encoding UTF-8 content. 
+   (Bug reported by Ilya Kuznetsov; thanks.)
+
diff --git a/Web/Codec/Percent.hs b/Web/Codec/Percent.hs
--- a/Web/Codec/Percent.hs
+++ b/Web/Codec/Percent.hs
@@ -14,7 +14,7 @@
 -}
 module Web.Codec.Percent where
 
-import Data.Char ( chr, isAlphaNum )
+import Data.Char ( chr, isAlphaNum, isAscii )
 import Numeric   ( readHex, showHex )
 
 getEncodedString :: String -> String
@@ -33,7 +33,7 @@
 
 getEncodedChar :: Char -> Maybe String
 getEncodedChar x
- | isAlphaNum x || 
+ | (isAlphaNum x && isAscii x) || 
    x `elem` "-_.~" = Nothing
  | xi < 0xff       = Just ('%':showHex (xi `div` 16) (showHex (xi `mod` 16) ""))
  | otherwise       = -- ToDo: import utf8 lib
diff --git a/Web/Codec/URLEncoder.hs b/Web/Codec/URLEncoder.hs
--- a/Web/Codec/URLEncoder.hs
+++ b/Web/Codec/URLEncoder.hs
@@ -6,13 +6,25 @@
 module Web.Codec.URLEncoder 
        ( encodeString
        , decodeString
+
+       , isUTF8Encoded
+       , utf8Encode
        ) where
 
 import qualified Codec.Binary.UTF8.String as UTF8 ( encodeString )
 import Web.Codec.Percent ( getEncodedChar, getDecodedChar )
 
+-- for isUTF8Encoded
+import Data.Bits
+import Data.Word ( Word32 )
+
+utf8Encode :: String -> String
+utf8Encode str
+ | isUTF8Encoded str = str
+ | otherwise         = UTF8.encodeString str
+
 encodeString :: String -> String
-encodeString str = go (UTF8.encodeString str)
+encodeString str = go (utf8Encode str)
  where
   go "" = ""
   go (' ':xs) = '+':go xs
@@ -31,3 +43,52 @@
   case getDecodedChar ls of
     Nothing -> x : decodeString xs
     Just (ch,xs1) -> ch : decodeString xs1
+
+
+-- | @isUTF8Encoded str@ tries to recognize input string as being in UTF-8 form.
+-- Will soon migrate to @utf8-string@.
+isUTF8Encoded :: String -> Bool
+isUTF8Encoded [] = True
+isUTF8Encoded (x:xs) = 
+  case ox of
+    _ | ox < 0x80  -> isUTF8Encoded xs
+      | ox > 0xff  -> False
+      | ox < 0xc0  -> False
+      | ox < 0xe0  -> check1
+      | ox < 0xf0  -> check_byte 2 0xf 0
+      | ox < 0xf8  -> check_byte 3 0x7  0x10000
+      | ox < 0xfc  -> check_byte 4 0x3  0x200000
+      | ox < 0xfe  -> check_byte 5 0x1  0x4000000
+      | otherwise  -> False
+ where
+   ox = toW32 x
+   
+   toW32 :: Char -> Word32
+   toW32 ch = fromIntegral (fromEnum ch)
+
+   check1 = 
+    case xs of
+     [] -> False
+     c1 : ds 
+      | oc .&. 0xc0 /= 0x80 || d < 0x000080 -> False
+      | otherwise -> isUTF8Encoded ds
+      where
+       oc = toW32 c1
+       d = ((ox .&. 0x1f) `shiftL` 6) .|.  (oc .&. 0x3f)
+
+   check_byte :: Int -> Word32 -> Word32 -> Bool
+   check_byte i mask overlong = aux i xs (ox .&. mask)
+      where
+        aux 0 rs acc
+         | overlong <= acc && 
+	   acc <= 0x10ffff &&
+           (acc < 0xd800 || 0xdfff < acc) &&
+           (acc < 0xfffe || 0xffff < acc) = isUTF8Encoded rs
+         | otherwise = False
+
+        aux n (r:rs) acc
+         | toW32 r .&. 0xc0 == 0x80 = 
+	    aux (n-1) rs  (acc `shiftL` 6 .|. (toW32 r .&. 0x3f))
+
+        aux _ _  _ = False
+
diff --git a/hs-twitter.cabal b/hs-twitter.cabal
--- a/hs-twitter.cabal
+++ b/hs-twitter.cabal
@@ -1,5 +1,5 @@
 name: hs-twitter
-version: 0.2.4
+version: 0.2.5
 synopsis: Haskell binding to the Twitter API
 description:
    The hs-twitter API binding lets you access twitter.com's
@@ -16,7 +16,7 @@
 maintainer: Sigbjorn Finne <sof@forkio.com>
 cabal-version:  >= 1.2
 build-type: Simple
-extra-source-files: README
+extra-source-files: README CHANGES
 
 library
  Exposed-modules: Web.Twitter,
