diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 1259a364111bfc2c78ebc5ef008636a83278f9d7..cf36dadae3ffd56b0cefc65a096743df630be22e 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.162 2007/11/15 21:14:42 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.163 2007/12/12 21:41:47 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "describe.h"
@@ -85,8 +85,11 @@ describeAggregates(const char *pattern, bool verbose)
 					  "FROM pg_catalog.pg_proc p\n"
 	   "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
 					  "WHERE p.proisagg\n",
-					  _("Schema"), _("Name"), _("Result data type"),
-					  _("Argument data types"), _("Description"));
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"),
+					  gettext_noop("Result data type"),
+					  gettext_noop("Argument data types"),
+					  gettext_noop("Description"));
 
 	processSQLNamePattern(pset.db, &buf, pattern, true, false,
 						  "n.nspname", "p.proname", NULL,
@@ -101,6 +104,7 @@ describeAggregates(const char *pattern, bool verbose)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of aggregate functions");
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -131,13 +135,16 @@ describeTablespaces(const char *pattern, bool verbose)
 					  "SELECT spcname AS \"%s\",\n"
 					  "  pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
 					  "  spclocation AS \"%s\"",
-					  _("Name"), _("Owner"), _("Location"));
+					  gettext_noop("Name"),
+					  gettext_noop("Owner"),
+					  gettext_noop("Location"));
 
 	if (verbose)
 		appendPQExpBuffer(&buf,
-						  ",\n  spcacl as \"%s\""
+						  ",\n  spcacl AS \"%s\""
 		 ",\n  pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
-						  _("Access privileges"), _("Description"));
+						  gettext_noop("Access privileges"),
+						  gettext_noop("Description"));
 
 	appendPQExpBuffer(&buf,
 					  "\nFROM pg_catalog.pg_tablespace\n");
@@ -155,6 +162,7 @@ describeTablespaces(const char *pattern, bool verbose)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of tablespaces");
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -208,8 +216,10 @@ describeFunctions(const char *pattern, bool verbose)
 					  "        pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
 					  "    ), ', ')\n"
 					  "  END AS \"%s\"",
