diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile
index 0afc08f798512d2b38d2dc68945bfac72238ee98..4f6e22b83ba03f4b658d217e43455c0152df5cd0 100644
--- a/src/pl/plpython/Makefile
+++ b/src/pl/plpython/Makefile
@@ -1,4 +1,4 @@
-# $PostgreSQL: pgsql/src/pl/plpython/Makefile,v 1.31 2008/10/02 08:11:11 petere Exp $
+# $PostgreSQL: pgsql/src/pl/plpython/Makefile,v 1.32 2009/01/15 13:49:56 petere Exp $
 
 subdir = src/pl/plpython
 top_builddir = ../../..
@@ -54,7 +54,7 @@ python${pytverstr}.def: $(WD)/system32/python${pytverstr}.dll
 endif
 
 
-SHLIB_LINK = $(python_libspec) $(python_additional_libs)
+SHLIB_LINK = $(python_libspec) $(python_additional_libs) $(filter -lintl,$(LIBS))
 
 REGRESS_OPTS = --dbname=$(PL_TESTDB) --load-language=plpythonu
 REGRESS = plpython_schema plpython_populate plpython_function plpython_test plpython_error plpython_drop
diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out
index 8a0b08fe163d7e4fb81fe594a202fb75512f9d08..548f7ae3ca5ea95b1c4f5f9017d4006592f5bb90 100644
--- a/src/pl/plpython/expected/plpython_error.out
+++ b/src/pl/plpython/expected/plpython_error.out
@@ -2,16 +2,16 @@
 -- the trigger handler once. the errors and subsequent core dump were
 -- interesting.
 SELECT invalid_type_uncaught('rick');
-WARNING:  plpython: in function invalid_type_uncaught:
-DETAIL:  plpy.SPIError: Unknown error in PLy_spi_prepare
+WARNING:  PL/Python: in PL/Python function "invalid_type_uncaught"
+DETAIL:  <class 'plpy.SPIError'>: unrecognized error in PLy_spi_prepare
 ERROR:  type "test" does not exist
 SELECT invalid_type_caught('rick');
-WARNING:  plpython: in function invalid_type_caught:
-DETAIL:  plpy.SPIError: Unknown error in PLy_spi_prepare
+WARNING:  PL/Python: in PL/Python function "invalid_type_caught"
+DETAIL:  <class 'plpy.SPIError'>: unrecognized error in PLy_spi_prepare
 ERROR:  type "test" does not exist
 SELECT invalid_type_reraised('rick');
-WARNING:  plpython: in function invalid_type_reraised:
-DETAIL:  plpy.SPIError: Unknown error in PLy_spi_prepare
+WARNING:  PL/Python: in PL/Python function "invalid_type_reraised"
+DETAIL:  <class 'plpy.SPIError'>: unrecognized error in PLy_spi_prepare
 ERROR:  type "test" does not exist
 SELECT valid_type('rick');
  valid_type 
@@ -23,16 +23,16 @@ SELECT valid_type('rick');
 -- Test Unicode error handling.
 --
 SELECT unicode_return_error();
-ERROR:  plpython: function "unicode_return_error" could not create return value
-DETAIL:  exceptions.UnicodeEncodeError: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
+ERROR:  PL/Python: could not create string representation of Python object in PL/Python function "unicode_return_error" while creating return value
+DETAIL:  <type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
 INSERT INTO unicode_test (testvalue) VALUES ('test');
-ERROR:  plpython: function "unicode_trigger_error" could not modify tuple
-DETAIL:  exceptions.UnicodeEncodeError: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
+ERROR:  PL/Python: could not compute string representation of Python object in PL/Python function "unicode_trigger_error" while modifying trigger row
+DETAIL:  <type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
 SELECT unicode_plan_error1();
