Don't know if it's a design choice, but in https://github.com/web2py/web2py/blob/master/gluon/html.py#L119 and following there are typechecks for str and unicode, but you're trying to use a T something for it, so it doesn't trigger properly.... T objects (and LazyT ones) have an xml() attribute, so the escaping is not reached and instead it's returned the xml() property of T, that is a string representation in the case of simple translations.
Until now data-* attributes were never really used, but I see a lot of patterns now that may require something like this. Let's see if someone comes up with a possible countereffect (markmin translations maybe ?), otherwise I'd say let's fix it in html.py --