Symfony2和Angular.JS之间共享的翻译

我正在寻找一种在Symfony2应用程序和我的Angular.JS应用程序之间共享翻译的好方法,它们是 本质上是相同的应用程序,但是它们的行为却截然不同。</ p>

首先,我已经制定了一个指令,允许在我的angular js app中使用[[variable]]进行模板化,所以我可以使用 来自twig的变量以及我在变量中的变量。</ p>

所以我想要实现的是将我的句子翻译成用户喜欢的本地化。</ p>

所以我的结论是我想使用Symfony的翻译功能,因为在Angular中没有很好的支持。 我还想使用Symfony包含的所有内置功能,这就像自动更新文件,支持YAML等。但我需要弄清楚如何将它们传输到我的JS应用程序以及如何在Symfony中检测它们,所以 两个应用程序都可以使用它们。</ p>

所以我最初的想法:</ p>

更改翻译的捕获或至少添加一个额外的 范围。</ strong> </ p>

{%trans%} Hello [[name]] {%endtrans%} </ code> </ p>

&lt; trans name =“My Name”translation =“Hello [[name]]”/&gt; </ code> </ p>

并且还支持所有其他功能的复数等 。</ p>

然后生成一个具有翻译和复数等的文件。</ p>

通过角度ajax调用请求语言并保存 到客户端的本地存储器。</ strong> </ p>

这将允许我用正确的值替换trans的上面的指令。
这不是设置的问题。 然而,它需要从任何格式导出到角度可以读取的JSON。</ p>

然后需要一个匹配器,并且需要支持多元化和所有其他可用功能。 / p>

其他想法</ strong> </ p>

一般来说,在使用Angular.JS应用程序时不使用Symfony2翻译可能会更好 ,因此只使用角度翻译,否则用Symfony2 Twigs编写并翻译的文本可能不会在Angular中翻译。 但是如果Symfony可以捕获并吐出这些文件,我发现它会更好。</ p>

我认为这需要做一些工作才能变得坚实,但我觉得这个 需要解决。 任何想法和有用的评论都表示赞赏,我正在考虑在GitHub上为此启动一个项目,以便为此提供适当的支持。 但是,如果有这样的话,可能会更好地使用它。</ p>

/ Marcus </ p>
</ div>

展开原文

原文

I am looking for a good way to share my translations between my Symfony2 App and my Angular.JS App, they are essentially the same app, however they act very differently.

First of all I have made a directive to allow for templating using [[ variable ]] in my angular js app, so I can use the variables from twig alongside my variables in angular.

So what I want to achieve is to translate my sentences into the localisation that the user prefers.

So my conclusion is that I want to use the translations features of Symfony, as there is no good support for that in Angular. I also want to use all the built in features that Symfony includes, which is like update the files automatically, support YAML etc. But I need to work out how to transfer them to my JS application and how I can detect them in Symfony, so both applications can use them.

So my initial idea:

Change the capturing of translations or at least add an additional one to the scope.

{% trans %}Hello [[name]]{% endtrans %}

<trans name="My Name" translation="Hello [[name]]" />

And also support all other functionalities with pluralisation etc.

This would then generate a file that has the translations, and pluralisation etc.

Request language through angular ajax call and save this into a local storage on the client side.

This would allow me to replace the directive above of trans with the proper value. This is not a problem to set up. However it needs to be exported from whatever format to JSON that angular can read.

Then there needs to be a matcher, and there needs to be support for pluralisation and all other features available.

Other Ideas

It might be better in general to not use the Symfony2 translations when you do an Angular.JS App, and thereby only use the angular translations, otherwise the text written in Symfony2 Twigs and is translated would probably not be translatable in Angular. But the generation of these files I find it to be better if Symfony could capture and spit out.

I think this needs to be a bit of work to be solid, but I feel that this needs to be solved. Any ideas and helpful comments are appreciated, I am considering to start a project for this on GitHub, to give proper support for this. But if there's such already it might just be better to work with that.

