Index: tools/i18n/makepot.php
===================================================================
--- tools/i18n/makepot.php	(revision 35714)
+++ tools/i18n/makepot.php	(working copy)
@@ -26,6 +26,10 @@
 		'glotpress',
 		'rosetta',
 		'wporg-bb-forums',
+		'wporg-themes',
+		'wporg-plugins',
+		'wporg-forums',
+		'wordcamporg',
 	);

 	var $rules = array(
@@ -137,6 +141,16 @@
 			'copyright-holder' => 'WordPress',
 			'package-name' => 'WordPress.org International Forums',
 		),
+		'wporg' => array(
+			'description' => 'WordPress.org',
+			'copyright-holder' => 'WordPress',
+			'package-name' => 'WordPress.org',
+		),
+		'wordcamporg' => array(
+			'description' => 'WordCamp.org',
+			'copyright-holder' => 'WordPress',
+			'package-name' => 'WordCamp.org',
+		),
 		'rosetta' => array(
 			'description' => 'Rosetta (.wordpress.org locale sites)',
 			'copyright-holder' => 'WordPress',
@@ -408,14 +422,6 @@
 		return $this->xgettext('wp', $dir, $output, $placeholders);
 	}

-
-	function bb($dir, $output) {
-		$placeholders = array();
-		$output = is_null($output)? 'bbpress.pot' : $output;
-		return $this->xgettext('bb', $dir, $output, $placeholders);
-
-	}
-
 	function get_first_lines($filename, $lines = 30) {
 		$extf = fopen($filename, 'r');
 		if (!$extf) return false;
@@ -428,17 +434,39 @@
 			}
 			$first_lines .= $line;
 		}
+
+		// PHP will close file handle, but we are good citizens.
+		fclose( $extf );
+
+		// Make sure we catch CR-only line endings.
+		$first_lines = str_replace( "\r", "\n", $first_lines );
+
 		return $first_lines;
 	}

-
 	function get_addon_header($header, &$source) {
-		if (preg_match('|'.$header.':(.*)$|mi', $source, $matches))
-			return trim($matches[1]);
-		else
+		/*
+		 * A few things this needs to handle:
+		 * - 'Header: Value\n'
+		 * - '// Header: Value'
+		 * - '/* Header: Value * /'
+		 * - '<?php // Header: Value ?>'
+		 * - '<?php /* Header: Value * / $foo='bar'; ?>'
+		 */
+		if ( preg_match( '/^(?:[ \t]*<\?php)?[ \t\/*#@]*' . preg_quote( $header, '/' ) . ':(.*)$/mi', $source, $matches ) ) {
+			return $this->_cleanup_header_comment( $matches[1] );
+		} else {
 			return false;
+		}
 	}

+	/**
+	 * Removes any trailing closing comment / PHP tags from the header value
+	 */
+	function _cleanup_header_comment( $str ) {
+		return trim( preg_replace( '/\s*(?:\*\/|\?>).*/', '', $str ) );
+	}
+
 	function generic($dir, $output) {
 		$output = is_null($output)? "generic.pot" : $output;
 		return $this->xgettext('generic', $dir, $output, array());
@@ -455,7 +483,12 @@
 		return $slug;
 	}

-	function wp_plugin($dir, $output, $slug = null) {
+	function wp_plugin( $dir, $output, $slug = null, $args = array() ) {
+		$defaults = array(
+			'excludes' => array(),
+			'includes' => array(),
+		);
+		$args = array_merge( $defaults, $args );
 		$placeholders = array();
 		// guess plugin slug
 		if (is_null($slug)) {
@@ -506,7 +539,7 @@
 		$placeholders['slug'] = $slug;

 		$output = is_null($output)? "$slug.pot" : $output;
-		$res = $this->xgettext('wp-plugin', $dir, $output, $placeholders);
+		$res = $this->xgettext( 'wp-plugin', $dir, $output, $placeholders, $args['excludes'], $args['includes'] );
 		if (!$res) return false;
 		$potextmeta = new PotExtMeta;
 		$res = $potextmeta->append($main_file, $output);
@@ -571,11 +604,28 @@
 		return $res;
 	}

-	function bp($dir, $output) {
-		$output = is_null($output)? "buddypress.pot" : $output;
-		return $this->xgettext('bp', $dir, $output, array(), array('bp-forums/bbpress/.*'));
+	function bp( $dir, $output ) {
+		$output = is_null( $output ) ? 'buddypress.pot' : $output;
+		$args = array(
+			'excludes' => array( 'bp-forums/bbpress/.*', 'tests/.*' ),
+		);
+
+		// BuddyPress 2.1+
+		if ( is_dir( "$dir/src" ) ) {
+			$args = array(
+				'includes' => array( 'src/.*' ),
+				'excludes' => array( 'src/bp-forums/bbpress/.*' ),
+			);
+		}
+
+		return $this->wp_plugin( $dir, $output, 'buddypress', $args );
 	}

+	function bb( $dir, $output ) {
+		$output = is_null( $output ) ? 'bbpress.pot' : $output;
+		return $this->wp_plugin( $dir, $output, 'bbpress' );
+	}
+
 	function glotpress( $dir, $output ) {
 		$output = is_null( $output ) ? "glotpress.pot" : $output;
 		return $this->xgettext( 'glotpress', $dir, $output );
@@ -586,9 +636,39 @@
 		return $this->xgettext( 'wporg-bb-forums', $dir, $output, array(), array(
 			'bb-plugins/elfakismet/.*',
 			'bb-plugins/support-forum/.*',
+			'themes/.*',
 		) );
 	}

+	function wporg_themes( $dir, $output ) {
+		$output = is_null( $output ) ? 'wporg-themes.pot' : $output;
+		return $this->xgettext( 'wporg', $dir, $output, array(), array(), array(
+			'plugins/theme-directory/.*',
+			'themes/pub/wporg-themes/.*'
+		) );
+	}
+
+	function wporg_plugins( $dir, $output ) {
+		$output = is_null( $output ) ? 'wporg-plugins.pot' : $output;
+		return $this->xgettext( 'wporg', $dir, $output, array(), array(), array(
+			'.*\.php',
+		) );
+	}
+
+	function wporg_forums( $dir, $output ) {
+		$output = is_null( $output ) ? 'wporg-forums.pot' : $output;
+		return $this->xgettext( 'wporg', $dir, $output, array(), array(), array(
+			'.*\.php',
+		) );
+	}
+
+	function wordcamporg( $dir, $output ) {
+		$output = is_null( $output ) ? 'wordcamporg.pot' : $output;
+		return $this->xgettext( 'wordcamporg', $dir, $output, array(), array(), array(
+			'.*\.php',
+		) );
+	}
+
 	function rosetta( $dir, $output ) {
 		$output = is_null( $output )? 'rosetta.pot' : $output;
 		return $this->xgettext( 'rosetta', $dir, $output, array(), array(), array(