-WARNING:  plpython: in function unicode_plan_error1:
-DETAIL:  plpy.Error: Unknown error in PLy_spi_execute_plan
-ERROR:  plpython: function "unicode_plan_error1" could not execute plan
-DETAIL:  exceptions.UnicodeEncodeError: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
+WARNING:  PL/Python: in PL/Python function "unicode_plan_error1"
+DETAIL:  <class 'plpy.Error'>: unrecognized error in PLy_spi_execute_plan
+ERROR:  PL/Python: PL/Python function "unicode_plan_error1" could not execute plan
+DETAIL:  <type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
 SELECT unicode_plan_error2();
-ERROR:  plpython: function "unicode_plan_error2" could not execute plan
-DETAIL:  exceptions.UnicodeEncodeError: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
+ERROR:  PL/Python: PL/Python function "unicode_plan_error2" could not execute plan
+DETAIL:  <type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
diff --git a/src/pl/plpython/expected/plpython_test.out b/src/pl/plpython/expected/plpython_test.out
index ddd565bbff5fda0d56a630d0a26d3a4e47d317b1..3bba37cf5098bce20b52807165fce4c3075a5cad 100644
--- a/src/pl/plpython/expected/plpython_test.out
+++ b/src/pl/plpython/expected/plpython_test.out
@@ -190,8 +190,7 @@ SELECT test_void_func1(), test_void_func1() IS NULL AS "is null";
 (1 row)
 
 SELECT test_void_func2(); -- should fail
-ERROR:  invalid return value from plpython function
-DETAIL:  Functions returning type "void" must return None.
+ERROR:  PL/Python function with return type "void" did not return None
 SELECT test_return_none(), test_return_none() IS NULL AS "is null";
  test_return_none | is null 
 ------------------+---------
@@ -547,7 +546,7 @@ SELECT * FROM test_in_out_params('test_in');
 
 -- this doesn't work yet :-(
 SELECT * FROM test_in_out_params_multi('test_in');
-ERROR:  plpython functions cannot return type record
+ERROR:  PL/Python functions cannot return type record
 SELECT * FROM test_inout_params('test_in');
      first     
 ---------------
diff --git a/src/pl/plpython/nls.mk b/src/pl/plpython/nls.mk
index 72b9ca525d45d9d5dad72bcd4a255415db439928..097ade1e0c0d46e68ef02b45ca9646c2c081003e 100644
--- a/src/pl/plpython/nls.mk
+++ b/src/pl/plpython/nls.mk
@@ -1,5 +1,5 @@
-# $PostgreSQL: pgsql/src/pl/plpython/nls.mk,v 1.1 2008/10/09 17:24:05 alvherre Exp $
+# $PostgreSQL: pgsql/src/pl/plpython/nls.mk,v 1.2 2009/01/15 13:49:56 petere Exp $
 CATALOG_NAME	:= plpython
 AVAIL_LANGUAGES	:=
 GETTEXT_FILES	:= plpython.c
-GETTEXT_TRIGGERS:= _ errmsg errdetail errdetail_log errhint errcontext write_stderr yyerror
+GETTEXT_TRIGGERS:= errmsg errdetail errdetail_log errhint errcontext PLy_elog:2 PLy_exception_set:2
diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c
index b8658837f4c8dbc3b0a5ceee1281196c02ae8d57..27324b3ff3556735df497190f7c6bd91aead0b05 100644
--- a/src/pl/plpython/plpython.c
+++ b/src/pl/plpython/plpython.c
@@ -1,7 +1,7 @@
 /**********************************************************************
  * plpython.c - python as a procedural language for PostgreSQL
  *
- *	$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.117 2008/12/11 07:34:09 petere Exp $
+ *	$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.118 2009/01/15 13:49:56 petere Exp $
  *
  *********************************************************************
  */
@@ -204,7 +204,7 @@ PG_FUNCTION_INFO_V1(plpython_call_handler);
 static void PLy_init_interp(void);
 static void PLy_init_plpy(void);
 
-/* call PyErr_SetString with a vprint interface */
+/* call PyErr_SetString with a vprint interface and translation support */
 static void
 PLy_exception_set(PyObject *, const char *,...)
 __attribute__((format(printf, 2, 3)));
