Index: wp-includes/post.php
===================================================================
--- wp-includes/post.php	(revision 21089)
+++ wp-includes/post.php	(working copy)
@@ -2850,8 +2850,8 @@
 		if ( $post_name_check || in_array( $slug, $feeds ) || apply_filters( 'wp_unique_post_slug_is_bad_attachment_slug', false, $slug ) ) {
 			$suffix = 2;
 			do {
-				$alt_post_name = substr ($slug, 0, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
-				$post_name_check = $wpdb->get_var( $wpdb->prepare($check_sql, $alt_post_name, $post_ID ) );
+				$alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
+				$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_ID ) );
 				$suffix++;
 			} while ( $post_name_check );
 			$slug = $alt_post_name;
@@ -2865,7 +2865,7 @@
 		if ( $post_name_check || in_array( $slug, $feeds ) || preg_match( "@^($wp_rewrite->pagination_base)?\d+$@", $slug )  || apply_filters( 'wp_unique_post_slug_is_bad_hierarchical_slug', false, $slug, $post_type, $post_parent ) ) {
 			$suffix = 2;
 			do {
-				$alt_post_name = substr( $slug, 0, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
+				$alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
 				$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_ID, $post_parent ) );
 				$suffix++;
 			} while ( $post_name_check );
@@ -2879,7 +2879,7 @@
 		if ( $post_name_check || in_array( $slug, $feeds ) || apply_filters( 'wp_unique_post_slug_is_bad_flat_slug', false, $slug, $post_type ) ) {
 			$suffix = 2;
 			do {
-				$alt_post_name = substr( $slug, 0, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
+				$alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
 				$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $post_ID ) );
 				$suffix++;
 			} while ( $post_name_check );
@@ -2891,6 +2891,36 @@
 }
 
 /**
+ * Truncate a post slug with UTF-8 characters.
+ *
+ * @since 3.5.0
+ * @access private
+ *
+ * @param string $slug The slug to truncate.
+ * @param int $length Max length of the slug.
+ * @return string The truncated slug.
+ */
+function _truncate_post_slug( $slug, $length = 200 ) {
+	while ( strlen( $slug ) > $length ) {
+		$raw_slug = urldecode( $slug );
+
+		if ( preg_match( '/[\xc2-\xdf][\x80-\xbf]$/', $raw_slug ) )
+			$last_char_length = 6;
+		elseif ( preg_match( '/[\xe0][\xa0-\xbf][\x80-\xbf]$/', $raw_slug )
+			|| preg_match( '/[\xe1-\xec][\x80-\xbf][\x80-\xbf]$/', $raw_slug )
+			|| preg_match( '/[\xed-\xef][\x80-\x9f][\x80-\xbf]$/', $raw_slug )
+			|| preg_match( '/[\xee-\xef][\x80-\xbf][\x80-\xbf]$/', $raw_slug ) )
+			$last_char_length = 9;
+		else
+			$last_char_length = 1;
+
+		$slug = trim( substr( $slug, 0, -$last_char_length ), '-' );
+	}
+
+	return $slug;
+}
+
+/**
  * Adds tags to a post.
  *
  * @uses wp_set_post_tags() Same first two parameters, but the last parameter is always set to true.