-					  _("Schema"), _("Name"), _("Result data type"),
-					  _("Argument data types"));
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"),
+					  gettext_noop("Result data type"),
+					  gettext_noop("Argument data types"));
 
 	if (verbose)
 		appendPQExpBuffer(&buf,
@@ -222,8 +232,11 @@ describeFunctions(const char *pattern, bool verbose)
 						  "  l.lanname as \"%s\",\n"
 						  "  p.prosrc as \"%s\",\n"
 				  "  pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
-						  _("Volatility"), _("Owner"), _("Language"),
-						  _("Source code"), _("Description"));
+						  gettext_noop("Volatility"),
+						  gettext_noop("Owner"),
+						  gettext_noop("Language"),
+						  gettext_noop("Source code"),
+						  gettext_noop("Description"));
 
 	if (!verbose)
 		appendPQExpBuffer(&buf,
@@ -258,6 +271,7 @@ describeFunctions(const char *pattern, bool verbose)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of functions");
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -283,7 +297,8 @@ describeTypes(const char *pattern, bool verbose)
 	printfPQExpBuffer(&buf,
 					  "SELECT n.nspname as \"%s\",\n"
 					  "  pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n",
-					  _("Schema"), _("Name"));
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"));
 	if (verbose)
 		appendPQExpBuffer(&buf,
 						  "  t.typname AS \"%s\",\n"
@@ -293,10 +308,11 @@ describeTypes(const char *pattern, bool verbose)
 						  "      THEN CAST('var' AS pg_catalog.text)\n"
 						  "    ELSE CAST(t.typlen AS pg_catalog.text)\n"
 						  "  END AS \"%s\",\n",
-						  _("Internal name"), _("Size"));
+						  gettext_noop("Internal name"),
+						  gettext_noop("Size"));
 	appendPQExpBuffer(&buf,
 				"  pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
-					  _("Description"));
+					  gettext_noop("Description"));
 
 	appendPQExpBuffer(&buf, "FROM pg_catalog.pg_type t\n"
 	 "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
@@ -325,6 +341,7 @@ describeTypes(const char *pattern, bool verbose)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of data types");
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -354,9 +371,12 @@ describeOperators(const char *pattern)
 	"           pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
 					  "FROM pg_catalog.pg_operator o\n"
 	  "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
-					  _("Schema"), _("Name"),
-					  _("Left arg type"), _("Right arg type"),
-					  _("Result type"), _("Description"));
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"),
+					  gettext_noop("Left arg type"),
+					  gettext_noop("Right arg type"),
+					  gettext_noop("Result type"),
+					  gettext_noop("Description"));
 
 	processSQLNamePattern(pset.db, &buf, pattern, false, true,
 						  "n.nspname", "o.oprname", NULL,
@@ -371,6 +391,7 @@ describeOperators(const char *pattern)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of operators");
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -395,19 +416,19 @@ listAllDbs(bool verbose)
 
 	printfPQExpBuffer(&buf,
 					  "SELECT d.datname as \"%s\",\n"
-					  "       r.rolname as \"%s\"",
-					  _("Name"), _("Owner"));
-	appendPQExpBuffer(&buf,
-			",\n       pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\"",
-					  _("Encoding"));
+					  "       r.rolname as \"%s\",\n"
+					  "       pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\"",
+					  gettext_noop("Name"),
+					  gettext_noop("Owner"),
+					  gettext_noop("Encoding"));
 	if (verbose)
 	{
 		appendPQExpBuffer(&buf,
 						  ",\n       t.spcname as \"%s\"",
-						  _("Tablespace"));
+						  gettext_noop("Tablespace"));
 		appendPQExpBuffer(&buf,
 						  ",\n       pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
-						  _("Description"));
+						  gettext_noop("Description"));
 	}
 	appendPQExpBuffer(&buf,
 					  "\nFROM pg_catalog.pg_database d"
@@ -423,6 +444,7 @@ listAllDbs(bool verbose)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of databases");
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -441,6 +463,7 @@ permissionsList(const char *pattern)
 	PQExpBufferData buf;
 	PGresult   *res;
 	printQueryOpt myopt = pset.popt;
+	static const bool trans_columns[] = {false, false, true, false};
 
 	initPQExpBuffer(&buf);
 
@@ -455,7 +478,11 @@ permissionsList(const char *pattern)
 					  "FROM pg_catalog.pg_class c\n"
 	   "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
 					  "WHERE c.relkind IN ('r', 'v', 'S')\n",
-					  _("Schema"), _("Name"), _("table"), _("view"), _("sequence"), _("Type"), _("Access privileges"));
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"),
+					  gettext_noop("table"), gettext_noop("view"), gettext_noop("sequence"),
+					  gettext_noop("Type"),
+					  gettext_noop("Access privileges"));
 
 	/*
 	 * Unless a schema pattern is specified, we suppress system and temp
@@ -477,8 +504,11 @@ permissionsList(const char *pattern)
 	}
 
 	myopt.nullPrint = NULL;
-	printfPQExpBuffer(&buf, _("Access privileges for database \"%s\""), PQdb(pset.db));
+	printfPQExpBuffer(&buf, _("Access privileges for database \"%s\""),
+					  PQdb(pset.db));
 	myopt.title = buf.data;
+	myopt.trans_headers = true;
+	myopt.trans_columns = trans_columns;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -503,13 +533,17 @@ objectDescription(const char *pattern)
 	PQExpBufferData buf;
 	PGresult   *res;
 	printQueryOpt myopt = pset.popt;
+	static const bool trans_columns[] = {false, false, true, false};
 
 	initPQExpBuffer(&buf);
 
 	appendPQExpBuffer(&buf,
 					  "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n"
 					  "FROM (\n",
-					  _("Schema"), _("Name"), _("Object"), _("Description"));
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"),
+					  gettext_noop("Object"),
+					  gettext_noop("Description"));
 
 	/* Aggregate descriptions */
 	appendPQExpBuffer(&buf,
@@ -520,7 +554,7 @@ objectDescription(const char *pattern)
 					  "  FROM pg_catalog.pg_proc p\n"
 	 "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
 					  "  WHERE p.proisagg\n",
-					  _("aggregate"));
+					  gettext_noop("aggregate"));
 	processSQLNamePattern(pset.db, &buf, pattern, true, false,
 						  "n.nspname", "p.proname", NULL,
 						  "pg_catalog.pg_function_is_visible(p.oid)");
@@ -539,7 +573,7 @@ objectDescription(const char *pattern)
 					  "      AND (p.proargtypes[0] IS NULL\n"
 					  "      OR   p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype)\n"
 					  "      AND NOT p.proisagg\n",
-					  _("function"));
+					  gettext_noop("function"));
 	processSQLNamePattern(pset.db, &buf, pattern, true, false,
 						  "n.nspname", "p.proname", NULL,
 						  "pg_catalog.pg_function_is_visible(p.oid)");
@@ -553,7 +587,7 @@ objectDescription(const char *pattern)
 					  "  CAST('%s' AS pg_catalog.text) as object\n"
 					  "  FROM pg_catalog.pg_operator o\n"
 	"       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
