diff --git a/swift/__init__.py b/swift/__init__.py index 0951da7e4b..7e8fb7b8dc 100644 --- a/swift/__init__.py +++ b/swift/__init__.py @@ -13,9 +13,20 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os +import gettext + import pbr.version _version_info = pbr.version.VersionInfo('swift') __version__ = _version_info.release_string() __canonical_version__ = _version_info.version_string() + + +_localedir = os.environ.get('SWIFT_LOCALEDIR') +_t = gettext.translation('swift', localedir=_localedir, fallback=True) + + +def gettext_(msg): + return _t.gettext(msg) diff --git a/swift/account/auditor.py b/swift/account/auditor.py index 2be0c96ebf..ecb799f6dd 100644 --- a/swift/account/auditor.py +++ b/swift/account/auditor.py @@ -15,7 +15,7 @@ import os import time -from gettext import gettext as _ +from swift import gettext_ as _ from random import random import swift.common.db diff --git a/swift/account/reaper.py b/swift/account/reaper.py index ef42afa1d1..8df2758b7b 100644 --- a/swift/account/reaper.py +++ b/swift/account/reaper.py @@ -15,7 +15,7 @@ import os import random -from gettext import gettext as _ +from swift import gettext_ as _ from logging import DEBUG from math import sqrt from time import time, ctime diff --git a/swift/account/server.py b/swift/account/server.py index 4e7f54dc9e..dc4154cb39 100644 --- a/swift/account/server.py +++ b/swift/account/server.py @@ -18,7 +18,7 @@ from __future__ import with_statement import os import time import traceback -from gettext import gettext as _ +from swift import gettext_ as _ from eventlet import Timeout diff --git a/swift/common/bench.py b/swift/common/bench.py index 97d80488d9..98066959e6 100644 --- a/swift/common/bench.py +++ b/swift/common/bench.py @@ -22,7 +22,7 @@ import signal import socket import logging from contextlib import contextmanager -from gettext import gettext as _ +from swift import gettext_ as _ from optparse import Values import eventlet diff --git a/swift/common/bufferedhttp.py b/swift/common/bufferedhttp.py index b302acf1f1..b16147c811 100644 --- a/swift/common/bufferedhttp.py +++ b/swift/common/bufferedhttp.py @@ -26,7 +26,7 @@ BufferedHTTPResponse. make all calls through httplib. """ -from gettext import gettext as _ +from swift import gettext_ as _ from urllib import quote import logging import time diff --git a/swift/common/db.py b/swift/common/db.py index 43c1571405..0027ca820c 100644 --- a/swift/common/db.py +++ b/swift/common/db.py @@ -25,7 +25,7 @@ import sys import time import cPickle as pickle import errno -from gettext import gettext as _ +from swift import gettext_ as _ from tempfile import mkstemp from eventlet import sleep, Timeout diff --git a/swift/common/db_replicator.py b/swift/common/db_replicator.py index 41904e027b..32fe485c8d 100644 --- a/swift/common/db_replicator.py +++ b/swift/common/db_replicator.py @@ -22,7 +22,7 @@ import shutil import uuid import errno import re -from gettext import gettext as _ +from swift import gettext_ as _ from eventlet import GreenPool, sleep, Timeout from eventlet.green import subprocess diff --git a/swift/common/internal_client.py b/swift/common/internal_client.py index 32f6af4553..e56f391695 100644 --- a/swift/common/internal_client.py +++ b/swift/common/internal_client.py @@ -19,7 +19,7 @@ from paste.deploy import loadapp import struct from sys import exc_info import zlib -from gettext import gettext as _ +from swift import gettext_ as _ from zlib import compressobj from swift.common.utils import quote diff --git a/swift/common/manager.py b/swift/common/manager.py index b080da6f8b..9e47afdcd7 100644 --- a/swift/common/manager.py +++ b/swift/common/manager.py @@ -22,7 +22,7 @@ import signal import time import subprocess import re -from gettext import gettext as _ +from swift import gettext_ as _ from swift.common.utils import search_tree, remove_file, write_file diff --git a/swift/common/memcached.py b/swift/common/memcached.py index 3e5eb13afd..9c5f96d487 100644 --- a/swift/common/memcached.py +++ b/swift/common/memcached.py @@ -49,7 +49,7 @@ import logging import socket import time from bisect import bisect -from gettext import gettext as _ +from swift import gettext_ as _ from hashlib import md5 from swift.common.utils import json diff --git a/swift/common/middleware/catch_errors.py b/swift/common/middleware/catch_errors.py index 1141a2f30f..496e0a09a0 100644 --- a/swift/common/middleware/catch_errors.py +++ b/swift/common/middleware/catch_errors.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from gettext import gettext as _ +from swift import gettext_ as _ from eventlet import Timeout from swift.common.swob import Request, HTTPServerError diff --git a/swift/common/middleware/cname_lookup.py b/swift/common/middleware/cname_lookup.py index 3db5752e4b..883b255ad2 100644 --- a/swift/common/middleware/cname_lookup.py +++ b/swift/common/middleware/cname_lookup.py @@ -28,7 +28,7 @@ rewritten and the request is passed further down the WSGI chain. """ import socket -from gettext import gettext as _ +from swift import gettext_ as _ try: import dns.resolver diff --git a/swift/common/middleware/ratelimit.py b/swift/common/middleware/ratelimit.py index e22dd5d5f3..56efb411be 100644 --- a/swift/common/middleware/ratelimit.py +++ b/swift/common/middleware/ratelimit.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import time -from gettext import gettext as _ +from swift import gettext_ as _ import eventlet diff --git a/swift/common/middleware/recon.py b/swift/common/middleware/recon.py index 504c6e0831..0ecf1ad13a 100644 --- a/swift/common/middleware/recon.py +++ b/swift/common/middleware/recon.py @@ -15,7 +15,7 @@ import errno import os -from gettext import gettext as _ +from swift import gettext_ as _ from swift import __version__ as swiftver from swift.common.swob import Request, Response diff --git a/swift/common/utils.py b/swift/common/utils.py index f4bf82224f..bb6cbe8c42 100644 --- a/swift/common/utils.py +++ b/swift/common/utils.py @@ -30,7 +30,6 @@ from hashlib import md5 from random import random, shuffle from urllib import quote as _quote from contextlib import contextmanager, closing -from gettext import gettext as _ import ctypes import ctypes.util from ConfigParser import ConfigParser, NoSectionError, NoOptionError, \ @@ -58,6 +57,7 @@ import codecs utf8_decoder = codecs.getdecoder('utf-8') utf8_encoder = codecs.getencoder('utf-8') +from swift import gettext_ as _ from swift.common.exceptions import LockTimeout, MessageTimeout from swift.common.http import is_success, is_redirection, HTTP_NOT_FOUND diff --git a/swift/common/wsgi.py b/swift/common/wsgi.py index 4d40602fbf..d8f7d3bcec 100644 --- a/swift/common/wsgi.py +++ b/swift/common/wsgi.py @@ -20,7 +20,7 @@ import os import signal import time import mimetools -from gettext import gettext as _ +from swift import gettext_ as _ from itertools import chain from StringIO import StringIO diff --git a/swift/container/auditor.py b/swift/container/auditor.py index 6c5b3e5bb0..6da9f602b6 100644 --- a/swift/container/auditor.py +++ b/swift/container/auditor.py @@ -15,7 +15,7 @@ import os import time -from gettext import gettext as _ +from swift import gettext_ as _ from random import random from eventlet import Timeout diff --git a/swift/container/server.py b/swift/container/server.py index 0960e5dac0..8c089fdf95 100644 --- a/swift/container/server.py +++ b/swift/container/server.py @@ -19,7 +19,7 @@ import os import time import traceback from datetime import datetime -from gettext import gettext as _ +from swift import gettext_ as _ from xml.etree.cElementTree import Element, SubElement, tostring from eventlet import Timeout diff --git a/swift/container/sync.py b/swift/container/sync.py index 0272174ea4..7125db3a3f 100644 --- a/swift/container/sync.py +++ b/swift/container/sync.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from gettext import gettext as _ +from swift import gettext_ as _ from time import ctime, time from random import random, shuffle from struct import unpack_from diff --git a/swift/container/updater.py b/swift/container/updater.py index bdc1696ec7..552f5145d6 100644 --- a/swift/container/updater.py +++ b/swift/container/updater.py @@ -18,7 +18,7 @@ import os import signal import sys import time -from gettext import gettext as _ +from swift import gettext_ as _ from random import random, shuffle from tempfile import mkstemp diff --git a/swift/obj/auditor.py b/swift/obj/auditor.py index 76e6d1106d..7468d80ee7 100644 --- a/swift/obj/auditor.py +++ b/swift/obj/auditor.py @@ -15,7 +15,7 @@ import os import time -from gettext import gettext as _ +from swift import gettext_ as _ from eventlet import Timeout diff --git a/swift/obj/diskfile.py b/swift/obj/diskfile.py index 6f993cd481..80d806f265 100644 --- a/swift/obj/diskfile.py +++ b/swift/obj/diskfile.py @@ -24,7 +24,6 @@ import uuid import hashlib import logging import traceback -from gettext import gettext as _ from os.path import basename, dirname, exists, getmtime, getsize, join from tempfile import mkstemp from contextlib import contextmanager @@ -32,6 +31,7 @@ from contextlib import contextmanager from xattr import getxattr, setxattr from eventlet import Timeout +from swift import gettext_ as _ from swift.common.constraints import check_mount from swift.common.utils import mkdirs, normalize_timestamp, \ storage_directory, hash_path, renamer, fallocate, fsync, \ diff --git a/swift/obj/expirer.py b/swift/obj/expirer.py index 9928520d71..6741ae1e50 100644 --- a/swift/obj/expirer.py +++ b/swift/obj/expirer.py @@ -17,7 +17,7 @@ import urllib from random import random from time import time from os.path import join -from gettext import gettext as _ +from swift import gettext_ as _ import hashlib from eventlet import sleep, Timeout diff --git a/swift/obj/replicator.py b/swift/obj/replicator.py index 2f76057601..61c3ddc74d 100644 --- a/swift/obj/replicator.py +++ b/swift/obj/replicator.py @@ -20,7 +20,7 @@ import shutil import time import itertools import cPickle as pickle -from gettext import gettext as _ +from swift import gettext_ as _ import eventlet from eventlet import GreenPool, tpool, Timeout, sleep, hubs diff --git a/swift/obj/server.py b/swift/obj/server.py index 1b1513bf7c..d93384f0b7 100644 --- a/swift/obj/server.py +++ b/swift/obj/server.py @@ -22,7 +22,7 @@ import time import traceback from collections import defaultdict from datetime import datetime -from gettext import gettext as _ +from swift import gettext_ as _ from hashlib import md5 from eventlet import sleep, Timeout diff --git a/swift/obj/updater.py b/swift/obj/updater.py index 97c6a2c3c8..857966fb90 100644 --- a/swift/obj/updater.py +++ b/swift/obj/updater.py @@ -18,7 +18,7 @@ import os import signal import sys import time -from gettext import gettext as _ +from swift import gettext_ as _ from random import random from eventlet import patcher, Timeout diff --git a/swift/proxy/controllers/account.py b/swift/proxy/controllers/account.py index d0cffddc4f..cc1ce41f05 100644 --- a/swift/proxy/controllers/account.py +++ b/swift/proxy/controllers/account.py @@ -24,7 +24,7 @@ # These shenanigans are to ensure all related objects can be garbage # collected. We've seen objects hang around forever otherwise. -from gettext import gettext as _ +from swift import gettext_ as _ from urllib import unquote from swift.account.utils import account_listing_response diff --git a/swift/proxy/controllers/base.py b/swift/proxy/controllers/base.py index 63fecb5d03..1e0b7146da 100644 --- a/swift/proxy/controllers/base.py +++ b/swift/proxy/controllers/base.py @@ -29,7 +29,7 @@ import time import functools import inspect import itertools -from gettext import gettext as _ +from swift import gettext_ as _ from urllib import quote from eventlet import spawn_n, GreenPile diff --git a/swift/proxy/controllers/container.py b/swift/proxy/controllers/container.py index a20a782452..e282e869fb 100644 --- a/swift/proxy/controllers/container.py +++ b/swift/proxy/controllers/container.py @@ -24,7 +24,7 @@ # These shenanigans are to ensure all related objects can be garbage # collected. We've seen objects hang around forever otherwise. -from gettext import gettext as _ +from swift import gettext_ as _ from urllib import unquote from swift.common.utils import public, csv_append diff --git a/swift/proxy/controllers/obj.py b/swift/proxy/controllers/obj.py index bd18b106f8..09e4016e46 100644 --- a/swift/proxy/controllers/obj.py +++ b/swift/proxy/controllers/obj.py @@ -29,7 +29,7 @@ import mimetypes import re import time from datetime import datetime -from gettext import gettext as _ +from swift import gettext_ as _ from urllib import unquote, quote from hashlib import md5 diff --git a/swift/proxy/server.py b/swift/proxy/server.py index b71015db73..57854ddaa8 100644 --- a/swift/proxy/server.py +++ b/swift/proxy/server.py @@ -26,7 +26,7 @@ import mimetypes import os -from gettext import gettext as _ +from swift import gettext_ as _ from random import shuffle from time import time diff --git a/test/__init__.py b/test/__init__.py index d32ca6088f..98d0b42ecd 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -16,13 +16,14 @@ # See http://code.google.com/p/python-nose/issues/detail?id=373 # The code below enables nosetests to work with i18n _() blocks -import __builtin__ import sys import os -from swift.common.utils import readconf +# make unittests pass on all locale +import swift +setattr(swift, 'gettext_', lambda x: x) -setattr(__builtin__, '_', lambda x: x) +from swift.common.utils import readconf # Work around what seems to be a Python bug. diff --git a/test/unit/locale/README b/test/unit/locale/README new file mode 100644 index 0000000000..aa1a15cae1 --- /dev/null +++ b/test/unit/locale/README @@ -0,0 +1,3 @@ +rebuild the .mo with msgfmt (included with GNU gettext) + + msgfmt eo.po diff --git a/test/unit/locale/__init__.py b/test/unit/locale/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/unit/locale/eo.po b/test/unit/locale/eo.po new file mode 100644 index 0000000000..aeafb074cf --- /dev/null +++ b/test/unit/locale/eo.po @@ -0,0 +1,2 @@ +msgid "test message" +msgstr "testo mesaĝon" diff --git a/test/unit/locale/eo/LC_MESSAGES/swift.mo b/test/unit/locale/eo/LC_MESSAGES/swift.mo new file mode 120000 index 0000000000..47fa4e6c7f --- /dev/null +++ b/test/unit/locale/eo/LC_MESSAGES/swift.mo @@ -0,0 +1 @@ +../../messages.mo \ No newline at end of file diff --git a/test/unit/locale/messages.mo b/test/unit/locale/messages.mo new file mode 100644 index 0000000000..4c8fcc0b29 Binary files /dev/null and b/test/unit/locale/messages.mo differ diff --git a/test/unit/locale/test_locale.py b/test/unit/locale/test_locale.py new file mode 100644 index 0000000000..75ff5e5f15 --- /dev/null +++ b/test/unit/locale/test_locale.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +import os +import unittest + +try: + from subprocess import check_output +except ImportError: + from subprocess import Popen, PIPE, CalledProcessError + + def check_output(*popenargs, **kwargs): + """Lifted from python 2.7 stdlib.""" + if 'stdout' in kwargs: + raise ValueError('stdout argument not allowed, it will be ' + 'overridden.') + process = Popen(stdout=PIPE, *popenargs, **kwargs) + output, unused_err = process.communicate() + retcode = process.poll() + if retcode: + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + raise CalledProcessError(retcode, cmd, output=output) + return output + + +os.environ['LC_ALL'] = 'eo' +os.environ['SWIFT_LOCALEDIR'] = os.path.dirname(__file__) +from swift import gettext_ as _ + + +class TestTranslations(unittest.TestCase): + + def test_translations(self): + translated_message = check_output(['python', __file__]) + self.assertEquals(translated_message, 'testo mesaĝon\n') + + +if __name__ == "__main__": + print _('test message')