Index: includes/unicode.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/unicode.inc,v
retrieving revision 1.46
diff -u -p -r1.46 unicode.inc
--- includes/unicode.inc	29 Jul 2010 00:38:24 -0000	1.46
+++ includes/unicode.inc	1 Aug 2010 17:14:52 -0000
@@ -586,6 +586,36 @@ function drupal_ucfirst($text) {
 }
 
 /**
+ * Capitalizes the first letter of each word in a UTF-8 string.
+ *
+ * @param $text
+ *   The text that will be converted.
+ *
+ * @return
+ *   The input $text with each word capitalized.
+ *
+ * @ingroup php_wrappers
+ */
+function drupal_ucwords($text) {
+  $regex = '/(^|[' . PREG_CLASS_UNICODE_WORD_BOUNDARY . '])([^' . PREG_CLASS_UNICODE_WORD_BOUNDARY . '])/u';
+  return preg_replace_callback($regex, '_drupal_ucwords_callback', $text);
+}
+
+/**
+ * Helper callback that is used to capitalize the first character of a word.
+ *
+ * @param $matches
+ *   An array of matched characters. Elements 0, 1, and 2 of $matches must be
+ *   the full match, the word boundary , and the first character of the word.
+ *
+ * @return
+ *   Our matched word boundary and uppercase of the first character.
+ */
+function _drupal_ucwords_callback($matches) {
+  return $matches[1] . drupal_strtoupper($matches[2]);
+}
+
+/**
  * Cut off a piece of a string based on character indices and counts. Follows
  * the same behavior as PHP's own substr() function.
  *
Index: modules/simpletest/tests/unicode.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/unicode.test,v
retrieving revision 1.6
diff -u -p -r1.6 unicode.test
--- modules/simpletest/tests/unicode.test	10 Jun 2010 15:20:48 -0000	1.6
+++ modules/simpletest/tests/unicode.test	1 Aug 2010 17:14:52 -0000
@@ -46,6 +46,7 @@ class UnicodeUnitTest extends DrupalWebT
     $this->helperTestStrToLower();
     $this->helperTestStrToUpper();
     $this->helperTestUcFirst();
+    $this->helperTestUcWords();
     $this->helperTestStrLen();
     $this->helperTestSubStr();
     $this->helperTestTruncate();
@@ -66,6 +67,7 @@ class UnicodeUnitTest extends DrupalWebT
     $this->helperTestStrToLower();
     $this->helperTestStrToUpper();
     $this->helperTestUcFirst();
+    $this->helperTestUcWords();
     $this->helperTestStrLen();
     $this->helperTestSubStr();
     $this->helperTestTruncate();
@@ -115,6 +117,24 @@ class UnicodeUnitTest extends DrupalWebT
     }
   }
 
+  function helperTestUcWords() {
+    $testcase = array(
+      'tHe QUIcK bRoWn' => 'THe QUIcK BRoWn',
+      'françAIS' => 'FrançAIS',
+      'über' => 'Über',
+      'åwesome' => 'Åwesome',
+      // Make sure we don't mangle extra spaces.
+      'frànçAIS is  über-åwesome' => 'FrànçAIS Is  Über-Åwesome',
+    );
+    if ($this->extendedMode) {
+      $testcase['σion'] = 'Σion';
+    }
+
+    foreach ($testcase as $input => $output) {
+      $this->assertEqual(drupal_ucwords($input), $output, t('%input is ucword-ed as %output', array('%input' => $input, '%output' => $output)));
+    }
+  }
+
   function helperTestStrLen() {
     $testcase = array(
       'tHe QUIcK bRoWn' => 15,