-					  _("operator"));
+					  gettext_noop("operator"));
 	processSQLNamePattern(pset.db, &buf, pattern, false, false,
 						  "n.nspname", "o.oprname", NULL,
 						  "pg_catalog.pg_operator_is_visible(o.oid)");
@@ -567,7 +601,7 @@ objectDescription(const char *pattern)
 					  "  CAST('%s' AS pg_catalog.text) as object\n"
 					  "  FROM pg_catalog.pg_type t\n"
 	"       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n",
-					  _("data type"));
+					  gettext_noop("data type"));
 	processSQLNamePattern(pset.db, &buf, pattern, false, false,
 						  "n.nspname", "pg_catalog.format_type(t.oid, NULL)",
 						  NULL,
@@ -585,7 +619,10 @@ objectDescription(const char *pattern)
 					  "  FROM pg_catalog.pg_class c\n"
 	 "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
 					  "  WHERE c.relkind IN ('r', 'v', 'i', 'S')\n",
-					  _("table"), _("view"), _("index"), _("sequence"));
+					  gettext_noop("table"),
+					  gettext_noop("view"),
+					  gettext_noop("index"),
+					  gettext_noop("sequence"));
 	processSQLNamePattern(pset.db, &buf, pattern, true, false,
 						  "n.nspname", "c.relname", NULL,
 						  "pg_catalog.pg_table_is_visible(c.oid)");
@@ -601,7 +638,7 @@ objectDescription(const char *pattern)
 				  "       JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
 	 "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
 					  "  WHERE r.rulename != '_RETURN'\n",
-					  _("rule"));
+					  gettext_noop("rule"));
 	/* XXX not sure what to do about visibility rule here? */
 	processSQLNamePattern(pset.db, &buf, pattern, true, false,
 						  "n.nspname", "r.rulename", NULL,
@@ -617,7 +654,7 @@ objectDescription(const char *pattern)
 					  "  FROM pg_catalog.pg_trigger t\n"
 				   "       JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
 	"       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
-					  _("trigger"));
+					  gettext_noop("trigger"));
 	/* XXX not sure what to do about visibility rule here? */
 	processSQLNamePattern(pset.db, &buf, pattern, false, false,
 						  "n.nspname", "t.tgname", NULL,
@@ -636,6 +673,8 @@ objectDescription(const char *pattern)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("Object descriptions");
+	myopt.trans_headers = true;
+	myopt.trans_columns = trans_columns;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -1572,6 +1611,7 @@ describeRoles(const char *pattern, bool verbose)
 	PQExpBufferData buf;
 	PGresult   *res;
 	printQueryOpt myopt = pset.popt;
+	static const bool trans_columns[] = {false, true, true, true, true, false, false};
 
 	initPQExpBuffer(&buf);
 
@@ -1584,16 +1624,20 @@ describeRoles(const char *pattern, bool verbose)
 					  "       ELSE CAST(r.rolconnlimit AS pg_catalog.text)\n"
 					  "  END AS \"%s\", \n"
 					  "  ARRAY(SELECT b.rolname FROM pg_catalog.pg_auth_members m JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid) WHERE m.member = r.oid) as \"%s\"",
-					  _("Role name"),
-					  _("yes"), _("no"), _("Superuser"),
-					  _("yes"), _("no"), _("Create role"),
-					  _("yes"), _("no"), _("Create DB"),
-					  _("no limit"), _("Connections"),
-					  _("Member of"));
+					  gettext_noop("Role name"),
+					  gettext_noop("yes"), gettext_noop("no"),
+					  gettext_noop("Superuser"),
+					  gettext_noop("yes"), gettext_noop("no"),
+					  gettext_noop("Create role"),
+					  gettext_noop("yes"), gettext_noop("no"),
+					  gettext_noop("Create DB"),
+					  gettext_noop("no limit"),
+					  gettext_noop("Connections"),
+					  gettext_noop("Member of"));
 
 	if (verbose)
 		appendPQExpBuffer(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS \"%s\"",
-						  _("Description"));
+						  gettext_noop("Description"));
 
 	appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_roles r\n");
 
@@ -1609,6 +1653,8 @@ describeRoles(const char *pattern, bool verbose)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of roles");
+	myopt.trans_headers = true;
+	myopt.trans_columns = trans_columns;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -1642,6 +1688,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose)
 	PQExpBufferData buf;
 	PGresult   *res;
 	printQueryOpt myopt = pset.popt;
+	static const bool trans_columns[] = {false, false, true, false, false, false};
 
 	if (!(showTables || showIndexes || showViews || showSeq))
 		showTables = showViews = showSeq = true;