/Marcus

douyan4243
douyan4243 我碰巧看到这个,因为我发布了我的过滤器....可能会帮助你github.com/PascalPrecht/angular-translate
接近 7 年之前 回复
doudou_3636
doudou_3636 不明白你在说什么
接近 7 年之前 回复
doubi2014
doubi2014 我的问题是我希望翻译能够更新,因此下面的解决方案将呈现它们一次,然后需要重新加载页面以供它们更改。我提供的解决方案是有效的,但是下面带有过滤器的解决方案并不能真正完成这项工作。
接近 7 年之前 回复
douxie3625
douxie3625 翻译自定义过滤器jsfiddle.net/4kuhF/1的原始演示
接近 7 年之前 回复
doubian6241
doubian6241 你考虑过有角度的自定义滤镜吗?可以使用它比创建指令<span>{{someVar|翻译}}</跨度>。
接近 7 年之前 回复

4个回答



我结束使用此解决方案。 解决我的所有问题:</ p>

http:/ /cliffmeyers.com/blog/2013/3/11/integration-angularjs </ p>
</ div>

展开原文

原文

I Ended up using this solution. Solves all my problems:

http://cliffmeyers.com/blog/2013/3/11/integration-angularjs



这是一个使用自定义角度过滤器来简化标记的建议</ p>

HTML:</ p>

 &lt; div ng-app =“myApp”ng-controller =“MainCtrl”&gt; 
{{item | translate}}
&lt; / div&gt;
</ code> </ pre>

JS
</ p>

  var words = {
'fr':{'Bus':“AutoBus”}
\ n};

var app = angular.module('myApp',[]);
app.constant('lang','fr');

app.factory('wordService',function(lang) {
return {
getWord:function(val){
return words [lang] [val];
}
}
})
app.filter('translate',function(wordService){\ n return function(val){
return wordService.getWord(val)
}
})

app.controller('MainCtrl',function($ scope){
$ scope.item ='Bus' ;
});
</ code> </ pre>

您可以使用服务从服务器或localStorage请求转换文件(如果它们已存在)。 只需在运行时设置语言。</ p>

您可以以任何适合您的方式重新配置单词对象,以便在两个应用程序中使用它。 </ p>

DEMO </ strong> </ kbd> </ p>
</ div>

展开原文

原文

Here's a suggestion using a custom angular filter to simplify markup

HTML:

<div ng-app="myApp" ng-controller="MainCtrl">
    {{ item |translate }}
</div>

JS

var words={
    'fr': {'Bus': "AutoBus"}  

};

var app = angular.module('myApp', []);
app.constant('lang','fr');

app.factory('wordService',function(lang){   
    return {
        getWord:function(val){
            return words[lang][val];
        }
    }
})
app.filter('translate', function(wordService){
    return function(val){
        return wordService.getWord(val)
    }
})

app.controller('MainCtrl', function($scope) {
  $scope.item = 'Bus';
});

You can ues a service to request the translation file(s) from either server or localStorage if they already exist. Just set language at run time.

You can reconfigure the words object any way that suits you to use it in both applications.

DEMO