@@ -213,7 +213,8 @@ __attribute__((format(printf, 2, 3)));
 static char *PLy_procedure_name(PLyProcedure *);
 
 /* some utility functions */
-static void PLy_elog(int, const char *,...);
+static void PLy_elog(int, const char *,...)
+__attribute__((format(printf, 2, 3)));
 static char *PLy_traceback(int *);
 
 static void *PLy_malloc(size_t);
@@ -331,7 +332,7 @@ plpython_call_handler(PG_FUNCTION_ARGS)
 	PLyProcedure *volatile proc = NULL;
 
 	if (SPI_connect() != SPI_OK_CONNECT)
-		elog(ERROR, "could not connect to SPI manager");
+		elog(ERROR, "SPI_connect failed");
 
 	save_curr_proc = PLy_curr_procedure;
 
@@ -417,7 +418,7 @@ PLy_trigger_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
 				ereport(ERROR,
 						(errcode(ERRCODE_DATA_EXCEPTION),
 					errmsg("unexpected return value from trigger procedure"),
-						 errdetail("Expected None or a String.")));
+						 errdetail("Expected None or a string.")));
 
 			srv = PyString_AsString(plrv);
 			if (pg_strcasecmp(srv, "SKIP") == 0)
@@ -430,7 +431,8 @@ PLy_trigger_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
 					TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
 					rv = PLy_modify_tuple(proc, plargs, tdata, rv);
 				else