@@ -1657,19 +1704,21 @@ listTables(const char *tabtypes, const char *pattern, bool verbose)
 					  "  c.relname as \"%s\",\n"
 					  "  CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' WHEN 's' THEN '%s' END as \"%s\",\n"
 					  "  r.rolname as \"%s\"",
-					  _("Schema"), _("Name"),
-					  _("table"), _("view"), _("index"), _("sequence"),
-					  _("special"), _("Type"), _("Owner"));
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"),
+					  gettext_noop("table"), gettext_noop("view"), gettext_noop("index"), gettext_noop("sequence"), gettext_noop("special"),
+					  gettext_noop("Type"),
+					  gettext_noop("Owner"));
 
 	if (showIndexes)
 		appendPQExpBuffer(&buf,
 						  ",\n c2.relname as \"%s\"",
-						  _("Table"));
+						  gettext_noop("Table"));
 
 	if (verbose)
 		appendPQExpBuffer(&buf,
 			  ",\n  pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
-						  _("Description"));
+						  gettext_noop("Description"));
 
 	appendPQExpBuffer(&buf,
 					  "\nFROM pg_catalog.pg_class c"
@@ -1729,6 +1778,8 @@ listTables(const char *tabtypes, const char *pattern, bool verbose)
 	{
 		myopt.nullPrint = NULL;
 		myopt.title = _("List of relations");
+		myopt.trans_headers = true;
+		myopt.trans_columns = trans_columns;
 
 		printQuery(res, &myopt, pset.queryFout, pset.logfile);
 	}
@@ -1766,11 +1817,11 @@ listDomains(const char *pattern)
 	   "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n"
 		  "     LEFT JOIN pg_catalog.pg_constraint r ON t.oid = r.contypid\n"
 					  "WHERE t.typtype = 'd'\n",
-					  _("Schema"),
-					  _("Name"),
-					  _("Type"),
-					  _("Modifier"),
-					  _("Check"));
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"),
+					  gettext_noop("Type"),
+					  gettext_noop("Modifier"),
+					  gettext_noop("Check"));
 
 	processSQLNamePattern(pset.db, &buf, pattern, true, false,
 						  "n.nspname", "t.typname", NULL,
@@ -1785,6 +1836,7 @@ listDomains(const char *pattern)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of domains");
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -1803,6 +1855,7 @@ listConversions(const char *pattern)
 	PQExpBufferData buf;
 	PGresult   *res;
 	printQueryOpt myopt = pset.popt;
+	static const bool trans_columns[] = {false, false, false, false, true};
 
 	initPQExpBuffer(&buf);
 
@@ -1815,13 +1868,12 @@ listConversions(const char *pattern)
 					  "       ELSE '%s' END AS \"%s\"\n"
 			   "FROM pg_catalog.pg_conversion c, pg_catalog.pg_namespace n\n"
 					  "WHERE n.oid = c.connamespace\n",
-					  _("Schema"),
-					  _("Name"),
-					  _("Source"),
-					  _("Destination"),
-					  _("yes"),
-					  _("no"),
-					  _("Default?"));
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"),
+					  gettext_noop("Source"),
+					  gettext_noop("Destination"),
+					  gettext_noop("yes"), gettext_noop("no"),
+					  gettext_noop("Default?"));
 
 	processSQLNamePattern(pset.db, &buf, pattern, true, false,
 						  "n.nspname", "c.conname", NULL,
@@ -1836,6 +1888,8 @@ listConversions(const char *pattern)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of conversions");
+	myopt.trans_headers = true;
+	myopt.trans_columns = trans_columns;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -1854,13 +1908,19 @@ listCasts(const char *pattern)
 	PQExpBufferData buf;
 	PGresult   *res;
 	printQueryOpt myopt = pset.popt;
+	static const bool trans_columns[] = {false, false, false, true};
 
 	initPQExpBuffer(&buf);
-/* NEED LEFT JOIN FOR BINARY CASTS */
+	/*
+	 * We need left join here for binary casts.  Also note that we don't
+	 * attempt to localize '(binary compatible)', because there's too much
+	 * risk of gettext translating a function name that happens to match
+	 * some string in the PO database.
+	 */
 	printfPQExpBuffer(&buf,
 			   "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
 			   "       pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n"
-					  "       CASE WHEN castfunc = 0 THEN '%s'\n"
+					  "       CASE WHEN castfunc = 0 THEN '(binary compatible)'\n"
 					  "            ELSE p.proname\n"
 					  "       END as \"%s\",\n"
 					  "       CASE WHEN c.castcontext = 'e' THEN '%s'\n"
@@ -1870,14 +1930,11 @@ listCasts(const char *pattern)
 				 "FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
 					  "     ON c.castfunc = p.oid\n"
 					  "ORDER BY 1, 2",
-					  _("Source type"),
-					  _("Target type"),
-					  _("(binary compatible)"),
-					  _("Function"),
-					  _("no"),
-					  _("in assignment"),
-					  _("yes"),
-					  _("Implicit?"));
+					  gettext_noop("Source type"),
+					  gettext_noop("Target type"),
+					  gettext_noop("Function"),
+					  gettext_noop("no"), gettext_noop("in assignment"), gettext_noop("yes"),
+					  gettext_noop("Implicit?"));
 
 	res = PSQLexec(buf.data, false);
 	termPQExpBuffer(&buf);
