That basically means any runtime except edX will need to reimplement a translation pipeline from scratch. :) Probably a templating service also, because every XBlock I've seen so far makes liberal use of Django templates, can't work without them, and therefore can't truly be platform-agnostic. Exposing mako as a service (or better yet, defining a self-contained templating service just for XBlocks to use) might be a good idea, the problem here is that templates contain the grand majority of strings requiring translation, so this would require some i18n service implementation too...
I'm pretty sure Django's own translation framework can be cheated by altering settings.LOCALE_PATHS at runtime, as long as django.utils.translations is imported after that happens, (knowing Django and it's magic, though, I'd have to experiment to be completely sure, but I'll try to set something up soon) and the actual location of the files can be anything, as long as they follow the pattern "<locale id>/LC_MESSAGES/django.mo" -- deviating from this pattern would involve either monkeypatching or rewriting. (The 'django' name is hardcoded, everything else is how GNU gettext likes it, and everyone on Earth uses gettext anyway.) Such an implementation seems easy enough to make, and I think it should also affect javascript translations, as long as settings.LOCALE_PATHS is altered globally. (django.views.i18n.javascript_catalog view checks it on every call, and the request would happen when javascript first runs. The translation service would need to supply the url to the XBlock for it to get used. Maybe this is better dealt with somewhere in javascript runtime? All XBlocks would want to use that, too...) Keeping the 'django' and 'djangojs' filenames hardcoded sounds a bit silly, but as long it's acceptable, it can be left as a problem for other implementations to circumvent with whatever translation machinery they have available. (Pylons has no hardcoded names, Flask-Babel actually consumes every .mo it finds and ignores the names -- so I guess the other Python frameworks will mostly be ok with it, Django is just the odd one out.)
The smoothest way would be to run this somewhere in the @XBlock.needs decorator, so that it fires early, giving a parameter to the service like so: @XBlock.needs("i18n",["path","path","path"]) -- i.e. explicitly tell the service where our locale files are, which would put the least restrictions on the internal structure of the XBlock. Which implies that the decorator needs to try to call something to initialise the service for a particular XBlock, which it doesn't currently do, and looking at the code in the XBlock repository, I'm not sure it should. I.e. it should probably work like this:
class WhateverBlock(XBlock):
_ = None
def __init__(self):
i18n_service = self.runtime.service(self,"i18n")
i18n_service.add_locale_files(["path","path","path"])
self._ = i18n_service.ugettext
# I'm not sure if def _(self) will work, because then there's no guarantee it doesn't race the LOCALE_PATHS change.