Twisted Internationalization I'm not particularly Python savy and recently wrote a LocalizationEngine for Twisted.

The strategy I implemented was to make a dictionary from base.json and then merge with any existing files set in the Accept-Language set in the URL (or cookie). For instance the Accept-Language of en-US,en;q=0.8,es;q=0.6 would merge base.json, en.json, en-US.json in that order. The folder layout looks like this:



from twisted.web import resource, server, static, error as http_error
import json
import os

## load the JSON resource from the path and return the parse obj (dict in this case)
def getJSON(path):
  file = open(path)
  data = json.load(file)
  file.close()
  return data

class LocalizationEngine(resource.Resource):
  isLeaf = True
  localePath = "static/lang/"

  def __init__(self, prefix):
    pass

  def render_GET(self, request):
    return self.getLocale(request)

  def getLocale(self, request):
    """
    Request a localization and respond with json object of appropriate locale
    """
    setLocales = request.getCookie("i18n") #preferred locale (todo implement)?
    locales = []
    if setLocales:
      locales = json.load(setLocales)
    else:
      lang_header = request.headers.get("Accept-Language", "en") # for example en-US,en;q=0.8,es;q=0.6
      locales = [locale.split(';')[0] for locale in lang_header.split(',')]

    basePath = self.localePath + (request.args.get("path", [""])[0])
    if not basePath.endswith("/"):
      basePath += "/"

    if not os.path.exists(basePath):
      raise http_error.NoResource().render(request)

    lang = getJSON(basePath + "base.json")

    # reverse so specificity overrides
    for locale in reversed(locales):
      path = basePath + locale + ".json"
      if os.path.exists(path):
        lang.update(getJSON(path))

    cache(request)
    request.write(json.dumps(lang))
    request.finish()
    return True


cache.py

from wsgiref.handlers import format_date_time as format_date
from datetime import date, timedelta
from time import mktime

'''
   Sets the cache headers for a (static resource) request
'''
def cache(request, expires=30, public=True):
    #set expires header
    expiry = (date.today() + timedelta(expires)).timetuple()
    request.responseHeaders.setRawHeaders("expires" , [format_date(mktime(expiry))])

    #set cache control
    cache_control = "max-age=" + str(int(60*60*24*expires))
    if public:
        cache_control += ", public"
    else:
        cache_control += ", private"
    request.responseHeaders.setRawHeaders("cache-control", [cache_control])

    return request


A code review of the above implementation or suggesting an existing Twisted/Python Internationalization implementation (couldn't find one) would be great answers :)
I haven't worked with Twisted, 
and also cannot recommend existing internationalization implementations,
but I can code review in terms of Python in general.

You are not following PEP8,
the official coding style guide of Python.
The coding style violations are not so bad but they are noticeable.
I won't comment on those one by one,
I suggest to give the doc a good read and follow it.

It's nice that you documented this method with a comment:


## load the JSON resource from the path and return the parse obj (dict in this case)
def getJSON(path):
  file = open(path)
  data = json.load(file)
  file.close()
  return data



Why not go all the way and document with a proper docstring?
Also, closing files manually is old-fashioned. 
The recommend way is simpler and better:

def getJSON(path):
    """
    load the JSON resource from the path and return the parse obj (dict in this case)

    @param path: JSON file to parse
    @return: parsed object as a dict
    """
    with open(path) as fh:
        return json.load(fh)


In this code, the initialization of locales = [] is unnecessary,
because you assign to the variable in both branches of the if, so you can remove it:


    locales = []
    if setLocales:
      locales = json.load(setLocales)
    else:
      lang_header = request.headers.get("Accept-Language", "en") # for example en-US,en;q=0.8,es;q=0.6
      locales = [locale.split(';')[0] for locale in lang_header.split(',')]