@@ -1886,6 +1943,8 @@ listCasts(const char *pattern)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of casts");
+	myopt.trans_headers = true;
+	myopt.trans_columns = trans_columns;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -1909,13 +1968,15 @@ listSchemas(const char *pattern, bool verbose)
 	printfPQExpBuffer(&buf,
 					  "SELECT n.nspname AS \"%s\",\n"
 					  "       r.rolname AS \"%s\"",
-					  _("Name"), _("Owner"));
+					  gettext_noop("Name"),
+					  gettext_noop("Owner"));
 
 	if (verbose)
 		appendPQExpBuffer(&buf,
 						  ",\n  n.nspacl as \"%s\","
 			 "  pg_catalog.obj_description(n.oid, 'pg_namespace') as \"%s\"",
-						  _("Access privileges"), _("Description"));
+						  gettext_noop("Access privileges"),
+						  gettext_noop("Description"));
 
 	appendPQExpBuffer(&buf,
 			  "\nFROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_roles r\n"
@@ -1936,6 +1997,7 @@ listSchemas(const char *pattern, bool verbose)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of schemas");
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -1967,9 +2029,9 @@ listTSParsers(const char *pattern, bool verbose)
 			"  pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n"
 					  "FROM pg_catalog.pg_ts_parser p \n"
 		   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n",
-					  _("Schema"),
-					  _("Name"),
-					  _("Description")
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"),
+					  gettext_noop("Description")
 		);
 
 	processSQLNamePattern(pset.db, &buf, pattern, false, false,
@@ -1985,6 +2047,7 @@ listTSParsers(const char *pattern, bool verbose)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of text search parsers");
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -2067,6 +2130,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
 	PGresult   *res;
 	char		title[1024];
 	printQueryOpt myopt = pset.popt;
+	static const bool trans_columns[] = {true, false, false};
 
 	initPQExpBuffer(&buf);
 
@@ -2100,14 +2164,19 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
 				  "   pg_catalog.obj_description(p.prslextype, 'pg_proc') \n"
 					  " FROM pg_catalog.pg_ts_parser p \n"
 					  " WHERE p.oid = '%s' \n",
-					  _("Start parse"),
-					  _("Method"), _("Function"), _("Description"),
+					  gettext_noop("Start parse"),
+					  gettext_noop("Method"),
+					  gettext_noop("Function"),
+					  gettext_noop("Description"),
 					  oid,
-					  _("Get next token"), oid,
-					  _("End parse"), oid,
-					  _("Get headline"), oid,
-					  _("Get token types"), oid
-		);
+					  gettext_noop("Get next token"),
+					  oid,
+					  gettext_noop("End parse"),
+					  oid,
+					  gettext_noop("Get headline"),
+					  oid,
+					  gettext_noop("Get token types"),
+					  oid);
 
 	res = PSQLexec(buf.data, false);
 	termPQExpBuffer(&buf);
@@ -2122,6 +2191,8 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
 	myopt.title = title;
 	myopt.footers = NULL;
 	myopt.default_footer = false;
+	myopt.trans_headers = true;
+	myopt.trans_columns = trans_columns;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -2134,8 +2205,8 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
 					  "  t.description as \"%s\" \n"
 			  "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t \n"
 					  "ORDER BY 1;",
-					  _("Token name"),
-					  _("Description"),
+					  gettext_noop("Token name"),
+					  gettext_noop("Description"),
 					  oid);
 
 	res = PSQLexec(buf.data, false);
@@ -2151,6 +2222,8 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
 	myopt.title = title;
 	myopt.footers = NULL;
 	myopt.default_footer = true;
