I18n objects are used to internationalize content that cannot be translated via messages. The problem is three fold:
The first two problems are very similar and can actually share the same interface for the language negotiation and redirection of the content request. I would therefore propose to have a II18nContent interface that somehow specifies how to get to the translated content and then redirect the call to the correct local content.
There will be an interface called II18nObject (which inherits I18nContent of course), which is a chameleon-like container, as it adapts to the properties of the contained object type. In order to accomplish all this, you will have to implement your own traverser which looks up the correct subobject.
This object will basically provide an internationalized version of zope.app.annotation.attribute.AttributeAnnotations, which will be accomplished in a similar manner as the I18nObject.
One issue left to solve is how to know the language when we need to make the decision. These objects are not Views, therefore they do not know about the request variable.
One way to solve the issue would be that I18nAttributeAnnotation, for example, would not actually implement the IAnnotations interface, but that there would be an Adapter converting the II18nAnnotations to IAnnotations. Since adapters are short-lived (meaning they are initialized for a particular call), we can safely store some language information in them in order to make the language decision.