-					elog(WARNING, "ignoring modified tuple in DELETE trigger");
+					ereport(WARNING,
+							(errmsg("PL/Python trigger function returned \"MODIFY\" in a DELETE trigger -- ignored")));
 			}
 			else if (pg_strcasecmp(srv, "OK") != 0)
 			{
@@ -487,9 +489,11 @@ PLy_modify_tuple(PLyProcedure * proc, PyObject * pltd, TriggerData *tdata,
 	PG_TRY();
 	{
 		if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
-			elog(ERROR, "TD[\"new\"] deleted, cannot modify tuple");
+			ereport(ERROR, 
+					(errmsg("TD[\"new\"] deleted, cannot modify row")));
 		if (!PyDict_Check(plntup))
-			elog(ERROR, "TD[\"new\"] is not a dictionary object");
+			ereport(ERROR,
+					(errmsg("TD[\"new\"] is not a dictionary")));
 		Py_INCREF(plntup);
 
 		plkeys = PyDict_Keys(plntup);
@@ -507,16 +511,18 @@ PLy_modify_tuple(PLyProcedure * proc, PyObject * pltd, TriggerData *tdata,
 
 			platt = PyList_GetItem(plkeys, i);
 			if (!PyString_Check(platt))
-				elog(ERROR, "attribute name is not a string");
+				ereport(ERROR,
+						(errmsg("name of TD[\"new\"] attribute at ordinal position %d is not a string", i)));
 			attn = SPI_fnumber(tupdesc, PyString_AsString(platt));
 			if (attn == SPI_ERROR_NOATTRIBUTE)
-				elog(ERROR, "invalid attribute \"%s\" in tuple",
-					 PyString_AsString(platt));
+				ereport(ERROR,
+						(errmsg("key \"%s\" found in TD[\"new\"] does not exist as a column in the triggering row",
+								PyString_AsString(platt))));
 			atti = attn - 1;
 
 			plval = PyDict_GetItem(plntup, platt);
 			if (plval == NULL)
-				elog(FATAL, "python interpreter is probably corrupted");
+				elog(FATAL, "Python interpreter is probably corrupted");
 
 			Py_INCREF(plval);
 
@@ -531,7 +537,7 @@ PLy_modify_tuple(PLyProcedure * proc, PyObject * pltd, TriggerData *tdata,
 			{
 				plstr = PyObject_Str(plval);
 				if (!plstr)
-					PLy_elog(ERROR, "function \"%s\" could not modify tuple",
+					PLy_elog(ERROR, "could not compute string representation of Python object in PL/Python function \"%s\" while modifying trigger row",
 							 proc->proname);
 				src = PyString_AsString(plstr);
 
@@ -562,7 +568,7 @@ PLy_modify_tuple(PLyProcedure * proc, PyObject * pltd, TriggerData *tdata,
 		rtup = SPI_modifytuple(tdata->tg_relation, otup, natts,
 							   modattrs, modvalues, modnulls);
 		if (rtup == NULL)
-			elog(ERROR, "SPI_modifytuple failed -- error %d", SPI_result);
+			elog(ERROR, "SPI_modifytuple failed: error %d", SPI_result);
 	}
 	PG_CATCH();
 	{
@@ -613,7 +619,7 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc, HeapTuple *
 	{
 		pltdata = PyDict_New();
 		if (!pltdata)
-			PLy_elog(ERROR, "could not build arguments for trigger procedure");
+			PLy_elog(ERROR, "could not create new dictionary while building trigger arguments");
 
 		pltname = PyString_FromString(tdata->tg_trigger->tgname);
 		PyDict_SetItemString(pltdata, "name", pltname);
@@ -821,7 +827,8 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
 				{
 					ereport(ERROR,
 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-							 errmsg("only value per call is allowed")));
+							 errmsg("unsupported set function return mode"),
+							 errdetail("PL/Python set-returning functions only support returning only value per call.")));
 				}
 				rsi->returnMode = SFRM_ValuePerCall;
 
@@ -834,7 +841,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
 					ereport(ERROR,
 							(errcode(ERRCODE_DATATYPE_MISMATCH),
 							 errmsg("returned object cannot be iterated"),
-					errdetail("SETOF must be returned as iterable object")));
+					errdetail("PL/Python set-returning functions must return an iterable object.")));
 			}
 
 			/* Fetch next from iterator */
@@ -880,8 +887,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
 			if (plrv != Py_None)
 				ereport(ERROR,
 						(errcode(ERRCODE_DATATYPE_MISMATCH),
-					   errmsg("invalid return value from plpython function"),
-						 errdetail("Functions returning type \"void\" must return None.")));
+					   errmsg("PL/Python function with return type \"void\" did not return None")));
 
 			fcinfo->isnull = false;
 			rv = (Datum) 0;
@@ -928,7 +934,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
 			fcinfo->isnull = false;
 			plrv_so = PyObject_Str(plrv);
 			if (!plrv_so)
-				PLy_elog(ERROR, "function \"%s\" could not create return value", proc->proname);
+				PLy_elog(ERROR, "could not create string representation of Python object in PL/Python function \"%s\" while creating return value", proc->proname);
 			plrv_sc = PyString_AsString(plrv_so);
 			rv = InputFunctionCall(&proc->result.out.d.typfunc,
 								   plrv_sc,
@@ -977,7 +983,7 @@ PLy_procedure_call(PLyProcedure * proc, char *kargs, PyObject * vargs)
 	if (rv == NULL || PyErr_Occurred())
 	{
 		Py_XDECREF(rv);
-		PLy_elog(ERROR, "function \"%s\" failed", proc->proname);
+		PLy_elog(ERROR, "PL/Python function \"%s\" failed", proc->proname);
 	}
 
 	return rv;
@@ -1049,7 +1055,7 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc)
 			if (PyList_SetItem(args, i, arg) == -1 ||
 				(proc->argnames &&
 				 PyDict_SetItemString(proc->globals, proc->argnames[i], arg) == -1))
-				PLy_elog(ERROR, "problem setting up arguments for \"%s\"", proc->proname);
+				PLy_elog(ERROR, "PyDict_SetItemString() failed for PL/Python function \"%s\" while setting up arguments", proc->proname);
 			arg = NULL;
 		}
 	}
@@ -1230,7 +1236,7 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
 				else
 					ereport(ERROR,
 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						   errmsg("plpython functions cannot return type %s",
+						   errmsg("PL/Python functions cannot return type %s",
 								  format_type_be(procStruct->prorettype))));
 			}
 