+	myopt.trans_headers = true;
+	myopt.trans_columns = NULL;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -2176,8 +2249,8 @@ listTSDictionaries(const char *pattern, bool verbose)
 					  "SELECT \n"
 					  "  n.nspname as \"%s\",\n"
 					  "  d.dictname as \"%s\",\n",
-					  _("Schema"),
-					  _("Name"));
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"));
 
 	if (verbose)
 	{
@@ -2187,13 +2260,13 @@ listTSDictionaries(const char *pattern, bool verbose)
 						  "			 LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace \n"
 						  "			 WHERE d.dicttemplate = t.oid ) AS  \"%s\", \n"
 						  "  d.dictinitoption as \"%s\", \n",
-						  _("Template"),
-						  _("Init options"));
+						  gettext_noop("Template"),
+						  gettext_noop("Init options"));
 	}
 
 	appendPQExpBuffer(&buf,
 			 "  pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n",
-					  _("Description"));
+					  gettext_noop("Description"));
 
 	appendPQExpBuffer(&buf, "FROM pg_catalog.pg_ts_dict d\n"
 		 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
@@ -2211,6 +2284,7 @@ listTSDictionaries(const char *pattern, bool verbose)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of text search dictionaries");
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -2240,20 +2314,20 @@ listTSTemplates(const char *pattern, bool verbose)
 						  "  t.tmplinit::pg_catalog.regproc AS \"%s\",\n"
 						  "  t.tmpllexize::pg_catalog.regproc AS \"%s\",\n"
 		 "  pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
-						  _("Schema"),
-						  _("Name"),
-						  _("Init"),
-						  _("Lexize"),
-						  _("Description"));
+						  gettext_noop("Schema"),
+						  gettext_noop("Name"),
+						  gettext_noop("Init"),
+						  gettext_noop("Lexize"),
+						  gettext_noop("Description"));
 	else
 		printfPQExpBuffer(&buf,
 						  "SELECT \n"
 						  "  n.nspname AS \"%s\",\n"
 						  "  t.tmplname AS \"%s\",\n"
 		 "  pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
-						  _("Schema"),
-						  _("Name"),
-						  _("Description"));
+						  gettext_noop("Schema"),
+						  gettext_noop("Name"),
+						  gettext_noop("Description"));
 
 	appendPQExpBuffer(&buf, "FROM pg_catalog.pg_ts_template t\n"
 		 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
@@ -2271,6 +2345,7 @@ listTSTemplates(const char *pattern, bool verbose)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of text search templates");
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -2302,9 +2377,9 @@ listTSConfigs(const char *pattern, bool verbose)
 		   "   pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n"
 					  "FROM pg_catalog.pg_ts_config c\n"
 		  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace \n",
-					  _("Schema"),
-					  _("Name"),
-					  _("Description")
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"),
+					  gettext_noop("Description")
 		);
 
 	processSQLNamePattern(pset.db, &buf, pattern, false, false,
@@ -2320,6 +2395,7 @@ listTSConfigs(const char *pattern, bool verbose)
 
 	myopt.nullPrint = NULL;
 	myopt.title = _("List of text search configurations");
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -2428,8 +2504,8 @@ describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname,
 					  "WHERE c.oid = '%s' AND m.mapcfg = c.oid \n"
 					  "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser \n"
 					  "ORDER BY 1",
-					  _("Token"),
-					  _("Dictionaries"),
+					  gettext_noop("Token"),
+					  gettext_noop("Dictionaries"),
 					  oid);
 
 	res = PSQLexec(buf.data, false);
@@ -2440,19 +2516,24 @@ describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname,
 	initPQExpBuffer(&title);
 
 	if (nspname)
-		appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""), nspname, cfgname);
+		appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""),
+						  nspname, cfgname);
 	else
-		appendPQExpBuffer(&title, _("Text search configuration \"%s\""), cfgname);
+		appendPQExpBuffer(&title, _("Text search configuration \"%s\""),
+						  cfgname);
 
 	if (pnspname)
-		appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""), pnspname, prsname);
+		appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""),
+						  pnspname, prsname);
 	else
-		appendPQExpBuffer(&title, _("\nParser: \"%s\""), prsname);
+		appendPQExpBuffer(&title, _("\nParser: \"%s\""),
+						  prsname);
 
 	myopt.nullPrint = NULL;
 	myopt.title = title.data;
 	myopt.footers = NULL;
 	myopt.default_footer = false;
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c
index 87918a8850f5776004094b93c9bb19702dd1de73..4ef2684eac774657cfa291dda2c2c6056332c3f1 100644
--- a/src/bin/psql/large_obj.c
+++ b/src/bin/psql/large_obj.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/large_obj.c,v 1.48 2007/01/20 16:57:31 neilc Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/large_obj.c,v 1.49 2007/12/12 21:41:47 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "large_obj.h"
@@ -279,11 +279,12 @@ do_lo_list(void)
 	printQueryOpt myopt = pset.popt;
 
 	snprintf(buf, sizeof(buf),
-			 "SELECT loid as \"ID\",\n"
+			 "SELECT loid as \"%s\",\n"
 		   "  pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n"
 			 "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n"
 			 "ORDER BY 1",
-			 _("Description"));
+			 gettext_noop("ID"),
+			 gettext_noop("Description"));
 
 	res = PSQLexec(buf, false);
 	if (!res)
