Sorry, I'm a bit late to this thread. I don't intend to dig the rabbit hole deeper, but I might do. Reading this reminds me of an issue I tried to solve with @mauritsvanrees last year where I wanted a pre-translated portlet title.
plone.api's translate is (or at least was) not a functional equivalent of zope.i18n's translate. See this rather long issue thread if you really want to find out: https://github.com/plone/plone.api/issues/379.
If you want to use defaultFactory and zope.i18n translate, you can inject a translation context, which actually is the request, which you can get from the context... From above discussion on the plone.api issue:
from zope.schema.interfaces import IContextAwareDefaultFactory
# use zope.i18n translate and pass in the request as the translation context
return translate(_(u"Recently Updated Indicators"), context=context.REQUEST)
header = schema.TextLine(title=_("Title"),
I was just looking up the ContextAwareDefault-blah for this post and I found the following snippet in collective.easyform. @hvelarde, maybe this helps with using a message label?
"""Schema for easyform import form.
upload = Bytes(
foo = _(u'default_submitLabel', u'Submit') # dummy msgid for i18ndude to translate # noqa