@@ -1309,7 +1315,7 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
 						/* Disallow pseudotype argument */
 						ereport(ERROR,
 								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-								 errmsg("plpython functions cannot take type %s",
+								 errmsg("PL/Python functions cannot accept type %s",
 								 format_type_be(types[i]))));
 						break;
 					case TYPTYPE_COMPOSITE:
@@ -1403,7 +1409,7 @@ PLy_procedure_compile(PLyProcedure * proc, const char *src)
 	else
 		Py_XDECREF(crv);
 
-	PLy_elog(ERROR, "could not compile function \"%s\"", proc->proname);
+	PLy_elog(ERROR, "could not compile PL/Python function \"%s\"", proc->proname);
 }
 
 static char *
@@ -1480,8 +1486,9 @@ PLy_procedure_delete(PLyProcedure * proc)
 		PLy_free(proc->argnames);
 }
 
-/* conversion functions.  remember output from python is
- * input to postgresql, and vis versa.
+/*
+ * Conversion functions.  Remember output from Python is input to
+ * PostgreSQL, and vice versa.
  */
 static void
 PLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
@@ -1714,7 +1721,7 @@ PLyDict_FromTuple(PLyTypeInfo * info, HeapTuple tuple, TupleDesc desc)
 
 	dict = PyDict_New();
 	if (dict == NULL)
-		PLy_elog(ERROR, "could not create tuple dictionary");
+		PLy_elog(ERROR, "could not create new dictionary");
 
 	PG_TRY();
 	{
@@ -1801,7 +1808,7 @@ PLyMapping_ToTuple(PLyTypeInfo * info, PyObject * mapping)
 
 				so = PyObject_Str(value);
 				if (so == NULL)
-					PLy_elog(ERROR, "cannot convert mapping type");
+					PLy_elog(ERROR, "could not compute string representation of Python object");
 				valuestr = PyString_AsString(so);
 
 				values[i] = InputFunctionCall(&info->out.r.atts[i].typfunc
@@ -1815,9 +1822,9 @@ PLyMapping_ToTuple(PLyTypeInfo * info, PyObject * mapping)
 			else
 				ereport(ERROR,
 						(errcode(ERRCODE_UNDEFINED_COLUMN),
-						 errmsg("no mapping found with key \"%s\"", key),
-						 errhint("to return null in specific column, "
-					  "add value None to map with key named after column")));
+						 errmsg("key \"%s\" not found in mapping", key),
+						 errhint("To return null in a column, "
+					  "add the value None to the mapping with the key named after the column.")));
 
 			Py_XDECREF(value);
 			value = NULL;
@@ -1860,7 +1867,7 @@ PLySequence_ToTuple(PLyTypeInfo * info, PyObject * sequence)
 	if (PySequence_Length(sequence) != desc->natts)
 		ereport(ERROR,
 				(errcode(ERRCODE_DATATYPE_MISMATCH),
-		errmsg("returned sequence's length must be same as tuple's length")));
+		errmsg("length of returned sequence did not match number of columns in row")));
 
 	if (info->is_rowtype == 2)
 		PLy_output_tuple_funcs(info, desc);
@@ -1890,7 +1897,7 @@ PLySequence_ToTuple(PLyTypeInfo * info, PyObject * sequence)
 
 				so = PyObject_Str(value);
 				if (so == NULL)