douchuitang0331
douchuitang0331 哦,是的,我尝试使用下面的代码进行设置,但是提交承诺会让它崩溃
接近 7 年之前 回复
duanliang789262
duanliang789262 删除手表......不需要,按照我使用的想法
接近 7 年之前 回复
duanliang2017
duanliang2017 仍然没有做到这一点。 浏览器最终无休止地循环:/抱歉这里有这个复杂的问题,但感谢您的耐心,这非常有帮助。
接近 7 年之前 回复
douyin8809
douyin8809 它似乎导致我的过滤器无限循环,也许你对我的承诺有更好的了解,但我已经尝试了一个解决方案,我生成承诺作为我的例子如下,然后尝试访问它如下使用 a .then(function(){}); 也许我需要一个.then(function(){},function(){})之类的东西?
接近 7 年之前 回复
dongzhong6675
dongzhong6675 类似...而不是只设置lang,可以使用延迟和解决延迟与郎
接近 7 年之前 回复
ds000001
ds000001 意识到这不包括最后一个要求,即使用$ q.defer对象作为响应。
接近 7 年之前 回复
dongzhaobai5982
dongzhaobai5982 有趣的是,这几乎是我正在寻找的解决方案。 我更喜欢过滤器的方式,但我在Angular中远没有完全正常运行,这真的很有帮助。 谢谢。
接近 7 年之前 回复
dongzen7263
dongzen7263 同样的事情,但语言按钮的单独控制器jsfiddle.net/4kuhF/3
接近 7 年之前 回复
dongyi3776
dongyi3776 试试这个jsfiddle.net/4kuhF/2太简单了吗?
接近 7 年之前 回复
douyanning3724
douyanning3724 是的,这将是一个很好的解决方案,一直在尝试,但它会导致无限的迭代:/
接近 7 年之前 回复
duanpao6163
duanpao6163 OK ...可以设置事件以观察语言对象。 你想要它,所以用户clciks选择语言?
接近 7 年之前 回复
dou29106
dou29106 好的要求没有得到满足,这仍然是一个问题,要求是你可以注入另一种语言,它将更新翻译。
接近 7 年之前 回复
dtvp3625
dtvp3625 确切地说......创建额外标签的时间也少得多
接近 7 年之前 回复
dpv21589
dpv21589 这是一个非常好的解决方案,可以在任何需要的地方附加其他过滤器等。
接近 7 年之前 回复

Further research

Here is my App:

'use strict';
var myApp = angular.module('myApp', []);

Here is my controller:

'use strict';
myApp.controller('PageController',
    function PageController($scope, translationService, $rootScope) {
        $rootScope.currentLanguage = 'en';
        $rootScope.translations = translationService.getTranslations($scope.currentLanguage);

        $scope.setLanguage = function(language) {
            if (language === $scope.currentLanguage) {
                 return;
            }
            $rootScope.currentLanguage = language;
            $rootScope.translations = translationService.getTranslations($scope.currentLanguage);
        }
    }
);

And here is the translationService:

'use strict';
myApp.service('translationService', function ($http, $q) {
    var translationsCache = {};
    return {
        getTranslations: function(language) {
            if (translationsCache[language]) {
                return translationsCache[language];
            }
            var deferred = $q.defer();
            // **** FAKE SOLUTION **** //
            // I just return a resolve here as it doesn't really matter for this test.
            if (language == 'sv') {
                deferred.resolve({
                    "My first text unit": "Detta är min första text unit",
                    "I am a Pirate": "Jag är en Pirat"
                });
            } else if (language == 'en') {
                deferred.resolve({
                    "My first text unit": "This is my first Text unit",
                    "I am a Pirate": "I'm a Pirate"
                });
            }

            translationsCache[language] = deferred.promise;
            return deferred.promise;
            // **** END FAKE SOLUTION **** //

            /* 
            // **** WORKING SOLUTION **** //
            The probable real solution to fetching language JSON generated by Symfony somewhere
            $http({method: 'GET', url: '/translations/'+language}).
                success(function (data, status, headers, config) {
                    deferred.resolve(data);
                }).
                error(function(data, status, headers, config) {
                    deferred.reject(status);
                });

            translationsCache[language] = deferred.promise;

            return deferred.promise;
            // **** END WORKING SOLUTION **** //
            */
        }
    }
});

So here is my directive that I came up with after some trial and error:

