Index: intltool-extract.in
===================================================================
--- intltool-extract.in	(revision 745)
+++ intltool-extract.in	(working copy)
@@ -47,6 +47,7 @@
 my $UPDATE_ARG  = "0";
 my $QUIET_ARG   = "0";
 my $SRCDIR_ARG	= ".";
+my $NOMSGCTXT_ARG = "0";
 
 my $FILE;
 my $OUTFILE;
@@ -76,6 +77,7 @@
             "update"     => \$UPDATE_ARG,
 	    "quiet|q"    => \$QUIET_ARG,
 	    "srcdir=s"	 => \$SRCDIR_ARG,
+	    "nomsgctxt"  => \$NOMSGCTXT_ARG,            
             ) or &error;
 
 &split_on_argument;
@@ -445,6 +447,11 @@
                 $lookup =~ s/^\s+//s;
                 $lookup =~ s/\s+$//s;
             }
+            if (exists $attrs->{"msgctxt"}) {
+                my $context = entity_decode ($attrs->{"msgctxt"});
+                $context =~ s/^["'](.*)["']/$1/;
+                $lookup = "$context\004$lookup";
+            }
 
 	    if ($lookup && $translate != 2) {
                 $comments{$lookup} = $XMLCOMMENT if $XMLCOMMENT;
@@ -833,6 +840,7 @@
     for my $message (@msgids)
     {
 	my $offsetlines = 1;
+	my $context = undef;
 	$offsetlines++ if $message =~ /%/;
 	if (defined ($comments{$message}))
 	{
@@ -847,12 +855,30 @@
                 if defined $comments{$message};
    	print OUT "/* xgettext:no-c-format */\n" if $message =~ /%/;
         
+    	if ($message =~ /(.*)\004(.*)/) {
+    	    $context = $1;
+    	    $message = $2;
+    	}
     	my @lines = split (/\n/, $message, -1);
     	for (my $n = 0; $n < @lines; $n++)
 	{
             if ($n == 0)
             {
- 		print OUT "char *s = N_(\""; 
+                if (defined $context)
+                {
+                     if ($NOMSGCTXT_ARG)
+                     {
+                          print OUT "char *s = N_(\"", $context, "|"; 
+                     }
+                     else
+                     {
+ 		          print OUT "char *s = C_(\"", $context, "\", \""; 
+                     }
+                }
+                else
+                {
+ 		     print OUT "char *s = N_(\""; 
+                }
             }
             else
             {  
Index: intltool-merge.in
===================================================================
--- intltool-merge.in	(revision 745)
+++ intltool-merge.in	(working copy)
@@ -441,6 +441,18 @@
     &create_cache;
 }
 
+sub add_translation
+{
+    my ($lang, $msgctxt, $msgid, $msgstr) = @_;
+
+    return if !($msgid && $msgstr);
+
+    if ($msgctxt) {
+	$msgid = "$msgctxt\004$msgid";
+    }
+    $translations{$lang, $msgid} = $msgstr;
+}
+
 sub create_translation_database
 {
     for my $lang (keys %po_files_by_lang) 
@@ -468,8 +480,10 @@
         }
 
 	my $nextfuzzy = 0;
+	my $inmsgctxt = 0;
 	my $inmsgid = 0;
 	my $inmsgstr = 0;
+	my $msgctxt = "";
 	my $msgid = "";
 	my $msgstr = "";
 
@@ -477,31 +491,52 @@
         {
 	    $nextfuzzy = 1 if /^#, fuzzy/;
        
+	    if (/^msgctxt "((\\.|[^\\]+)*)"/ ) 
+            {
+		if ($inmsgstr) {
+		    add_translation ($lang, $msgctxt, $msgid, $msgstr);
+		    $msgctxt = "";
+		    $msgid = "";
+		    $msgstr = "";
+		}
+
+		$msgctxt = unescape_po_string($1);
+		$inmsgctxt = 1;
+		$inmsgid = 0;
+		$inmsgstr = 0;
+	    }
+
 	    if (/^msgid "((\\.|[^\\]+)*)"/ ) 
             {
-		$translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr;
-		$msgid = "";
-		$msgstr = "";
+		if ($inmsgstr) {
+		    add_translation ($lang, $msgctxt, $msgid, $msgstr);
+		    $msgctxt = "";
+		    $msgid = "";
+		    $msgstr = "";
+		}
 
 		if ($nextfuzzy) {
 		    $inmsgid = 0;
+		    $nextfuzzy = 0;
 		} else {
 		    $msgid = unescape_po_string($1);
 		    $inmsgid = 1;
 		}
+		$inmsgctxt = 0;
 		$inmsgstr = 0;
-		$nextfuzzy = 0;
 	    }
 
 	    if (/^msgstr "((\\.|[^\\]+)*)"/) 
             {
 	        $msgstr = unescape_po_string($1);
 		$inmsgstr = 1;
+		$inmsgctxt = 0;
 		$inmsgid = 0;
 	    }
 
 	    if (/^"((\\.|[^\\]+)*)"/) 
             {
+	        $msgctxt .= unescape_po_string($1) if $inmsgctxt;
 	        $msgid .= unescape_po_string($1) if $inmsgid;
 	        $msgstr .= unescape_po_string($1) if $inmsgstr;
 	    }
@@ -814,16 +849,23 @@
 
 	print $fh "<$nodename", $outattr;
 	if ($translate) {
-	    $lookup = getXMLstring($content, $spacepreserve);
+	    $content = getXMLstring($content, $spacepreserve);
             if (!$spacepreserve) {
-                $lookup =~ s/^\s+//s;
-                $lookup =~ s/\s+$//s;
+                $content =~ s/^\s+//s;
+                $content =~ s/\s+$//s;
             }
+            if (exists $attrs->{"msgctxt"}) {
+                my $context = entity_decode ($attrs->{"msgctxt"});
+                $context =~ s/^["'](.*)["']/$1/;
+                $lookup = "$context\004$content";
+            } else {
+                $lookup = $content;
+            }
 
 	    if ($lookup || $translate == 2) {
                 my $translation = $translations{$language, $lookup} if isWellFormedXmlFragment($translations{$language, $lookup});
                 if ($MULTIPLE_OUTPUT && ($translation || $translate == 2)) {
-                    $translation = $lookup if (!$translation);
+                    $translation = $content if (!$translation);
                     print $fh " xml:lang=\"", $language, "\"" if $language;
                     print $fh ">";
                     if ($translate == 2) {
@@ -840,7 +882,7 @@
                     if ($translate == 2) {
                         translate_subnodes($fh, \@all, $language, 1, $spacepreserve);
                     } else {
-                        print $fh $lookup;
+                        print $fh $content;
                     }
                     print $fh "</$nodename>";
                 }
@@ -859,7 +901,7 @@
                         my $localattrs = getAttributeString($attrs, 1, $lang, \$translate);
                         my $translation = $translations{$lang, $lookup} if isWellFormedXmlFragment($translations{$lang, $lookup});
                         if ($translate && !$translation) {
-                            $translation = $lookup;
+                            $translation = $content;
                         }
 
                         if ($translation || $translate) {
Index: tests/cases/context.xml.in
===================================================================
--- tests/cases/context.xml.in	(revision 0)
+++ tests/cases/context.xml.in	(revision 0)
@@ -0,0 +1,17 @@
+<test>
+    <entry>
+	<_name>Foo</_name>
+    </entry>
+    <entry>
+	<!-- This is the comment on the first Bar -->
+	<_name msgctxt="1">Bar</_name>
+    </entry>
+    <entry>
+	<!-- This is the comment on the second Bar -->
+	<_name msgctxt="2">Bar</_name>
+    </entry>
+    <entry>
+	<!-- This is the comment on Baz -->
+	<_name>Baz</_name>
+    </entry>
+</test>
Index: tests/cases/fr.po
===================================================================
--- tests/cases/fr.po	(revision 745)
+++ tests/cases/fr.po	(working copy)
@@ -59,3 +59,21 @@
 #: cases/extract10.templates_:20
 msgid "Current month?"
 msgstr "Mois en cours ?"
+
+#: cases/context.xml.in.h:2
+msgctxt "1"
+msgid "Bar"
+msgstr "bar un"
+
+#: cases/context.xml.in.h:4
+msgctxt "2"
+msgid "Bar"
+msgstr "bar deux"
+
+#: cases/context.xml.in.h:6
+msgid "Baz"
+msgstr "le baz"
+
+#: cases/context.xml.in.h:7
+msgid "Foo"
+msgstr "le foo"
Index: tests/cases/az.po
===================================================================
--- tests/cases/az.po	(revision 745)
+++ tests/cases/az.po	(working copy)
@@ -26,3 +26,14 @@
 msgid "A cake mixer"
 msgstr "KÃ¶kÉ™ qarÄ±ÅŸdÄ±rÄ±cÄ±"
 
+#: cases/context.xml.in.h:1
+msgid "Bar"
+msgstr "(not used, because no msgctxt)"
+
+#: cases/context.xml.in.h:2
+msgid "Baz"
+msgstr "az-baz"
+
+#: cases/context.xml.in.h:3
+msgid "Foo"
+msgstr "az-foo"
Index: tests/results/context.xml
===================================================================
--- tests/results/context.xml	(revision 0)
+++ tests/results/context.xml	(revision 0)
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<test>
+    <entry>
+	<name>Foo</name>
+	<name xml:lang="az">az-foo</name>
+	<name xml:lang="fr">le foo</name>
+    </entry>
+    <entry>
+	
+	<name msgctxt="1">Bar</name>
+	<name xml:lang="fr" msgctxt="1">bar un</name>
+    </entry>
+    <entry>
+	
+	<name msgctxt="2">Bar</name>
+	<name xml:lang="fr" msgctxt="2">bar deux</name>
+    </entry>
+    <entry>
+	
+	<name>Baz</name>
+	<name xml:lang="az">az-baz</name>
+	<name xml:lang="fr">le baz</name>
+    </entry>
+</test>
\ No newline at end of file
Index: tests/results/context.xml.in.h
===================================================================
--- tests/results/context.xml.in.h	(revision 0)
+++ tests/results/context.xml.in.h	(revision 0)
@@ -0,0 +1,7 @@
+/*  This is the comment on the first Bar  */
+char *s = C_("1", "Bar");
+/*  This is the comment on the second Bar  */
+char *s = C_("2", "Bar");
+/*  This is the comment on Baz  */
+char *s = N_("Baz");
+char *s = N_("Foo");
Index: tests/selftest.pl.in
===================================================================
--- tests/selftest.pl.in	(revision 745)
+++ tests/selftest.pl.in	(working copy)
@@ -267,6 +267,16 @@
 system("$INTLTOOL_MERGE -x --quiet cases cases/$case.in cases/$case") == 0 or $failed = 1;
 check_merge_result($case);
 
+print "35. Extract messages from an XML file with msgctxts:                 ";
+$case = "context.xml.in";
+system("$INTLTOOL_EXTRACT --type=gettext/xml --quiet --update cases/$case") == 0 or $failed = 1;
+check_extract_result($case);
+
+print "36. Merge translations into an XML file with msgctxts:               ";
+$case = "context.xml";
+system("$INTLTOOL_MERGE -x --quiet cases cases/$case.in cases/$case") == 0 or $failed = 1;
+check_merge_result($case);
+
 system("rm -f cases/*.*") if $srcdir ne ".";
 system("rm -rf C az extract9 fr fr_BE fr_FR merge6 schemasmerge1 schemasmerge2 spacepreserve test test-quoted merge6.xml");