-					PLy_elog(ERROR, "cannot convert sequence type");
+					PLy_elog(ERROR, "could not compute string representation of Python object");
 				valuestr = PyString_AsString(so);
 				values[i] = InputFunctionCall(&info->out.r.atts[i].typfunc
 											  ,valuestr
@@ -1961,7 +1968,7 @@ PLyObject_ToTuple(PLyTypeInfo * info, PyObject * object)
 
 				so = PyObject_Str(value);
 				if (so == NULL)
-					PLy_elog(ERROR, "cannot convert object type");
+					PLy_elog(ERROR, "could not compute string representation of Python object");
 				valuestr = PyString_AsString(so);
 				values[i] = InputFunctionCall(&info->out.r.atts[i].typfunc
 											  ,valuestr
@@ -1974,10 +1981,10 @@ PLyObject_ToTuple(PLyTypeInfo * info, PyObject * object)
 			else
 				ereport(ERROR,
 						(errcode(ERRCODE_UNDEFINED_COLUMN),
-						 errmsg("no attribute named \"%s\"", key),
-						 errhint("to return null in specific column, "
-							   "let returned object to have attribute named "
-								 "after column with value None")));
+						 errmsg("attribute \"%s\" does not exist in Python object", key),
+						 errhint("To return null in a column, "
+								 "let the returned object have an attribute named "
+								 "after column with value None.")));
 
 			Py_XDECREF(value);
 			value = NULL;
@@ -2197,7 +2204,7 @@ PLy_plan_status(PyObject * self, PyObject * args)
 		return Py_True;
 		/* return PyInt_FromLong(self->status); */
 	}
-	PyErr_SetString(PLy_exc_error, "plan.status() takes no arguments");
+	PLy_exception_set(PLy_exc_error, "plan.status takes no arguments");
 	return NULL;
 }
 
@@ -2327,21 +2334,21 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
 	/* Can't execute more if we have an unhandled error */
 	if (PLy_error_in_progress)
 	{
-		PyErr_SetString(PLy_exc_error, "Transaction aborted.");
+		PLy_exception_set(PLy_exc_error, "transaction aborted");
 		return NULL;
 	}
 
 	if (!PyArg_ParseTuple(args, "s|O", &query, &list))
 	{
-		PyErr_SetString(PLy_exc_spi_error,
-						"Invalid arguments for plpy.prepare()");
+		PLy_exception_set(PLy_exc_spi_error,
+						  "invalid arguments for plpy.prepare");
 		return NULL;
 	}
 
 	if (list && (!PySequence_Check(list)))
 	{
-		PyErr_SetString(PLy_exc_spi_error,
-					 "Second argument in plpy.prepare() must be a sequence");
+		PLy_exception_set(PLy_exc_spi_error,
+						  "second argument of plpy.prepare must be a sequence");
 		return NULL;
 	}
 
@@ -2385,7 +2392,8 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
 
 					optr = PySequence_GetItem(list, i);
 					if (!PyString_Check(optr))
-						elog(ERROR, "Type names must be strings.");
+						ereport(ERROR,
+								(errmsg("plpy.prepare: type name at ordinal position %d is not a string", i)));
 					sptr = PyString_AsString(optr);
 
 					/********************************************************
@@ -2410,7 +2418,9 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
 					if (typeStruct->typtype != TYPTYPE_COMPOSITE)
 						PLy_output_datum_func(&plan->args[i], typeTup);
 					else
-						elog(ERROR, "tuples not handled in plpy.prepare, yet.");
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("plpy.prepare does not support composite types")));
 					ReleaseSysCache(typeTup);
 				}
 			}
@@ -2437,10 +2447,10 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
 		Py_DECREF(plan);
 		Py_XDECREF(optr);
 		if (!PyErr_Occurred())
-			PyErr_SetString(PLy_exc_spi_error,
-							"Unknown error in PLy_spi_prepare");
+			PLy_exception_set(PLy_exc_spi_error,
+							  "unrecognized error in PLy_spi_prepare");
 		/* XXX this oughta be replaced with errcontext mechanism */
-		PLy_elog(WARNING, "in function %s:",
+		PLy_elog(WARNING, "in PL/Python function \"%s\"",
 				 PLy_procedure_name(PLy_curr_procedure));
 		return NULL;
 	}
@@ -2463,7 +2473,7 @@ PLy_spi_execute(PyObject * self, PyObject * args)
 	/* Can't execute more if we have an unhandled error */
 	if (PLy_error_in_progress)
 	{
-		PyErr_SetString(PLy_exc_error, "Transaction aborted.");
+		PLy_exception_set(PLy_exc_error, "transaction aborted");
 		return NULL;
 	}
 