myApp.directive('translation', function($rootScope) {
    return {
        restrict: 'A', // Restrict to attribute
        replace: true, // Replace current object by default, not for input though, see solution below
        link: function(scope, element, attrs, controller){
            // This will watch for changes in currentLanguage in your $rootScope
            scope.$watch(function() {
                return $rootScope.currentLanguage; // If this changes then trigger function (binding)
            }, function(newVal, oldVal) {
                // As we have translation as a promise this is how we do
                $rootScope.translations.then(function(translations) {
                    // Does it exist, then translate it, otherwise use default as fallback
                    if (translations[scope.translation]) {
                        // Just some extra I found could be useful, set value if it is a button or submit. Could be extended.
                        if (element.prop('tagName') === 'INPUT' && (element.prop('type') === 'button' || element.prop('type') === 'submit')) {
                            return angular.element(element).val(translations[scope.translation]);
                        }
                        // Else just change the object to be the new translation.
                        return element.html(translations[scope.translation]);
                    }
                    // This is the fallback, and same as above, button and submit
                    if (element.prop('tagName') === 'INPUT' && (element.prop('type') === 'button' || element.prop('type') === 'submit')) {
                        return element.val(scope.translation);
                    }
                    return element.html(scope.translation);
                });
            });
        },
        scope: {
            translation: "@" // Save the parameter to the scope as a string
        }
    }
});

And here are some examples of how to use it.

HTML:

<div class="container">
    <div class="nav">
        <button ng-click="setLanguage('en')">
            <trans translation="English" />
        </button>
        <button ng-click="setLanguage('sv')">
            <trans translation="Svenska" />
        </button>
    </div>
    <hr />
    <p><trans translation="I am a Pirate" /></p>
    <p><trans translation="A text unit that doesn't exist" /></p>
    <p><input type="button" translation="My button" /></p>
</div>

This would work as following using the jsFiddle: http://jsfiddle.net/Oldek/95AH3/4/

This this solves:

  • Fetch translations asynchronously
  • Cache translations so switch is really fast
  • Working with input / fields with value
  • Store language in Local Storage
  • Dynamically update the whole DOM on translation change
  • Really quick, at least the scale I have tried
  • Full and working solution to a common problem

Things to solve:

  • Move out code that checks if it is an input field somewhere else
  • Pluralisation
  • Input Placeholder
  • And other features a translation supports.
  • Support parameters, see example:

<trans translation="Hello {{name}}" name="{{name}}">

  • Scan the project with xgettext? and generate an YML or similar structure that can be translated in some software.
  • Remove the temporary solution and use the working one commented out.

Other Comments

Please feel free to ask questions if you have, I'll provide info, and probably a jsFiddle some time soon in deemed needed.

/Marcus

So I have come a bit further, and after some research it makes much more sense to use a filter for this action, however I cannot seem to get it working as I intend.

So this is what I got for application:

var app = angular.module('app', []);

app.factory('translationsService', function($http, translations, $q) {
    return {
        getTranslations: function(lang) {
            var deferred = $q.defer();
            $http({method: 'GET', url: '/translations/'+lang}).
                success(function (data) {
                    deferred.resolve({
                        data: data,
                        getWord: function(word) {
                            return data[word] ? data[word] : word;
                        }
                    });
                });
            return deferred.promise;
        }
    }
});

app.factory('wordService', function(translationsService, $q){
    return {
        lang: 'en-us',
        getWord: function(val){
            var translations = translationsService.getTranslations(this.lang);

            var deferred = $q.defer();
            translations.then(function(data) {
                deferred.resolve(data.getWord(val));
            });

            return deferred.promise;
        }
    }
});

app.filter('translate', function(wordService){
    return function(val){
        return wordService.getWord(val);
    }
});

So if I now do this in an html page:

{{ "User" | translate }}

Then I end up in an endless loop. Have I got the whole $q / promise thing wrong? I need some assistance here please.

However, if I use this by assigning it to a value in a controller it works fine.

In Controller I do:

app.controller('PageController',
    function PageController($scope, wordService) {
         $scope.someValue = wordService.getWord("USER");
    }
);

And then use it in html:

{{ someValue }}

And it works just fine.

/Marcus

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问