i18next / ng-i18next

translation for AngularJS using i18next
https://github.com/i18next/ng-i18next
MIT License
161 stars 54 forks source link

ng-i18next cloak #30

Closed Soviut closed 10 years ago

Soviut commented 10 years ago

When you reload a page quickly, you can sometimes see the placeholder translation keys before the language file has had a chance to load.

I'd recommend a directive similar to ng-cloak to allow the page, or elements on it, to stay hidden until translations have loaded.

bugwelle commented 10 years ago

Hello, thanks for that idea. Currently I'm busy, so I don't have time to implement this. But if you would like to write such a directive, I'll merge it. :) I'll look on this next week again.

Regards, Andre

Soviut commented 10 years ago

Here's what I wrote in CoffeeScript for my current project:

app = angular.module 'App'
app.directive 'i18nextCloak', ($rootScope, $i18next, $q) ->
    restrict: 'A'
    link: (scope, el, attr) ->
        defer = $q.defer()
        $rootScope.$on 'i18nextLanguageChange', (lng) -> defer.resolve()
        defer.promise.then -> el.removeClass 'i18next-cloak'

I use a promise as a sort of "debounce" because the i18nextLanguageChange event fires more than once. I also went the simplest route and only worried about the class that the directive auto-generates. So my corresponding CSS looks like:

.i18next-cloak {
    display: none !important;
}
Soviut commented 10 years ago

@archer96 Is there any event that can be used to determine if the digest cycle is complete? the i18nextLanguageChange event can fire before the digest is complete and the i18next keys can sometimes still be visible.

Soviut commented 10 years ago

@archer96 From what I can gather from the source, it might be a good idea for the $i18next provider to keep track of how many directives and filters have been registered. Since providers are singletons, an integer could be incremented each time a directive is linked or a filter is returned. Then just count up as the $i18next function is called and broadcast a completion event.

masterpoi commented 10 years ago

I use

if($rootScope.$$phase)

to detect if angular is in a digest loop.

bugwelle commented 10 years ago

Hello, I'm really sorry that it took so long. I added an example of how you could do something like i18nextCloak yourself. Please see:

i18nextLanguageChange fires when i18next has loaded (you have to configure ng-i18next first)

Please let me know if this works for you. I'll close this for now :)

Regards, Andre

Soviut commented 10 years ago

Interesting. I actually wound up doing an interval that checks to see if a hidden element has had its text changed. If a simple $timeout to wait for a digest cycle works then that's way more elegant.

bugwelle commented 10 years ago

Oh, well, the timeout is just there to show the hide/show progresss. You don't have to do that. :)

Soviut commented 10 years ago

Right, but $timeout forces the code within it to be evaluated on a future digest cycle. So if this works, no actual time would be necessary and the following would work.

    $scope.i18nextReady = false;
    $scope.$on('i18nextLanguageChange', function () {
        if (!$scope.i18nextReady) {
            $timeout(function () {
                $scope.i18nextReady = true;
            }); // no time set
        }
    });

I'm just want to confirm that the 500 ms isn't just a cheat.

bugwelle commented 10 years ago

Ah, now I understand what you want :) What about $apply or $digest? (I haven't tested that)