@@ -2476,7 +2486,7 @@ PLy_spi_execute(PyObject * self, PyObject * args)
 		is_PLyPlanObject(plan))
 		return PLy_spi_execute_plan(plan, list, limit);
 
-	PyErr_SetString(PLy_exc_error, "Expected a query or plan.");
+	PLy_exception_set(PLy_exc_error, "plpy.execute expected a query or a plan");
 	return NULL;
 }
 
@@ -2493,9 +2503,7 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, long limit)
 	{
 		if (!PySequence_Check(list) || PyString_Check(list))
 		{
-			char	   *msg = "plpy.execute() takes a sequence as its second argument";
-
-			PyErr_SetString(PLy_exc_spi_error, msg);
+			PLy_exception_set(PLy_exc_spi_error, "plpy.execute takes a sequence as its second argument");
 			return NULL;
 		}
 		nargs = PySequence_Length(list);
@@ -2511,11 +2519,11 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, long limit)
 		PyObject   *so = PyObject_Str(list);
 
 		if (!so)
-			PLy_elog(ERROR, "function \"%s\" could not execute plan",
+			PLy_elog(ERROR, "PL/Python function \"%s\" could not execute plan",
 					 PLy_procedure_name(PLy_curr_procedure));
 		sv = PyString_AsString(so);
 		PLy_exception_set(PLy_exc_spi_error,
-						  "Expected sequence of %d arguments, got %d. %s",
+						  "Expected sequence of %d arguments, got %d: %s",
 						  plan->nargs, nargs, sv);
 		Py_DECREF(so);
 
@@ -2538,7 +2546,7 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, long limit)
 			{
 				so = PyObject_Str(elem);
 				if (!so)
-					PLy_elog(ERROR, "function \"%s\" could not execute plan",
+					PLy_elog(ERROR, "PL/Python function \"%s\" could not execute plan",
 							 PLy_procedure_name(PLy_curr_procedure));
 				Py_DECREF(elem);
 
@@ -2601,10 +2609,10 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, long limit)
 		}
 
 		if (!PyErr_Occurred())
-			PyErr_SetString(PLy_exc_error,
-							"Unknown error in PLy_spi_execute_plan");
+			PLy_exception_set(PLy_exc_error,
+							  "unrecognized error in PLy_spi_execute_plan");
 		/* XXX this oughta be replaced with errcontext mechanism */
-		PLy_elog(WARNING, "in function %s:",
+		PLy_elog(WARNING, "in PL/Python function \"%s\"",
 				 PLy_procedure_name(PLy_curr_procedure));
 		return NULL;
 	}
@@ -2648,10 +2656,10 @@ PLy_spi_execute_query(char *query, long limit)
 		PLy_error_in_progress = CopyErrorData();
 		FlushErrorState();
 		if (!PyErr_Occurred())
-			PyErr_SetString(PLy_exc_spi_error,
-							"Unknown error in PLy_spi_execute_query");
+			PLy_exception_set(PLy_exc_spi_error,
+							  "unrecognized error in PLy_spi_execute_query");
 		/* XXX this oughta be replaced with errcontext mechanism */
-		PLy_elog(WARNING, "in function %s:",
+		PLy_elog(WARNING, "in PL/Python function \"%s\"",
 				 PLy_procedure_name(PLy_curr_procedure));
 		return NULL;
 	}
@@ -2719,8 +2727,8 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
 			PLy_error_in_progress = CopyErrorData();
 			FlushErrorState();
 			if (!PyErr_Occurred())
-				PyErr_SetString(PLy_exc_error,
-							"Unknown error in PLy_spi_execute_fetch_result");
+				PLy_exception_set(PLy_exc_error,
+								  "unrecognized error in PLy_spi_execute_fetch_result");
 			Py_DECREF(result);
 			PLy_typeinfo_dealloc(&args);
 			return NULL;
