Index: includes/unicode.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/unicode.inc,v
retrieving revision 1.45
diff -u -p -r1.45 unicode.inc
--- includes/unicode.inc	16 Jul 2010 11:17:25 -0000	1.45
+++ includes/unicode.inc	19 Jul 2010 17:45:38 -0000
@@ -569,6 +569,27 @@ function drupal_ucfirst($text) {
 }
 
 /**
+ * Capitalize the first letter of each word in a UTF-8 string.
+ *
+ * @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);
+}
+
+/**
+ * Uppercase matched strings.
+ * 
+ * @see drupal_ucwords().
+ * @param $matches
+ *   An array of matched characters.
+ */
+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	19 Jul 2010 17:45:39 -0000
@@ -114,6 +114,24 @@ class UnicodeUnitTest extends DrupalWebT
       $this->assertEqual(drupal_ucfirst($input), $output, t('%input is ucfirst-ed as %output', array('%input' => $input, '%output' => $output)));
     }
   }
+  
+  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 ucfirst-ed as %output', array('%input' => $input, '%output' => $output)));
+    }
+  }
 
   function helperTestStrLen() {
     $testcase = array(