@@ -292,6 +293,7 @@ do_lo_list(void)
 	myopt.topt.tuples_only = false;
 	myopt.nullPrint = NULL;
 	myopt.title = _("Large objects");
+	myopt.trans_headers = true;
 
 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c
index d0e378b7bdca7b6912ac89bf986fcf8dd23d25c7..c7df0072f84d830078065fadcf047d7f69c65007 100644
--- a/src/bin/psql/print.c
+++ b/src/bin/psql/print.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.94 2007/11/22 17:51:39 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.95 2007/12/12 21:41:47 tgl Exp $
  *
  * Note: we include postgres.h not postgres_fe.h so that we can include
  * catalog/pg_type.h, and thereby have access to INT4OID and similar macros.
@@ -1926,38 +1926,59 @@ printTable(const char *title,
 void
 printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *flog)
 {
+	int			ntuples;
 	int			nfields;
 	int			ncells;
 	const char **headers;
 	const char **cells;
 	char	  **footers;
 	char	   *align;
-	int			i;
+	int			i,
+				r,
+				c;
 
 	if (cancel_pressed)
 		return;
 
 	/* extract headers */
+	ntuples = PQntuples(result);
 	nfields = PQnfields(result);
 
 	headers = pg_local_calloc(nfields + 1, sizeof(*headers));
 
 	for (i = 0; i < nfields; i++)
+	{
 		headers[i] = (char *) mbvalidate((unsigned char *) PQfname(result, i),
 										 opt->topt.encoding);
+#ifdef ENABLE_NLS
+		if (opt->trans_headers)
+			headers[i] = _(headers[i]);
+#endif
+	}
 
 	/* set cells */
-	ncells = PQntuples(result) * nfields;
+	ncells = ntuples * nfields;
 	cells = pg_local_calloc(ncells + 1, sizeof(*cells));
 
-	for (i = 0; i < ncells; i++)
+	i = 0;
+	for (r = 0; r < ntuples; r++)
 	{
-		if (PQgetisnull(result, i / nfields, i % nfields))
-			cells[i] = opt->nullPrint ? opt->nullPrint : "";
-		else
-			cells[i] = (char *)
-				mbvalidate((unsigned char *) PQgetvalue(result, i / nfields, i % nfields),
-						   opt->topt.encoding);
+		for (c = 0; c < nfields; c++)
+		{
+			if (PQgetisnull(result, r, c))
+				cells[i] = opt->nullPrint ? opt->nullPrint : "";
+			else
+			{
+				cells[i] = (char *)
+					mbvalidate((unsigned char *) PQgetvalue(result, r, c),
+							   opt->topt.encoding);
+#ifdef ENABLE_NLS
+				if (opt->trans_columns && opt->trans_columns[c])
+					cells[i] = _(cells[i]);
+#endif
+			}
+			i++;
+		}
 	}
 
 	/* set footers */
@@ -1970,7 +1991,7 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f
 
 		footers = pg_local_calloc(2, sizeof(*footers));
 		footers[0] = pg_local_malloc(100);
-		total_records = opt->topt.prior_records + PQntuples(result);
+		total_records = opt->topt.prior_records + ntuples;
 		if (total_records == 1)
 			snprintf(footers[0], 100, _("(1 row)"));
 		else
@@ -2013,7 +2034,7 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f
 
 	free(headers);
 	free(cells);
-	if (footers)
+	if (footers && !opt->footers)
 	{
 		free(footers[0]);
 		free(footers);
diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h
index 8c1537762ace68135b9ad80a826213d096cd51aa..cfe9a17a02cbdb4aa90643526439a00020464e50 100644
--- a/src/bin/psql/print.h
+++ b/src/bin/psql/print.h
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/print.h,v 1.33 2007/01/05 22:19:49 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/print.h,v 1.34 2007/12/12 21:41:47 tgl Exp $
  */
 #ifndef PRINT_H
 #define PRINT_H
@@ -67,7 +67,6 @@ void printTable(const char *title, const char *const * headers,
 		   const printTableOpt *opt, FILE *fout, FILE *flog);
 
 
-
 typedef struct _printQueryOpt
 {
 	printTableOpt topt;			/* the options above */
@@ -76,6 +75,8 @@ typedef struct _printQueryOpt
 	char	   *title;			/* override title */
 	char	  **footers;		/* override footer (default is "(xx rows)") */
 	bool		default_footer; /* print default footer if footers==NULL */
+	bool		trans_headers;	/* do gettext on column headers */
+	const bool *trans_columns;	/* trans_columns[i-1] => do gettext on col i */
 } printQueryOpt;
 
 /*
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 32f8dcd59ca9ba94b3b0e0c04cf4235d32c44149..77281cbc71476d559a0e528d0f28712c2eb11fe0 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.144 2007/12/11 19:01:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.145 2007/12/12 21:41:47 tgl Exp $
  */
 #include "postgres_fe.h"
 
@@ -140,6 +140,7 @@ main(int argc, char *argv[])
 	pset.cur_cmd_source = stdin;
 	pset.cur_cmd_interactive = false;
 
+	/* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */
 	pset.popt.topt.format = PRINT_ALIGNED;
 	pset.popt.topt.border = 1;
 	pset.popt.topt.pager = 1;
diff --git a/src/bin/scripts/createlang.c b/src/bin/scripts/createlang.c
index 6fe6f25e6f37031579349730c9b461ba0f6f3aef..3c0838e32a3910d024173e605bb2bdb9db571866 100644
--- a/src/bin/scripts/createlang.c
+++ b/src/bin/scripts/createlang.c
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/scripts/createlang.c,v 1.27 2007/12/11 19:57:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/scripts/createlang.c,v 1.28 2007/12/12 21:41:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -125,6 +125,7 @@ main(int argc, char *argv[])
 	if (listlangs)
 	{
 		printQueryOpt popt;
+		static const bool trans_columns[] = {false, true};
 
 		conn = connectDatabase(dbname, host, port, username, password,
 							   progname);
@@ -132,7 +133,9 @@ main(int argc, char *argv[])
 		printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
 				"(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
 						  "FROM pg_catalog.pg_language WHERE lanispl;",
-						  _("Name"), _("yes"), _("no"), _("Trusted?"));
+						  gettext_noop("Name"),
+						  gettext_noop("yes"), gettext_noop("no"),
+						  gettext_noop("Trusted?"));
 		result = executeQuery(conn, sql.data, progname, echo);
 
 		memset(&popt, 0, sizeof(popt));
@@ -142,6 +145,8 @@ main(int argc, char *argv[])
 		popt.topt.stop_table = true;
 		popt.topt.encoding = PQclientEncoding(conn);
 		popt.title = _("Procedural Languages");
+		popt.trans_headers = true;
+		popt.trans_columns = trans_columns;
 		printQuery(result, &popt, stdout, NULL);
 
 		PQfinish(conn);
diff --git a/src/bin/scripts/droplang.c b/src/bin/scripts/droplang.c
index bd255585b43ec097d304e1e8eba85943a18fba32..982471f7c03b1ddcf7a7220879bfc969823c1430 100644
--- a/src/bin/scripts/droplang.c
+++ b/src/bin/scripts/droplang.c
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/scripts/droplang.c,v 1.24 2007/12/11 19:57:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/scripts/droplang.c,v 1.25 2007/12/12 21:41:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -136,6 +136,7 @@ main(int argc, char *argv[])
 	if (listlangs)
 	{
 		printQueryOpt popt;
+		static const bool trans_columns[] = {false, true};
 
 		conn = connectDatabase(dbname, host, port, username, password,
 							   progname);
@@ -143,7 +144,9 @@ main(int argc, char *argv[])
 		printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
 				"(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
 						  "FROM pg_catalog.pg_language WHERE lanispl;",
-						  _("Name"), _("yes"), _("no"), _("Trusted?"));
+						  gettext_noop("Name"),
+						  gettext_noop("yes"), gettext_noop("no"),
+						  gettext_noop("Trusted?"));
 		result = executeQuery(conn, sql.data, progname, echo);
 
 		memset(&popt, 0, sizeof(popt));
@@ -153,6 +156,8 @@ main(int argc, char *argv[])
 		popt.topt.stop_table = true;
 		popt.topt.encoding = PQclientEncoding(conn);
 		popt.title = _("Procedural Languages");
+		popt.trans_headers = true;
+		popt.trans_columns = trans_columns;
 		printQuery(result, &popt, stdout, NULL);
 
 		PQfinish(conn);