@@ -2771,7 +2779,7 @@ PLy_init_interp(void)
 
 	mainmod = PyImport_AddModule("__main__");
 	if (mainmod == NULL || PyErr_Occurred())
-		PLy_elog(ERROR, "could not import \"__main__\" module.");
+		PLy_elog(ERROR, "could not import \"__main__\" module");
 	Py_INCREF(mainmod);
 	PLy_interp_globals = PyModule_GetDict(mainmod);
 	PLy_interp_safe_globals = PyDict_New();
@@ -2794,9 +2802,9 @@ PLy_init_plpy(void)
 	 * initialize plpy module
 	 */
 	if (PyType_Ready(&PLy_PlanType) < 0)
-		elog(ERROR, "could not init PLy_PlanType");
+		elog(ERROR, "could not initialize PLy_PlanType");
 	if (PyType_Ready(&PLy_ResultType) < 0)
-		elog(ERROR, "could not init PLy_ResultType");
+		elog(ERROR, "could not initialize PLy_ResultType");
 
 	plpy = Py_InitModule("plpy", PLy_methods);
 	plpy_dict = PyModule_GetDict(plpy);
@@ -2818,7 +2826,7 @@ PLy_init_plpy(void)
 	plpy_mod = PyImport_AddModule("plpy");
 	PyDict_SetItemString(main_dict, "plpy", plpy_mod);
 	if (PyErr_Occurred())
-		elog(ERROR, "could not init plpy");
+		elog(ERROR, "could not initialize plpy");
 }
 
 /* the python interface to the elog function
@@ -2880,7 +2888,7 @@ PLy_output(volatile int level, PyObject * self, PyObject * args)
 	if (so == NULL || ((sv = PyString_AsString(so)) == NULL))
 	{
 		level = ERROR;
-		sv = "could not parse error message in `plpy.elog'";
+		sv = dgettext(TEXTDOMAIN, "could not parse error message in plpy.elog");
 	}
 
 	oldcontext = CurrentMemoryContext;
@@ -2940,7 +2948,7 @@ PLy_exception_set(PyObject * exc, const char *fmt,...)
 	va_list		ap;
 
 	va_start(ap, fmt);
-	vsnprintf(buf, sizeof(buf), fmt, ap);
+	vsnprintf(buf, sizeof(buf), dgettext(TEXTDOMAIN, fmt), ap);
 	va_end(ap);
 
 	PyErr_SetString(exc, buf);
@@ -2966,7 +2974,7 @@ PLy_elog(int elevel, const char *fmt,...)
 		bool		success;
 
 		va_start(ap, fmt);
-		success = appendStringInfoVA(&emsg, fmt, ap);
+		success = appendStringInfoVA(&emsg, dgettext(TEXTDOMAIN, fmt), ap);
 		va_end(ap);
 		if (success)
 			break;
@@ -2976,7 +2984,7 @@ PLy_elog(int elevel, const char *fmt,...)
 	PG_TRY();
 	{
 		ereport(elevel,
-				(errmsg("plpython: %s", emsg.data),
+				(errmsg("PL/Python: %s", emsg.data),
 				 (xmsg) ? errdetail("%s", xmsg) : 0));
 	}
 	PG_CATCH();
@@ -3026,7 +3034,7 @@ PLy_traceback(int *xlevel)
 	if (v && ((vob = PyObject_Str(v)) != NULL))
 		vstr = PyString_AsString(vob);
 	else
-		vstr = "Unknown";
+		vstr = "unknown";
 
 	/*
 	 * I'm not sure what to do if eob is NULL here -- we can't call PLy_elog
@@ -3034,7 +3042,7 @@ PLy_traceback(int *xlevel)
 	 * recursion.  I'm not even sure if eob could be NULL here -- would an
 	 * Assert() be more appropriate?
 	 */
-	estr = eob ? PyString_AsString(eob) : "Unknown Exception";
+	estr = eob ? PyString_AsString(eob) : "unrecognized exception";
 	initStringInfo(&xstr);
 	appendStringInfo(&xstr, "%s: %s", estr, vstr);