diff -r 7f122a63dc17 Include/pyerrors.h --- a/Include/pyerrors.h Sun Oct 28 01:35:53 2012 -0300 +++ b/Include/pyerrors.h Sun Oct 28 03:47:23 2012 -0300 @@ -236,7 +236,7 @@ PyAPI_FUNC(PyObject *) PyErr_Format( PyObject *exception, - const char *format, /* ASCII-encoded string */ + const char *format, /* UTF-8 encoded string */ ... ); diff -r 7f122a63dc17 Include/pyi18n.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Include/pyi18n.h Sun Oct 28 03:47:23 2012 -0300 @@ -0,0 +1,48 @@ +#ifndef Py_I18N_H +#define Py_I18N_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Must be before gettext() games below */ +#if defined(HAVE_LANGINFO_H) +#include +#endif + +/* Internal Internationalization Interface */ + +#ifdef HAVE_LIBINTL_H +#include +#else +/* + * Fallback when gettext is not available + */ +#define gettext(x) (x) +#define dgettext(d,x) (x) +#define ngettext(s,p,n) ((n) == 1 ? (s) : (p)) +#define dngettext(d,s,p,n) ((n) == 1 ? (s) : (p)) +#endif + +/* Py_GETTEXT should be used inside python interpreter and extension libraries + * to get a message translation for the domain "python" + * use cases are exception messages, tracebacks, etc. + */ + +#define Py_GETTEXT(msgid) dgettext("python", msgid) + +/* + * Use this to mark string constants as needing translation at some later + * time, rather than immediately. This is useful for cases where you need + * access to the original string and translated string, and for cases where + * immediate translation is not possible, like when initializing global + * variables. + * http://www.gnu.org/software/autoconf/manual/gettext/Special-cases.html + */ +#define Py_GETTEXT_noop(x) (x) + + +/* --- */ +#ifdef __cplusplus +} +#endif +#endif /* !Py_I18N_H */ diff -r 7f122a63dc17 Lib/site.py --- a/Lib/site.py Sun Oct 28 01:35:53 2012 -0300 +++ b/Lib/site.py Sun Oct 28 03:47:23 2012 -0300 @@ -476,6 +476,14 @@ encodings.aliases.aliases[enc] = 'mbcs' +def seti18n(): + "Initialize internationalization (python domain path)" + import sysconfig + import locale + locale.bindtextdomain("python", sysconfig._safe_realpath("Locale")) + #locale.setlocale(locale.LC_MESSAGES,'es_AR.utf8') + + CONFIG_LINE = re.compile(r'^(?P(\w|[-_])+)\s*=\s*(?P.*)\s*$') def venv(known_paths): @@ -582,6 +590,7 @@ setcopyright() sethelper() aliasmbcs() + seti18n() execsitecustomize() if ENABLE_USER_SITE: execusercustomize() diff -r 7f122a63dc17 Lib/test/test_i18n.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/test/test_i18n.py Sun Oct 28 03:47:23 2012 -0300 @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- + +import locale +import gettext +import sys +import sysconfig +import os +import unittest +import warnings +from test import support, string_tests + +LOCALE_DIR = sysconfig._safe_realpath("Locale") + +class InternationalizationTest(unittest.TestCase): + + def setUp(self): + # bind locales for internal cpython (locale module) + ok = locale.bindtextdomain("python", LOCALE_DIR) + if not ok: + raise RuntimeError("cannot bind textdomain!") + + def test_textdomain_codeset(self): + # Ensure codeset is utf-8 (as used internally by cpython) + # http://www.gnu.org/software/gettext/manual/gettext.html#Charset-conversion * + + charset = locale.bind_textdomain_codeset("python","utf8") + self.assertEqual(charset, 'utf8') + + def test_untranslated(self): + locale.setlocale(locale.LC_MESSAGES,'C') + try: + 1/0 + except Exception as e: + self.assertEqual(str(e), 'division by zero') + + def test_translation(self): + locale.setlocale(locale.LC_MESSAGES,'es_AR.utf8') + try: + 1/0 + except Exception as e: + print(e) + self.assertEqual(str(e), 'división por cero') + + +class InternationalizationTest(unittest.TestCase): + + def setUp(self): + # bind locales for python gettext module + ok = gettext.bindtextdomain('python', LOCALE_DIR) + if not ok: + raise RuntimeError("cannot bind textdomain!") + + def test_lang_exists(self): + # translation will raise an exception if mo file is missing + lang = gettext.translation('python', localedir=LOCALE_DIR, languages=['es']) + + def test_gettext(self): + self.assertEqual(gettext.dgettext("python", "division by zero"), + 'división por cero') + self.assertEqual(gettext.dgettext("python", "invalid syntax"), + "sintaxis inválida") + + +def test_main(): + support.run_unittest(__name__) + +if __name__ == "__main__": + test_main() diff -r 7f122a63dc17 Locale/es.po --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Locale/es.po Sun Oct 28 03:47:23 2012 -0300 @@ -0,0 +1,41 @@ +# Spanish message translation file for python +# +# Copyright (C) 2012- Python Software Fundation +# This file is distributed under the same license as the Python package. +# +# Mariano Reingart , 2012 +# +# +msgid "" +msgstr "" +"Project-Id-Version: python (CPython 3.5)\n" +"Report-Msgid-Bugs-To: po-bugs@python.org\n" +"POT-Creation-Date: 2012-10-27 15:52-0300\n" +"PO-Revision-Date: 2012-10-27 15:52-0300\n" +"Last-Translator: Mariano Reingart \n" +"Language-Team: Español <@python.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Traceback (most recent call last):\n" +msgstr "Traza de rastreo (llamada más reciente última):\n" + +msgid " File \"%U\", line %d, in %U\n" +msgstr " Archivo \"%U\", línea %d, en %U\n" + +msgid "invalid syntax" +msgstr "sintaxis inválida" + +msgid "division by zero" +msgstr "división por cero" + +msgid "integer division or modulo by zero" +msgstr "división entera o modulo por cero" + +msgid "name '%.200s' is not defined" +msgstr "nombre '%.200s' no está definido" + +msgid "global name '%.200s' is not defined" +msgstr "nombre global '%.200s' no está definido" + diff -r 7f122a63dc17 Makefile.pre.in --- a/Makefile.pre.in Sun Oct 28 01:35:53 2012 -0300 +++ b/Makefile.pre.in Sun Oct 28 03:47:23 2012 -0300 @@ -799,6 +799,7 @@ $(srcdir)/Include/pydebug.h \ $(srcdir)/Include/pyerrors.h \ $(srcdir)/Include/pyfpe.h \ + $(srcdir)/Include/pyi18n.h \ $(srcdir)/Include/pymath.h \ $(srcdir)/Include/pygetopt.h \ $(srcdir)/Include/pymacro.h \ diff -r 7f122a63dc17 Python/errors.c --- a/Python/errors.c Sun Oct 28 01:35:53 2012 -0300 +++ b/Python/errors.c Sun Oct 28 03:47:23 2012 -0300 @@ -16,6 +16,8 @@ #include +#include "pyi18n.h" + #ifdef __cplusplus extern "C" { #endif @@ -121,7 +123,7 @@ void PyErr_SetString(PyObject *exception, const char *string) { - PyObject *value = PyUnicode_FromString(string); + PyObject *value = PyUnicode_FromString(Py_GETTEXT(string)); PyErr_SetObject(exception, value); Py_XDECREF(value); } @@ -694,7 +696,7 @@ va_start(vargs); #endif - string = PyUnicode_FromFormatV(format, vargs); + string = PyUnicode_FromFormatV(Py_GETTEXT(format), vargs); PyErr_SetObject(exception, string); Py_XDECREF(string); va_end(vargs); diff -r 7f122a63dc17 Python/pythonrun.c --- a/Python/pythonrun.c Sun Oct 28 01:35:53 2012 -0300 +++ b/Python/pythonrun.c Sun Oct 28 03:47:23 2012 -0300 @@ -247,7 +247,7 @@ PyInterpreterState *interp; PyThreadState *tstate; PyObject *bimod, *sysmod, *pstderr; - char *p; + char *p, *codeset; extern void _Py_ReadyTypes(void); if (initialized) @@ -260,6 +260,14 @@ the locale's charset without having to switch locales. */ setlocale(LC_CTYPE, ""); + + /* Ensure codeset is utf-8 (as used internally by cpython) + http://www.gnu.org/software/gettext/manual/gettext.html + #Charset-conversion + */ + codeset = bind_textdomain_codeset("python", "utf8"); + if (codeset == NULL) + Py_FatalError("Py_Initialize: can't bind textdomain codeset (i18n)"); #endif if ((p = Py_GETENV("PYTHONDEBUG")) && *p != '\0') diff -r 7f122a63dc17 Python/traceback.c --- a/Python/traceback.c Sun Oct 28 01:35:53 2012 -0300 +++ b/Python/traceback.c Sun Oct 28 03:47:23 2012 -0300 @@ -7,6 +7,7 @@ #include "frameobject.h" #include "structmember.h" #include "osdefs.h" +#include "pyi18n.h" #ifdef HAVE_FCNTL_H #include #endif @@ -336,7 +337,7 @@ if (filename == NULL || name == NULL) return -1; - line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n", + line = PyUnicode_FromFormat(Py_GETTEXT(" File \"%U\", line %d, in %U\n"), filename, lineno, name); if (line == NULL) return -1; @@ -412,7 +413,7 @@ } PyErr_Restore(exc_type, exc_value, exc_tb); } - err = PyFile_WriteString("Traceback (most recent call last):\n", f); + err = PyFile_WriteString(Py_GETTEXT("Traceback (most recent call last):\n"), f); if (!err) err = tb_printinternal((PyTracebackObject *)v, f, limit); return err;