move i18n of UserActions to JS-side and make sentences translatable (take 3)

move i18n of UserActions to JS-side and make sentences translatable (take 3)

diff --git a/app/assets/javascripts/discourse/models/user.js b/app/assets/javascripts/discourse/models/user.js
index 1c083db60f..77b1dd3aef 100644
--- a/app/assets/javascripts/discourse/models/user.js
+++ b/app/assets/javascripts/discourse/models/user.js
@@ -370,6 +370,7 @@ Discourse.User = Discourse.Model.extend({
         var stat = Em.Object.create(s);
         stat.set('isPM', stat.get('action_type') === Discourse.UserAction.NEW_PRIVATE_MESSAGE ||
                          stat.get('action_type') === Discourse.UserAction.GOT_PRIVATE_MESSAGE);
+        stat.set('description', Em.String.i18n('user_action_groups.' + stat.get('action_type')));
         return stat;
       }));
 
@@ -429,7 +430,7 @@ Discourse.User.reopenClass({
           found = true;
           if (!g[k]) {
             g[k] = Em.Object.create({
-              description: Em.String.i18n("user_action_descriptions." + k),
+              description: Em.String.i18n("user_action_groups." + k),
               count: 0,
               action_type: parseInt(k, 10)
             });
diff --git a/app/assets/javascripts/discourse/models/user_action.js b/app/assets/javascripts/discourse/models/user_action.js
index 207bf362e6..bfbc159392 100644
--- a/app/assets/javascripts/discourse/models/user_action.js
+++ b/app/assets/javascripts/discourse/models/user_action.js
@@ -8,6 +8,77 @@
 **/
 Discourse.UserAction = Discourse.Model.extend({
 
+  descriptionHtml: (function() {
+    var action = this.get('action_type');
+    var ua = Discourse.UserAction;
+    var actions = [ua.LIKE, ua.WAS_LIKED, ua.STAR, ua.EDIT, ua.BOOKMARK, ua.GOT_PRIVATE_MESSAGE, ua.NEW_PRIVATE_MESSAGE];
+    var icon = "";
+    var sentence = "";
+    var sameUser = (this.get('username') === Discourse.get('currentUser.username'));
+
+    if (action === null || actions.indexOf(action) >= 0) {
+      if (this.get('isPM')) {
+        icon = '<i class="icon icon-envelope-alt" title="{{i18n user.stream.private_message}}"></i>';
+        if (sameUser) {
+          sentence = Em.String.i18n('user_action.sent_by_you', { userUrl: this.get('userUrl') });
+        } else {
+          sentence = Em.String.i18n('user_action.sent_by_user', { user: this.get('name'), userUrl: this.get('userUrl') });
+        }
+      } else {
+        if (sameUser) {
+          sentence = Em.String.i18n('user_action.posted_by_you', { userUrl: this.get('userUrl') });
+        } else {
+          sentence = Em.String.i18n('user_action.posted_by_user', { user: this.get('name'), userUrl: this.get('userUrl') });
+        }
+      }
+    } else if (action === ua.NEW_TOPIC) {
+      if (sameUser) {
+        sentence = Em.String.i18n('user_action.you_posted_topic', { userUrl: this.get('userUrl'), topicUrl: this.get('replyUrl') });
+      } else {
+        sentence = Em.String.i18n('user_action.user_posted_topic', { user: this.get('name'), userUrl: this.get('userUrl'), topicUrl: this.get('replyUrl') });
+      }
+    } else if (action === ua.POST || action === ua.RESPONSE) {
+      if (this.get('reply_to_post_number')) {
+        if (sameUser) {
+          sentence = Em.String.i18n('user_action.you_replied_to_post', { post_number: '#' + this.get('reply_to_post_number'),
+              userUrl: this.get('userUrl'), postUrl: this.get('postUrl') });
+        } else {
+          sentence = Em.String.i18n('user_action.user_replied_to_post', { user: this.get('name'),
+              post_number: '#' + this.get('reply_to_post_number'), userUrl: this.get('userUrl'), postUrl: this.get('postUrl') });
+        }
+      } else {
+        if (sameUser) {
+          sentence = Em.String.i18n('user_action.you_replied_to_topic', { userUrl: this.get('userUrl'),
+              topicUrl: this.get('replyUrl') });
+        } else {
+          sentence = Em.String.i18n('user_action.user_replied_to_topic', { user: this.get('name'),
+              userUrl: this.get('userUrl'), topicUrl: this.get('replyUrl') });
+        }
+      }
+    } else if (action === ua.MENTION) {
+      if (sameUser) {
+        sentence = Em.String.i18n('user_action.you_mentioned_user', { user: this.get('target_name'),
+            user1Url: this.get('userUrl'), user2Url: this.get('targetUserUrl') });
+      } else {
+        if (this.get('target_username') === Discourse.get('currentUser.username')) {
+          sentence = Em.String.i18n('user_action.user_mentioned_you', { user: this.get('name'),
+              user1Url: this.get('userUrl'), user2Url: this.get('targetUserUrl') });
+        } else {
+          sentence = Em.String.i18n('user_action.user_mentioned_user', { user: this.get('name'),
+              another_user: this.get('target_name'), user1Url: this.get('userUrl'), user2Url: this.get('targetUserUrl') });
+        }
+      }
+    } else {
+      Ember.debug("Invalid user action: " + action);
+    }
+
+    return new Handlebars.SafeString(icon + " " + sentence);
+  }).property(),
+
+  targetUserUrl: (function() {
+    return Discourse.Utilities.userUrl(this.get('target_username'));
+  }).property(),
+
   userUrl: (function() {
     return Discourse.Utilities.userUrl(this.get('username'));
   }).property(),
diff --git a/app/assets/javascripts/discourse/templates/user/stream.js.handlebars b/app/assets/javascripts/discourse/templates/user/stream.js.handlebars
index 4c53bfb483..af55af78c5 100644
--- a/app/assets/javascripts/discourse/templates/user/stream.js.handlebars
+++ b/app/assets/javascripts/discourse/templates/user/stream.js.handlebars
@@ -7,31 +7,7 @@
         <span class="title">
           <a href="{{unbound postUrl}}">{{unbound title}}</a>
         </span>
-        {{#unless description}}
-          <span class="type">
-          {{#if isPM}}
-            <i class="icon icon-envelope-alt" title="{{i18n user.stream.private_message}}"></i>
-            {{i18n user.stream.sent_by}}
-          {{else}}
-            {{i18n user.stream.posted_by}}
-          {{/if}}
-          </span>
-        {{/unless}}
-        <a class='name' href="{{unbound userUrl}}">{{personalizedName name usernamePath="username"}}</a>
-        {{#if description}}
-          <span class='type'>{{unbound description}}</span>
-          {{#if isPostAction}}
-            <a class="post-number" href="{{unbound replyUrl}}">
-            {{#if reply_to_post_number}}
-              #{{unbound reply_to_post_number}}
-            {{else}}
-              {{i18n user.stream.the_topic}}
-            {{/if}}
-            </a>
-          {{else}}
-            <span class="name">{{personalizedName view.parentView.parentView.user.name usernamePath="view.parentView.parentView.user.username"}}</span>
-          {{/if}}
-        {{/if}}
+        <span class="type">{{unbound descriptionHtml}}</span>
       </div>
       <p class='excerpt'>
       {{{unbound excerpt}}}
diff --git a/app/models/user_action.rb b/app/models/user_action.rb
index 17813b942b..e007962e9f 100644
--- a/app/models/user_action.rb
+++ b/app/models/user_action.rb
@@ -36,7 +36,7 @@ class UserAction < ActiveRecord::Base
   ].each_with_index.to_a.flatten]
 
   def self.stats(user_id, guardian)
-    results = UserAction.select("action_type, COUNT(*) count, '' AS description")
+    results = UserAction.select("action_type, COUNT(*) count")
       .joins(:target_topic)
       .where(user_id: user_id)
       .group('action_type')
@@ -57,9 +57,6 @@ class UserAction < ActiveRecord::Base
     results = results.to_a
 
     results.sort! { |a,b| ORDER[a.action_type] <=> ORDER[b.action_type] }
-    results.each do |row|
-      row.description = self.description(row.action_type, detailed: true)
-    end
 
     results
   end
@@ -83,6 +80,7 @@ class UserAction < ActiveRecord::Base
     builder = SqlBuilder.new("
 SELECT
   t.title, a.action_type, a.created_at, t.id topic_id,
+  a.user_id AS target_user_id, au.name AS target_name, au.username AS target_username,
   coalesce(p.post_number, 1) post_number,
   p.reply_to_post_number,
   pu.email ,pu.username, pu.name, pu.id user_id,
@@ -94,6 +92,7 @@ LEFT JOIN posts p on p.id = a.target_post_id

[... diff too long, it was truncated ...]

GitHub sha: d355e42d