angular.module('ngLocalize')
    .directive('i18n', function ($sce, locale, localeEvents, localeConf) {
        function setText(elm, tag) {
            if (tag !== elm.html()) {
                elm.html($sce.getTrustedHtml(tag));
            }
        }

        function update(elm, string, optArgs) {
            if (locale.isToken(string)) {
                locale.ready(locale.getPath(string)).then(function () {
                    setText(elm, locale.getString(string, optArgs));
                });
            } else {
                setText(elm, string);
            }
        }

        return function (scope, elm, attrs) {
            var hasObservers;

            attrs.$observe('i18n', function (newVal, oldVal) {
                if (newVal && newVal !== oldVal) {
                    update(elm, newVal, hasObservers); 
                }
            });

            angular.forEach(attrs.$attr, function (attr, normAttr) {
                if (localeConf.observableAttrs.test(attr)) {
                    attrs.$observe(normAttr, function (newVal) {
                        if (newVal || !hasObservers || !hasObservers[normAttr]) {
                            hasObservers = hasObservers || {};
                            hasObservers[normAttr] = attrs[normAttr];
                            update(elm, attrs.i18n, hasObservers);
                        }
                    });
                }
            });

            scope.$on(localeEvents.resourceUpdates, function () {
                update(elm, attrs.i18n, hasObservers);
            });
            scope.$on(localeEvents.localeChanges, function () {
                update(elm, attrs.i18n, hasObservers);
            });
        };
    })
    .directive('i18nAttr', function (locale, localeEvents) {
        return function (scope, elem, attrs) {
            var lastValues = {};

            function updateText(target, attributes) {
                var values = scope.$eval(attributes),
                    langFiles = [],
                    exp;

                for(var key in values) {
                    exp = values[key];
                    if (locale.isToken(exp) && langFiles.indexOf(locale.getPath(exp)) === -1) {
                        langFiles.push(locale.getPath(exp));
                    }
                }

                locale.ready(langFiles).then(function () {
                    var value = '';

                    for(var key in values) {
                        exp = values[key];
                        value = locale.getString(exp);
                        if (lastValues[key] !== value) {
                            attrs.$set(key, lastValues[key] = value);
                        }
                    }
                });
            }

            attrs.$observe('i18nAttr', function (newVal) {
                if (newVal) {
                    updateText(elem, newVal); 
                }
            });

            scope.$on(localeEvents.resourceUpdates, function () {
                updateText(elem, attrs.i18nAttr);
            });
            scope.$on(localeEvents.localeChanges, function () {
                updateText(elem, attrs.i18nAttr);
            });
        };
    });

@@ -2643,19 +2643,37 @@
 rs.$set(
+attrs.$normalize(
 key
+)
 , lastVa

Normalize the attribute key before it is set